From fee81ae90d35750e7285172b8a91c4b9b598eb6f Mon Sep 17 00:00:00 2001 From: Miroslav Shaltev <miroslav.shaltev@shaltev.de> Date: Wed, 16 Sep 2015 22:28:20 +0200 Subject: [PATCH] q# modified: tools/SENSITIVITY/problems/styrene/black-box/truth/thermolib.hpp --- ChangeLog | 3 + README | 229 +- configure.ac | 2 +- doc/user_guide.pdf | Bin 1176419 -> 1389306 bytes examples/advanced/categorical/batch/bb.cpp | 4 +- .../advanced/categorical/batch/runExample.log | 86 +- .../categorical/bi_obj/categorical.cpp | 11 +- .../categorical/bi_obj/runExample.log | 82 +- .../categorical/single_obj/categorical.cpp | 729 +- .../categorical/single_obj/runExample.log | 777 +- examples/advanced/multi_start/best_x.txt | 2 +- examples/advanced/multi_start/param.txt | 4 +- examples/advanced/multi_start/runExample.log | 29 +- .../problems/02/{parameters.txt => param.txt} | 0 examples/advanced/restart/restart.cpp | 57 +- examples/advanced/restart/runExample.log | 51 +- examples/advanced/user_search/runExample.log | 90 +- examples/advanced/user_search/user_search.cpp | 23 + examples/basic/batch/bi_obj/param.txt | 2 +- examples/basic/batch/bi_obj/runExample.log | 266 +- .../basic/batch/single_obj/runExample.log | 26 +- .../basic/batch/single_obj_parallel/bb.cpp | 31 + .../batch/single_obj_parallel/bb_parallel.cpp | 113 + .../single_obj_parallel/parallel_BBWrapper.pl | 117 + .../basic/batch/single_obj_parallel/param.txt | 20 + .../batch/single_obj_parallel/runExample.log | 43 + .../basic/batch/single_obj_parallel/x.txt | 4 + .../basic/batch/single_obj_parallel/x0.txt | 1 + examples/basic/library/bi_obj/runExample.log | 22 +- .../basic/library/single_obj/basic_lib.cpp | 9 +- .../basic/library/single_obj/runExample.log | 21 +- .../library/single_obj_parallel/basic_lib.cpp | 203 + .../library/single_obj_parallel/makefile | 50 + .../single_obj_parallel/runExample.log | 27 + examples/interfaces/AMPL/runExample.log | 92 +- .../CUTEr/{parameters.txt => param.txt} | 2 +- examples/interfaces/CUTEr/readme.txt | 2 +- .../interfaces/DLL/bi_obj/nomad_for_DLL.cpp | 424 +- .../DLL/bi_obj/{parameters.txt => param.txt} | 56 +- examples/interfaces/DLL/bi_obj/readme.txt | 108 +- .../DLL/single_obj/nomad_for_DLL.cpp | 424 +- .../single_obj/{parameters.txt => param.txt} | 54 +- examples/interfaces/DLL/single_obj/readme.txt | 104 +- examples/interfaces/GAMS/bb.gms | 642 +- examples/interfaces/GAMS/ed.hup | 24 +- examples/interfaces/GAMS/lb.txt | 36 +- .../GAMS/{parameters.txt => param.txt} | 32 +- examples/interfaces/GAMS/points/x0.txt | 38 +- examples/interfaces/GAMS/points/x1.txt | 38 +- examples/interfaces/GAMS/points/x2.txt | 38 +- examples/interfaces/GAMS/readme.txt | 26 +- examples/interfaces/GAMS/ub.txt | 36 +- examples/interfaces/GAMS/x0.txt | 36 +- .../interfaces/Matlab_MEX/GERAD_NOMAD_build.m | 79 + .../interfaces/Matlab_MEX/Source/nomadmex.cpp | 1635 ++ .../Matlab_MEX/example_block_eval/fun.m | 26 + .../Matlab_MEX/example_block_eval/run_nomad.m | 12 + .../Matlab_MEX/example_categorical/fun.m | 60 + .../example_categorical/neighbors.m | 14 + .../example_categorical/run_nomad.m | 7 + .../Matlab_MEX/example_surrogate/bbsur.m | 11 + .../Matlab_MEX/example_surrogate/run_nomad.m | 5 + examples/interfaces/Matlab_MEX/nomad.m | 38 + examples/interfaces/Matlab_MEX/nomadset.m | 343 + .../interfaces/Matlab_MEX/test_nomad_gerad.m | 152 + install/install.sh | 64 +- nomad.spec | 2 +- readme.txt | 229 +- src/Barrier.cpp | 803 +- src/Barrier.hpp | 4 +- src/Cache.cpp | 1031 +- src/Cache.hpp | 4 +- src/Cache_File_Point.cpp | 123 +- src/Cache_File_Point.hpp | 4 +- src/Cache_Point.cpp | 4 +- src/Cache_Point.hpp | 4 +- src/Cache_Search.cpp | 4 +- src/Cache_Search.hpp | 4 +- src/Clock.cpp | 11 +- src/Clock.hpp | 4 +- src/Direction.cpp | 4 +- src/Direction.hpp | 4 +- src/Directions.cpp | 1634 +- src/Directions.hpp | 557 +- src/Display.cpp | 1211 +- src/Display.hpp | 4 +- src/Double.cpp | 845 +- src/Double.hpp | 4 +- src/Eval_Point.cpp | 576 +- src/Eval_Point.hpp | 1067 +- src/Evaluator.cpp | 1173 +- src/Evaluator.hpp | 401 +- src/Evaluator_Control.cpp | 1975 +- src/Evaluator_Control.hpp | 1372 +- src/Exception.cpp | 4 +- src/Exception.hpp | 4 +- src/Extended_Poll.cpp | 2142 ++- src/Extended_Poll.hpp | 4 +- src/Filter_Point.hpp | 4 +- src/LH_Search.cpp | 615 +- src/LH_Search.hpp | 4 +- src/L_Curve.cpp | 4 +- src/L_Curve.hpp | 4 +- src/Mads.cpp | 4334 +++-- src/Mads.hpp | 1086 +- src/Makefile.am | 14 +- src/Mesh.cpp | 382 - src/Mesh.hpp | 361 - src/Model_Sorted_Point.cpp | 4 +- src/Model_Sorted_Point.hpp | 4 +- src/Model_Stats.cpp | 4 +- src/Model_Stats.hpp | 4 +- src/Multi_Obj_Evaluator.cpp | 4 +- src/Multi_Obj_Evaluator.hpp | 4 +- src/Multi_Obj_Quad_Model_Evaluator.hpp | 10 +- src/OrthogonalMesh.cpp | 205 + src/OrthogonalMesh.hpp | 384 + src/Parameter_Entries.cpp | 4 +- src/Parameter_Entries.hpp | 4 +- src/Parameter_Entry.cpp | 8 +- src/Parameter_Entry.hpp | 4 +- src/Parameters.cpp | 15927 ++++++++-------- src/Parameters.hpp | 5004 ++--- src/Pareto_Front.cpp | 4 +- src/Pareto_Front.hpp | 4 +- src/Pareto_Point.cpp | 4 +- src/Pareto_Point.hpp | 4 +- src/Phase_One_Evaluator.cpp | 66 +- src/Phase_One_Evaluator.hpp | 196 +- src/Phase_One_Search.cpp | 568 +- src/Phase_One_Search.hpp | 4 +- src/Point.cpp | 43 +- src/Point.hpp | 7 +- src/Priority_Eval_Point.cpp | 145 +- src/Priority_Eval_Point.hpp | 11 +- src/Quad_Model.cpp | 3306 ++-- src/Quad_Model.hpp | 6 +- src/Quad_Model_Evaluator.cpp | 25 +- src/Quad_Model_Evaluator.hpp | 146 +- src/Quad_Model_Search.cpp | 1700 +- src/Quad_Model_Search.hpp | 14 +- src/RNG.cpp | 87 +- src/RNG.hpp | 79 +- src/Random_Pickup.cpp | 6 +- src/Random_Pickup.hpp | 4 +- src/SMesh.cpp | 382 + src/SMesh.hpp | 309 + src/Search.hpp | 4 +- src/Set_Element.hpp | 4 +- src/Signature.cpp | 1686 +- src/Signature.hpp | 964 +- src/Signature_Element.hpp | 4 +- src/Single_Obj_Quad_Model_Evaluator.hpp | 10 +- src/Slave.cpp | 829 +- src/Slave.hpp | 10 +- src/Speculative_Search.cpp | 298 +- src/Speculative_Search.hpp | 4 +- src/Stats.cpp | 10 +- src/Stats.hpp | 27 +- src/TGP_Model.cpp | 4 +- src/TGP_Model.hpp | 4 +- src/TGP_Model_Evaluator.cpp | 4 +- src/TGP_Model_Evaluator.hpp | 4 +- src/TGP_Model_Search.cpp | 58 +- src/TGP_Model_Search.hpp | 8 +- src/TGP_Output_Model.cpp | 8 +- src/TGP_Output_Model.hpp | 6 +- src/Uncopyable.hpp | 4 +- src/VNS_Search.cpp | 1156 +- src/VNS_Search.hpp | 23 +- src/Variable_Group.cpp | 301 +- src/Variable_Group.hpp | 342 +- src/XMesh.cpp | 511 + src/XMesh.hpp | 307 + src/defines.hpp | 660 +- src/nomad.cpp | 480 +- src/nomad.hpp | 4 +- src/utils.cpp | 27 +- src/utils.hpp | 39 +- tools/COOP-MADS/Cache_Server.cpp | 1407 +- tools/COOP-MADS/main.cpp | 6 +- tools/COOP-MADS/problems/G2_10/runExample.log | 40 +- .../problems/RHEOLOGY/runExample.log | 234 +- tools/COOP-MADS/problems/RHEOLOGY/x0.txt | 6 +- tools/PSD-MADS/Cache_Server.cpp | 26 +- tools/PSD-MADS/Master_Slaves.cpp | 1424 +- tools/PSD-MADS/Master_Slaves.hpp | 9 +- tools/PSD-MADS/main.cpp | 5 + tools/PSD-MADS/problems/G2_10/runExample.log | 133 +- .../detailed_analysis/detailed_analysis.cpp | 1 - .../problems/cube/detailed/param.txt | 2 +- .../black-box/surrogate/RungeKutta.cpp | 160 +- .../black-box/surrogate/RungeKutta.hpp | 74 +- .../black-box/surrogate/bissection.cpp | 54 +- .../black-box/surrogate/bissection.hpp | 62 +- .../styrene/black-box/surrogate/burner.cpp | 574 +- .../styrene/black-box/surrogate/burner.hpp | 118 +- .../styrene/black-box/surrogate/cashflow.cpp | 228 +- .../styrene/black-box/surrogate/cashflow.hpp | 66 +- .../styrene/black-box/surrogate/chemical.cpp | 1058 +- .../styrene/black-box/surrogate/chemical.hpp | 96 +- .../styrene/black-box/surrogate/column.cpp | 580 +- .../styrene/black-box/surrogate/column.hpp | 122 +- .../styrene/black-box/surrogate/combrx.cpp | 132 +- .../styrene/black-box/surrogate/combrx.hpp | 58 +- .../styrene/black-box/surrogate/flash.cpp | 440 +- .../styrene/black-box/surrogate/flash.hpp | 110 +- .../styrene/black-box/surrogate/heatx.cpp | 292 +- .../styrene/black-box/surrogate/heatx.hpp | 98 +- .../styrene/black-box/surrogate/mix.cpp | 160 +- .../styrene/black-box/surrogate/mix.hpp | 88 +- .../styrene/black-box/surrogate/pfr.cpp | 348 +- .../styrene/black-box/surrogate/pfr.hpp | 72 +- .../black-box/surrogate/profitability.cpp | 276 +- .../black-box/surrogate/profitability.hpp | 60 +- .../styrene/black-box/surrogate/pump.cpp | 188 +- .../styrene/black-box/surrogate/pump.hpp | 92 +- .../styrene/black-box/surrogate/reaction.cpp | 408 +- .../styrene/black-box/surrogate/reaction.hpp | 64 +- .../styrene/black-box/surrogate/reactor.cpp | 200 +- .../styrene/black-box/surrogate/reactor.hpp | 96 +- .../styrene/black-box/surrogate/secant.cpp | 94 +- .../styrene/black-box/surrogate/secant.hpp | 62 +- .../styrene/black-box/surrogate/servor.cpp | 1076 +- .../styrene/black-box/surrogate/servor.hpp | 202 +- .../styrene/black-box/surrogate/split.cpp | 106 +- .../styrene/black-box/surrogate/split.hpp | 86 +- .../styrene/black-box/surrogate/stream.cpp | 530 +- .../styrene/black-box/surrogate/stream.hpp | 172 +- .../styrene/black-box/surrogate/thermolib.cpp | 350 +- .../styrene/black-box/surrogate/thermolib.hpp | 100 +- .../styrene/black-box/truth/RungeKutta.cpp | 160 +- .../styrene/black-box/truth/RungeKutta.hpp | 74 +- .../problems/styrene/black-box/truth/bb.cpp | 722 +- .../styrene/black-box/truth/bissection.cpp | 54 +- .../styrene/black-box/truth/bissection.hpp | 62 +- .../styrene/black-box/truth/burner.cpp | 574 +- .../styrene/black-box/truth/burner.hpp | 118 +- .../styrene/black-box/truth/cashflow.cpp | 228 +- .../styrene/black-box/truth/cashflow.hpp | 66 +- .../styrene/black-box/truth/chemical.cpp | 1058 +- .../styrene/black-box/truth/chemical.hpp | 96 +- .../styrene/black-box/truth/column.cpp | 580 +- .../styrene/black-box/truth/column.hpp | 122 +- .../styrene/black-box/truth/combrx.cpp | 132 +- .../styrene/black-box/truth/combrx.hpp | 58 +- .../styrene/black-box/truth/defines.hpp | 178 +- .../styrene/black-box/truth/flash.cpp | 440 +- .../styrene/black-box/truth/flash.hpp | 110 +- .../styrene/black-box/truth/heatx.cpp | 292 +- .../styrene/black-box/truth/heatx.hpp | 98 +- .../problems/styrene/black-box/truth/mix.cpp | 160 +- .../problems/styrene/black-box/truth/mix.hpp | 88 +- .../problems/styrene/black-box/truth/pfr.cpp | 344 +- .../problems/styrene/black-box/truth/pfr.hpp | 72 +- .../styrene/black-box/truth/profitability.cpp | 276 +- .../styrene/black-box/truth/profitability.hpp | 60 +- .../problems/styrene/black-box/truth/pump.cpp | 188 +- .../problems/styrene/black-box/truth/pump.hpp | 92 +- .../styrene/black-box/truth/reaction.cpp | 408 +- .../styrene/black-box/truth/reaction.hpp | 64 +- .../styrene/black-box/truth/reactor.cpp | 200 +- .../styrene/black-box/truth/reactor.hpp | 96 +- .../styrene/black-box/truth/secant.cpp | 94 +- .../styrene/black-box/truth/secant.hpp | 62 +- .../styrene/black-box/truth/servor.cpp | 1076 +- .../styrene/black-box/truth/servor.hpp | 202 +- .../styrene/black-box/truth/split.cpp | 106 +- .../styrene/black-box/truth/split.hpp | 86 +- .../styrene/black-box/truth/stream.cpp | 530 +- .../styrene/black-box/truth/stream.hpp | 172 +- .../styrene/black-box/truth/thermolib.cpp | 348 +- .../styrene/black-box/truth/thermolib.hpp | 100 +- utils/MergeCacheFiles/Readme.txt | 21 + utils/MergeCacheFiles/build.m | 72 + utils/MergeCacheFiles/cache1.bin | Bin 0 -> 8904 bytes utils/MergeCacheFiles/cache2.bin | Bin 0 -> 8815 bytes utils/MergeCacheFiles/cache3.bin | Bin 0 -> 17715 bytes utils/MergeCacheFiles/makefile | 50 + utils/MergeCacheFiles/merge.cpp | 56 + utils/MergeCacheFiles/mergeM.cpp | 90 + utils/Run_TestSuite/readme.txt | 3 + utils/Run_TestSuite/runNomadAll_parallel.pl | 309 + 283 files changed, 48394 insertions(+), 41004 deletions(-) rename examples/advanced/plot/problems/02/{parameters.txt => param.txt} (100%) create mode 100644 examples/basic/batch/single_obj_parallel/bb.cpp create mode 100644 examples/basic/batch/single_obj_parallel/bb_parallel.cpp create mode 100755 examples/basic/batch/single_obj_parallel/parallel_BBWrapper.pl create mode 100644 examples/basic/batch/single_obj_parallel/param.txt create mode 100644 examples/basic/batch/single_obj_parallel/runExample.log create mode 100644 examples/basic/batch/single_obj_parallel/x.txt create mode 100644 examples/basic/batch/single_obj_parallel/x0.txt create mode 100644 examples/basic/library/single_obj_parallel/basic_lib.cpp create mode 100644 examples/basic/library/single_obj_parallel/makefile create mode 100644 examples/basic/library/single_obj_parallel/runExample.log rename examples/interfaces/CUTEr/{parameters.txt => param.txt} (90%) rename examples/interfaces/DLL/bi_obj/{parameters.txt => param.txt} (91%) rename examples/interfaces/DLL/single_obj/{parameters.txt => param.txt} (92%) rename examples/interfaces/GAMS/{parameters.txt => param.txt} (94%) create mode 100644 examples/interfaces/Matlab_MEX/GERAD_NOMAD_build.m create mode 100755 examples/interfaces/Matlab_MEX/Source/nomadmex.cpp create mode 100644 examples/interfaces/Matlab_MEX/example_block_eval/fun.m create mode 100644 examples/interfaces/Matlab_MEX/example_block_eval/run_nomad.m create mode 100644 examples/interfaces/Matlab_MEX/example_categorical/fun.m create mode 100644 examples/interfaces/Matlab_MEX/example_categorical/neighbors.m create mode 100644 examples/interfaces/Matlab_MEX/example_categorical/run_nomad.m create mode 100644 examples/interfaces/Matlab_MEX/example_surrogate/bbsur.m create mode 100644 examples/interfaces/Matlab_MEX/example_surrogate/run_nomad.m create mode 100644 examples/interfaces/Matlab_MEX/nomad.m create mode 100755 examples/interfaces/Matlab_MEX/nomadset.m create mode 100755 examples/interfaces/Matlab_MEX/test_nomad_gerad.m delete mode 100644 src/Mesh.cpp delete mode 100644 src/Mesh.hpp create mode 100644 src/OrthogonalMesh.cpp create mode 100644 src/OrthogonalMesh.hpp create mode 100644 src/SMesh.cpp create mode 100644 src/SMesh.hpp create mode 100644 src/XMesh.cpp create mode 100644 src/XMesh.hpp create mode 100644 utils/MergeCacheFiles/Readme.txt create mode 100644 utils/MergeCacheFiles/build.m create mode 100644 utils/MergeCacheFiles/cache1.bin create mode 100644 utils/MergeCacheFiles/cache2.bin create mode 100644 utils/MergeCacheFiles/cache3.bin create mode 100644 utils/MergeCacheFiles/makefile create mode 100644 utils/MergeCacheFiles/merge.cpp create mode 100644 utils/MergeCacheFiles/mergeM.cpp create mode 100644 utils/Run_TestSuite/readme.txt create mode 100755 utils/Run_TestSuite/runNomadAll_parallel.pl diff --git a/ChangeLog b/ChangeLog index 6af6b26..b2f5030 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2015-03: NOMAD 3.7 + -Anisotropic scaling + -Block evaluations 2013-03: NOMAD 3.6 -ortho n+1 2011-01: NOMAD 3.5 diff --git a/README b/README index 96df2cf..4966d0c 100644 --- a/README +++ b/README @@ -1,115 +1,114 @@ -####################################################################################### -# # -# README # -# # -####################################################################################### -# # -# NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search # -# V 3.6.1 # -# 2013/05 # -# # -# Copyright (C) 2001-2013 # -# # -# Mark Abramson - the Boeing Company, Seattle # -# Charles Audet - Ecole Polytechnique, Montreal # -# Gilles Couture - Ecole Polytechnique, Montreal # -# John Dennis - Rice University, Houston # -# Sebastien Le Digabel - Ecole Polytechnique, Montreal # -# Christophe Tribes - Ecole Polytechnique, Montreal # -# # -#-------------------------------------------------------------------------------------# -# # -# Contact information: # -# Ecole Polytechnique de Montreal - GERAD # -# C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada # -# e-mail: nomad@gerad.ca # -# phone : 1-514-340-6053 #6928 # -# fax : 1-514-340-5665 # -# # -# This program is free software: you can redistribute it and/or modify it under the # -# terms of the GNU Lesser General Public License as published by the Free Software # -# Foundation, either version 3 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 Lesser General Public License for more details. # -# # -# -# You should have received a copy of the GNU Lesser General Public License along # -# with this program. If not, see <http://www.gnu.org/licenses/>. # -# # -# You can find information on the NOMAD software at www.gerad.ca/nomad # -####################################################################################### - - - AUTHORS : - -* Mark A. Abramson (Mark.A.Abramson@boeing.com), The Boeing Company. - -* Charles Audet (www.gerad.ca/Charles.Audet), GERAD and Departement de -mathematiques et de genie industriel, ecole Polytechnique de Montreal. - -* J.E. Dennis Jr. (www.caam.rice.edu/~dennis), Computational and Applied -Mathematics Department, Rice University. - -* Sebastien Le Digabel (www.gerad.ca/Sebastien.Le.Digabel), GERAD and Departement -de mathematiques et de genie industriel, ecole Polytechnique de Montreal. - -* Christophe Tribes, GERAD, Departement -de mathematiques et de genie industriel, Department of mechanical engineering, ecole Polytechnique de Montreal. - - DESCRIPTION : - -NOMAD is a C++ implementation of the Mesh Adaptive Direct Search (MADS) algorithm, -designed for constrained optimization of black-box functions. - -The project started in 2001, and was funded in part by AFOSR, CRIAQ, FQRNT, LANL, -NSERC, the Boeing Company, and ExxonMobil Upstream Research Company. - - - WEB PAGE : - -http://www.gerad.ca/nomad/ - - - FURTHER INSTRUCTIONS : - -Please visit the web page for futher instruction on the following: - - * Downloading, configuring, compiling, and installing NOMAD - * Using NOMAD and setting the parameters - * Reports on NOMAD - * How to report bugs and make enhancement requests - * And more... - - - BATCH OR LIBRARY MODE : - -NOMAD is designed to be used in two different modes : batch and library. -The batch mode is intended for a basic ans simple usage of the MADS method, -while the library mode allows more flexibility. -For example, in batch mode, users must define their separate black-box program, -that will be called with system calls by NOMAD. -In library mode, users can define their black-box function as C++ code -that will be directly called by NOMAD, without system calls and temporary files. - - - TYPES OF USE : - -There are two ways of using NOMAD, one can directly use an executable or compile -the source code. - -NOMAD batch mode executable is located in directory $NOMAD_HOME/bin or %NOMAD_HOME%\bin. -In order to avoid compiling the code, you can simply use this executable. - - - HOW TO EXECUTE NOMAD : - -For informations about the execution of NOMAD, please read the user guide : - - $NOMAD_HOME/doc/user_guide.pdf or %NOMAD_HOME%\doc\user_guide.pdf - -or - - http://www.gerad.ca/NOMAD/Downloads/user_guide.pdf +####################################################################################### +# # +# README # +# # +####################################################################################### +# # +# NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search # +# V 3.7.2 # +# # +# Copyright (C) 2001-2015 # +# # +# Mark Abramson - the Boeing Company, Seattle # +# Charles Audet - Ecole Polytechnique, Montreal # +# Gilles Couture - Ecole Polytechnique, Montreal # +# John Dennis - Rice University, Houston # +# Sebastien Le Digabel - Ecole Polytechnique, Montreal # +# Christophe Tribes - Ecole Polytechnique, Montreal # +# # +#-------------------------------------------------------------------------------------# +# # +# Contact information: # +# Ecole Polytechnique de Montreal - GERAD # +# C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada # +# e-mail: nomad@gerad.ca # +# phone : 1-514-340-6053 #6928 # +# fax : 1-514-340-5665 # +# # +# This program is free software: you can redistribute it and/or modify it under the # +# terms of the GNU Lesser General Public License as published by the Free Software # +# Foundation, either version 3 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 Lesser General Public License for more details. # +# # +# +# You should have received a copy of the GNU Lesser General Public License along # +# with this program. If not, see <http://www.gnu.org/licenses/>. # +# # +# You can find information on the NOMAD software at www.gerad.ca/nomad # +####################################################################################### + + + AUTHORS : + +* Mark A. Abramson (Mark.A.Abramson@boeing.com), The Boeing Company. + +* Charles Audet (www.gerad.ca/Charles.Audet), GERAD and Departement de +mathematiques et de genie industriel, ecole Polytechnique de Montreal. + +* J.E. Dennis Jr. (www.caam.rice.edu/~dennis), Computational and Applied +Mathematics Department, Rice University. + +* Sebastien Le Digabel (www.gerad.ca/Sebastien.Le.Digabel), GERAD and Departement +de mathematiques et de genie industriel, ecole Polytechnique de Montreal. + +* Christophe Tribes, GERAD, Departement +de mathematiques et de genie industriel, Department of mechanical engineering, ecole Polytechnique de Montreal. + + DESCRIPTION : + +NOMAD is a C++ implementation of the Mesh Adaptive Direct Search (MADS) algorithm, +designed for constrained optimization of black-box functions. + +The project started in 2001, and was funded in part by AFOSR, CRIAQ, FQRNT, LANL, +NSERC, the Boeing Company, and ExxonMobil Upstream Research Company. + + + WEB PAGE : + +http://www.gerad.ca/nomad/ + + + FURTHER INSTRUCTIONS : + +Please visit the web page for futher instruction on the following: + + * Downloading, configuring, compiling, and installing NOMAD + * Using NOMAD and setting the parameters + * Reports on NOMAD + * How to report bugs and make enhancement requests + * And more... + + + BATCH OR LIBRARY MODE : + +NOMAD is designed to be used in two different modes : batch and library. +The batch mode is intended for a basic ans simple usage of the MADS method, +while the library mode allows more flexibility. +For example, in batch mode, users must define their separate black-box program, +that will be called with system calls by NOMAD. +In library mode, users can define their black-box function as C++ code +that will be directly called by NOMAD, without system calls and temporary files. + + + TYPES OF USE : + +There are two ways of using NOMAD, one can directly use an executable or compile +the source code. + +NOMAD batch mode executable is located in directory $NOMAD_HOME/bin or %NOMAD_HOME%\bin. +In order to avoid compiling the code, you can simply use this executable. + + + HOW TO EXECUTE NOMAD : + +For informations about the execution of NOMAD, please read the user guide : + + $NOMAD_HOME/doc/user_guide.pdf or %NOMAD_HOME%\doc\user_guide.pdf + +or + + http://www.gerad.ca/NOMAD/Downloads/user_guide.pdf diff --git a/configure.ac b/configure.ac index 840291f..9ab8eb4 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(nomad, 3.6.1, miroslav.shaltev@shaltev.de) +AC_INIT(nomad, 3.7.2, miroslav.shaltev@shaltev.de) AC_PREREQ([2.63]) AC_CONFIG_HEADERS([config.h]) diff --git a/doc/user_guide.pdf b/doc/user_guide.pdf index d36529e595ab18e41f6b5c7e09235f808e099b69..9d7d24922c4389db5d4da282552f411c8a276da8 100644 GIT binary patch delta 846237 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	*E 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%0Duh+_?wn~!iFIL~f0Gpd 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⪚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%0DsBaVeAVzn!mtz1zIqdJ^wXi&dNC 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�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	+w7n?c0 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⁡AItftx?6tu$YU5_vu2xr-ZMEz>E@p~e@~xd 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%0A-g59xS+;o%H(0Y<*<-H|i8=QXqWR6V&U%a^#{ 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 delta 623973 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�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𝔤0MuS#4vKe)%)E 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�z4YVKx4z?= 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	_bg1?8B7v8Eda>`*d~n$L{Uh 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 diff --git a/examples/advanced/categorical/batch/bb.cpp b/examples/advanced/categorical/batch/bb.cpp index 96e7377..3e86359 100644 --- a/examples/advanced/categorical/batch/bb.cpp +++ b/examples/advanced/categorical/batch/bb.cpp @@ -79,8 +79,8 @@ int main ( int argc , char ** argv ) { in.close(); } } - - cout << g1 << " " << g2 << " " << f << endl; + cout.precision(18); + cout << g1 << " " << g2 << " " << f << endl; return 0; } diff --git a/examples/advanced/categorical/batch/runExample.log b/examples/advanced/categorical/batch/runExample.log index 1b60451..543c3aa 100644 --- a/examples/advanced/categorical/batch/runExample.log +++ b/examples/advanced/categorical/batch/runExample.log @@ -1,10 +1,13 @@ Warning: { Model use is disabled for problem with categorical variables. } +Warning: { + Anisotropic mesh are not supported with categorical and binary variables. +} -NOMAD - version 3.6.1 - www.gerad.ca/nomad +NOMAD - version 3.7.1 - www.gerad.ca/nomad -Copyright (C) 2001-2013 { +Copyright (C) 2001-2015 { Mark A. Abramson - The Boeing Company Charles Audet - Ecole Polytechnique de Montreal Gilles Couture - Ecole Polytechnique de Montreal @@ -26,31 +29,54 @@ MADS run { BBE ( SOL ) OBJ - 1 ( 0 100.0000000000 1 100.0000000000 ) 159.6460000000 - 3 ( 0 100.0000000000 1 1100.0000000000 ) 150.4540000000 - 4 ( 0 100.0000000000 1 4100.0000000000 ) 111.1390000000 - 6 ( 0 100.0000000000 1 6100.0000000000 ) 85.9544000000 - 14 ( 0 100.0000000000 1 8100.0000000000 ) 64.1532000000 - 24 ( 0 100.0000000000 1 9100.0000000000 ) 55.8612000000 - 32 ( 0 1100.0000000000 1 8100.0000000000 ) 52.5820000000 - 47 ( 0 1600.0000000000 1 8100.0000000000 ) 47.6450000000 - 55 ( 0 1850.0000000000 1 8100.0000000000 ) 45.3357000000 - 72 ( 0 1853.4179687500 1 8111.7187500000 ) 45.2005000000 - 75 ( 0 1833.8867187500 1 8132.2265625000 ) 45.1958000000 - 76 ( 0 1775.2929687500 1 8193.7500000000 ) 45.1911000000 - 80 ( 0 1900.2929687500 1 8068.7500000000 ) 45.1620000000 - 89 ( 0 1923.7304687500 1 8058.9843750000 ) 45.0398000000 - 98 ( 0 1899.3164062500 1 8083.3984375000 ) 45.0394000000 - 105 ( 0 1892.4804687500 1 8106.8359375000 ) 44.8919000000 - 114 ( 0 1923.7304687500 1 8075.5859375000 ) 44.8905000000 - 137 ( 0 1922.9360580444 1 8076.6168594360 ) 44.8884000000 - 146 ( 0 1922.1416473389 1 8077.6477813721 ) 44.8863000000 - 162 ( 0 1922.1003413200 1 8077.7624607086 ) 44.8856000000 - 169 ( 0 1922.0590353012 1 8077.8771400452 ) 44.8850000000 - 171 ( 0 1921.9208717346 1 8078.0774116516 ) 44.8844000000 - 294 ( 0 1921.9208717346 1 8078.0774116516 ) 44.8844000000 - -} end of run (mesh index limits (+/- 50)) - -blackbox evaluations : 294 -best feasible solution : ( 0 1921.920872 1 8078.077412 ) h=0 f=44.8844 + 1 ( 0 100.0000000000 1 100.0000000000 ) 159.6461296475 + 5+ 2 ( 0 1100.0000000000 2 100.0000000000 ) 152.8902369239 (ExtendedPoll) + 5+ 3 ( 0 4100.0000000000 2 100.0000000000 ) 134.5175377184 (ExtendedPoll) + 5+ 6 ( 0 8100.0000000000 2 1100.0000000000 ) 93.9098509400 (ExtendedPoll) + 5+ 13 ( 0 3600.0000000000 2 4600.0000000000 ) 72.2375927442 (ExtendedPoll) + 5+ 23 ( 0 4600.0000000000 2 4600.0000000000 ) 63.9850651149 (ExtendedPoll) + 5+ 29 ( 0 4100.0000000000 2 5100.0000000000 ) 62.0438640124 (ExtendedPoll) + 41+ 5 ( 0 3975.0000000000 1 5725.0000000000 ) 55.6086573370 (ExtendedPoll) + 66+ 6 ( 2 3881.2500000000 1 5975.0000000000 ) 58.7730353554 (ExtendedPoll) + 85+ 7 ( 0 3943.7500000000 2 5975.0000000000 ) 54.5634971325 (ExtendedPoll) + 110 ( 0 3943.7500000000 1 5975.0000000000 ) 52.5611211856 + 114+ 12 ( 0 3914.4531250000 2 6029.6875000000 ) 54.3636860906 (ExtendedPoll) + 114+ 14 ( 0 3836.3281250000 2 6131.2500000000 ) 54.2565794588 (ExtendedPoll) + 114+ 26 ( 0 3863.6718750000 2 6115.6250000000 ) 54.1218203970 (ExtendedPoll) + 114+ 28 ( 0 3908.5937500000 2 6072.6562500000 ) 54.0518889750 (ExtendedPoll) + 114+ 29 ( 0 4043.3593750000 2 5943.7500000000 ) 53.9097569796 (ExtendedPoll) + 114+ 42 ( 0 4017.9687500000 2 5979.8828125000 ) 53.8237647156 (ExtendedPoll) + 166+ 12 ( 0 3945.7031250000 2 6037.5000000000 ) 53.9997469058 (ExtendedPoll) + 166+ 23 ( 0 3945.2148437500 2 6053.1250000000 ) 53.8701209592 (ExtendedPoll) + 199+ 8 ( 0 4100.0000000000 2 5881.2500000000 ) 53.9564900102 (ExtendedPoll) + 199+ 24 ( 0 4107.8125000000 2 5881.4331054688 ) 53.8832486375 (ExtendedPoll) + 199+ 26 ( 0 4121.8505859375 2 5874.7192382812 ) 53.8169487483 (ExtendedPoll) + 238+ 10 ( 0 4006.2500000000 2 5980.8593750000 ) 53.9245869941 (ExtendedPoll) + 238+ 18 ( 0 4030.6640625000 2 5961.3281250000 ) 53.8703341236 (ExtendedPoll) + 238+ 30 ( 0 4028.8024902344 2 5968.9270019531 ) 53.8199810273 (ExtendedPoll) + 238+ 38 ( 0 4026.6967773438 2 5972.2152709961 ) 53.8103680832 (ExtendedPoll) + 286+ 8 ( 0 4006.2500000000 2 5973.0468750000 ) 53.9937648079 (ExtendedPoll) + 286+ 19 ( 0 4006.3720703125 2 5988.6718750000 ) 53.8544733742 (ExtendedPoll) + 286+ 24 ( 0 4017.6025390625 2 5977.8076171875 ) 53.8455562804 (ExtendedPoll) + 286+ 25 ( 0 4051.2939453125 2 5945.2148437500 ) 53.8230307642 (ExtendedPoll) + 286+ 40 ( 0 4049.3560791016 2 5948.6022949219 ) 53.8105786370 (ExtendedPoll) + 286+ 48 ( 0 4049.1615295410 2 5950.5458831787 ) 53.7949509311 (ExtendedPoll) + 344+ 11 ( 0 4092.1875000000 2 5889.0625000000 ) 53.9562156297 (ExtendedPoll) + 344+ 26 ( 0 4082.9101562500 2 5901.6357421875 ) 53.9261842233 (ExtendedPoll) + 344+ 27 ( 0 4055.0781250000 2 5939.3554687500 ) 53.8406875009 (ExtendedPoll) + 344+ 41 ( 0 4054.7653198242 2 5943.2464599609 ) 53.8085676438 (ExtendedPoll) + 344+ 52 ( 0 4055.7056427002 2 5943.5101509094 ) 53.7974893949 (ExtendedPoll) + 344+ 55 ( 0 4057.1723937988 2 5942.2207832336 ) 53.7955084222 (ExtendedPoll) + 344+ 56 ( 0 4061.5726470947 2 5938.3526802063 ) 53.7896289020 (ExtendedPoll) + 416+ 8 ( 0 4092.1875000000 2 5873.4375000000 ) 54.1002366323 (ExtendedPoll) + 416+24 ( 0 4104.6386718750 2 5891.7480468750 ) 53.8173417481 (ExtendedPoll) + 416+33 ( 0 4111.5356445312 2 5888.0859375000 ) 53.7878645675 (ExtendedPoll) + 416+47 ( 0 4112.3014450073 2 5887.4798774719 ) 53.7864363345 (ExtendedPoll) + 475 ( 0 4004.2968750000 1 5986.7187500000 ) 51.9855654455 + 481+19 ( 0 3994.9005859375 2 5999.2932421875 ) 53.8684879252 (ExtendedPoll) + 500 ( 0 4004.2968750000 1 5986.7187500000 ) 51.9855654455 + +} end of run (max number of blackbox evaluations) + +blackbox evaluations : 500 +best feasible solution : ( 0 4004.296875 1 5986.71875 ) h=0 f=51.98556545 diff --git a/examples/advanced/categorical/bi_obj/categorical.cpp b/examples/advanced/categorical/bi_obj/categorical.cpp index a0e0421..f37c449 100644 --- a/examples/advanced/categorical/bi_obj/categorical.cpp +++ b/examples/advanced/categorical/bi_obj/categorical.cpp @@ -46,10 +46,6 @@ class My_Evaluator : public Multi_Obj_Evaluator { public: My_Evaluator ( const Parameters & p ) : Multi_Obj_Evaluator ( p ) { - - - - } ~My_Evaluator ( void ) {} @@ -263,12 +259,10 @@ My_Extended_Poll::My_Extended_Poll ( Parameters & p ) bbit_1[0] = bbit_1[1] = CATEGORICAL; bbit_1[2] = CONTINUOUS; - const Point & d0_1 = p.get_initial_mesh_size(); + const Point & d0_1 = p.get_initial_poll_size(); const Point & lb_1 = p.get_lb(); const Point & ub_1 = p.get_ub(); - int halton_seed = p.get_halton_seed(); - _s1 = new Signature ( 3 , bbit_1 , d0_1 , @@ -276,7 +270,6 @@ My_Extended_Poll::My_Extended_Poll ( Parameters & p ) ub_1 , p.get_direction_types () , p.get_sec_poll_dir_types() , - halton_seed++ , _p.out() ); // signature for 2 assets: @@ -302,7 +295,6 @@ My_Extended_Poll::My_Extended_Poll ( Parameters & p ) ub_2 , p.get_direction_types () , p.get_sec_poll_dir_types() , - halton_seed++ , _p.out() ); } @@ -329,7 +321,6 @@ My_Extended_Poll::My_Extended_Poll ( Parameters & p ) ub_3 , p.get_direction_types () , p.get_sec_poll_dir_types() , - halton_seed , _p.out() ); } } diff --git a/examples/advanced/categorical/bi_obj/runExample.log b/examples/advanced/categorical/bi_obj/runExample.log index 1b4a4d2..c73859f 100644 --- a/examples/advanced/categorical/bi_obj/runExample.log +++ b/examples/advanced/categorical/bi_obj/runExample.log @@ -1,59 +1,45 @@ Warning: { Model use is disabled for problem with categorical variables. } +Warning: { + Default anisotropic mesh is disabled with categorical and binary variables. +} +Warning: { + Model use is disabled in parallel mode (MPI). +} +Warning: { + Asynchronous mode is disabled in parallel mode (MPI) when dynamic directions (ortho n+1) are used. +} multi-MADS run { - MADS run 1/30 ...... OK [bb eval= 60] [overall bb eval= 60] [# dominant pts= 5] [# new pts= 5] [f1=52.02241823 f2=52.95541823] - MADS run 2/30 ...... OK [bb eval= 66] [overall bb eval= 126] [# dominant pts= 5] [# new pts= 0] [f1=52.02241823 f2=51.05441823] - MADS run 3/30 ...... OK [bb eval= 57] [overall bb eval= 183] [# dominant pts= 6] [# new pts= 1] [f1=52.02241823 f2=51.56141823] - MADS run 4/30 ...... OK [bb eval= 49] [overall bb eval= 232] [# dominant pts= 6] [# new pts= 0] [f1=52.02241823 f2=51.70341823] - MADS run 5/30 ...... OK [bb eval=181] [overall bb eval= 413] [# dominant pts= 5] [# new pts= -1] [f1=44.95823059 f2=43.96223059] - MADS run 6/30 ...... OK [bb eval=203] [overall bb eval= 616] [# dominant pts= 5] [# new pts= 0] [f1=44.90686591 f2=43.90786591] - MADS run 7/30 ...... OK [bb eval=138] [overall bb eval= 754] [# dominant pts= 8] [# new pts= 3] [f1=44.90641676 f2=43.90741676] - MADS run 8/30 ...... OK [bb eval=124] [overall bb eval= 878] [# dominant pts= 8] [# new pts= 0] [f1=44.90640745 f2=43.91240745] - MADS run 9/30 ...... OK [bb eval=180] [overall bb eval= 1058] [# dominant pts= 8] [# new pts= 0] [f1=44.90640744 f2=43.91440744] - MADS run 10/30 ...... OK [bb eval= 96] [overall bb eval= 1154] [# dominant pts= 8] [# new pts= 0] [f1=44.90640744 f2=43.91340744] - MADS run 11/30 ...... OK [bb eval=168] [overall bb eval= 1322] [# dominant pts= 11] [# new pts= 3] [f1=44.90640744 f2=43.97340744] - MADS run 12/30 ...... OK [bb eval=201] [overall bb eval= 1523] [# dominant pts= 10] [# new pts= -1] [f1=44.89376891 f2=43.89876891] - MADS run 13/30 ...... OK [bb eval=204] [overall bb eval= 1727] [# dominant pts= 12] [# new pts= 2] [f1=44.88950881 f2=43.90550881] - MADS run 14/30 ...... OK [bb eval=202] [overall bb eval= 1929] [# dominant pts= 10] [# new pts= -2] [f1=44.88548533 f2=43.90048533] - MADS run 15/30 ...... OK [bb eval=212] [overall bb eval= 2141] [# dominant pts= 10] [# new pts= 0] [f1=44.88519731 f2=43.88619731] - MADS run 16/30 ...... OK [bb eval=209] [overall bb eval= 2350] [# dominant pts= 9] [# new pts= -1] [f1=44.88510307 f2=43.91210307] - MADS run 17/30 ...... OK [bb eval=203] [overall bb eval= 2553] [# dominant pts= 9] [# new pts= 0] [f1=44.88508265 f2=43.90208265] - MADS run 18/30 ...... OK [bb eval=239] [overall bb eval= 2792] [# dominant pts= 9] [# new pts= 0] [f1=44.88508168 f2=43.90108168] - MADS run 19/30 ...... OK [bb eval=222] [overall bb eval= 3014] [# dominant pts= 9] [# new pts= 0] [f1=44.8850816 f2=43.9070816] - MADS run 20/30 ...... OK [bb eval=207] [overall bb eval= 3221] [# dominant pts= 8] [# new pts= -1] [f1=44.8850816 f2=43.9610816] - MADS run 21/30 ...... OK [bb eval=180] [overall bb eval= 3401] [# dominant pts= 6] [# new pts= -2] [f1=44.8850816 f2=43.9010816] - MADS run 22/30 ...... OK [bb eval=174] [overall bb eval= 3575] [# dominant pts= 11] [# new pts= 5] [f1=44.8850816 f2=44.0440816] - MADS run 23/30 ...... OK [bb eval=176] [overall bb eval= 3751] [# dominant pts= 9] [# new pts= -2] [f1=44.8850816 f2=43.9800816] - MADS run 24/30 ...... OK [bb eval=187] [overall bb eval= 3938] [# dominant pts= 8] [# new pts= -1] [f1=44.8850816 f2=44.1020816] - MADS run 25/30 ...... OK [bb eval=166] [overall bb eval= 4104] [# dominant pts= 10] [# new pts= 2] [f1=44.8850816 f2=43.9460816] - MADS run 26/30 ...... OK [bb eval=176] [overall bb eval= 4280] [# dominant pts= 11] [# new pts= 1] [f1=44.8850816 f2=43.9870816] - MADS run 27/30 ...... OK [bb eval= 2] [overall bb eval= 4282] [# dominant pts= 11] [# new pts= 0] [f1=44.8850816 f2=43.9460816] - MADS run 28/30 ...... OK [bb eval= 0] [overall bb eval= 4282] [# dominant pts= 11] [# new pts= 0] [f1=44.8850816 f2=43.9870816] - MADS run 29/30 ...... OK [bb eval= 0] [overall bb eval= 4282] [# dominant pts= 11] [# new pts= 0] [f1=44.8850816 f2=43.9460816] - MADS run 30/30 ...... OK [bb eval= 0] [overall bb eval= 4282] [# dominant pts= 11] [# new pts= 0] [f1=44.8850816 f2=43.9870816] - -} end of run (max number of MADS runs) - - -blackbox evaluations : 4282 -number of MADS runs : 30 + MADS run 1 ...... OK [bb eval= 78] [overall bb eval= 78] [# dominant pts= 2] [# new pts= 2] [f1=52.02241823 f2=51.31041823] + MADS run 2 ...... OK [bb eval= 39] [overall bb eval= 117] [# dominant pts= 3] [# new pts= 1] [f1=52.0224221 f2=51.0754221] + MADS run 3 ...... OK [bb eval= 39] [overall bb eval= 156] [# dominant pts= 3] [# new pts= 0] [f1=52.02242186 f2=51.23342186] + MADS run 4 ...... OK [bb eval= 38] [overall bb eval= 194] [# dominant pts= 4] [# new pts= 1] [f1=52.02242186 f2=51.06242186] + MADS run 5 ...... OK [bb eval= 39] [overall bb eval= 233] [# dominant pts= 5] [# new pts= 1] [f1=52.02242186 f2=51.19342186] + MADS run 6 ...... OK [bb eval= 7] [overall bb eval= 240] [# dominant pts= 5] [# new pts= 0] [f1=52.02242186 f2=51.19342186] + MADS run 7 ...... OK [bb eval= 39] [overall bb eval= 279] [# dominant pts= 2] [# new pts= -3] [f1=45.36506988 f2=44.51306988] + MADS run 8 ...... OK [bb eval= 39] [overall bb eval= 318] [# dominant pts= 3] [# new pts= 1] [f1=45.36506988 f2=44.51306988] + MADS run 9 ...... OK [bb eval= 39] [overall bb eval= 357] [# dominant pts= 7] [# new pts= 4] [f1=44.99982416 f2=44.55082416] + MADS run 10 ...... OK [bb eval= 39] [overall bb eval= 396] [# dominant pts= 4] [# new pts= -3] [f1=44.97647101 f2=44.00347101] + MADS run 11 ...... OK [bb eval= 39] [overall bb eval= 435] [# dominant pts= 4] [# new pts= 0] [f1=44.9661848 f2=44.1371848] + MADS run 12 ...... OK [bb eval= 39] [overall bb eval= 474] [# dominant pts= 5] [# new pts= 1] [f1=44.9661848 f2=44.1371848] + MADS run 13 ...... OK [bb eval= 26] [overall bb eval= 500] [# dominant pts= 5] [# new pts= 0] [f1=44.96576761 f2=45.17076761] + +} end of run (max number of bb evaluations) + + +blackbox evaluations : 500 +number of MADS runs : 13 Pareto front { - 44.8849906075 45.5549906075 - 44.8850816013 45.5000816013 - 44.8850816013 45.2800816013 - 44.8850816013 44.2430816013 - 44.8850816013 43.9800816013 - 44.8850816013 43.9260816013 - 44.8850816013 43.9020816013 - 44.8850816013 43.9010816013 - 44.8850816075 43.8900816075 - 44.8850816076 43.8890816076 - 44.8851973070 43.8861973070 + 44.9348019953 45.4168019953 + 44.9657676108 45.1707676108 + 44.9661847951 44.1371847951 + 44.9738637269 44.0708637269 + 44.9764710086 44.0034710086 } -number of Pareto points: 11 +number of Pareto points: 5 diff --git a/examples/advanced/categorical/single_obj/categorical.cpp b/examples/advanced/categorical/single_obj/categorical.cpp index 8611469..c79bcc0 100644 --- a/examples/advanced/categorical/single_obj/categorical.cpp +++ b/examples/advanced/categorical/single_obj/categorical.cpp @@ -44,404 +44,415 @@ using namespace std; using namespace NOMAD; -#define USE_SURROGATE false +#define USE_SURROGATE false /*----------------------------------------*/ /* the problem */ /*----------------------------------------*/ -class My_Evaluator : public Evaluator { +class My_Evaluator : public Evaluator +{ public: - My_Evaluator ( const Parameters & p ) : + My_Evaluator ( const Parameters & p ) : Evaluator ( p ) {} - - ~My_Evaluator ( void ) {} - - bool eval_x ( Eval_Point & x , - const Double & h_max , - bool & count_eval ) const; + + ~My_Evaluator ( void ) {} + + bool eval_x ( Eval_Point & x , + const Double & h_max , + bool & count_eval ) const; }; /*--------------------------------------------------*/ /* user class to define categorical neighborhoods */ /*--------------------------------------------------*/ -class My_Extended_Poll : public Extended_Poll { - +class My_Extended_Poll : public Extended_Poll +{ + private: - - // signatures for 1, 2, and 3 assets: - Signature * _s1 , * _s2 , * _s3; - + + // signatures for 1, 2, and 3 assets: + Signature * _s1 , * _s2 , * _s3; + public: - - // constructor: - My_Extended_Poll ( Parameters & ); - - // destructor: - virtual ~My_Extended_Poll ( void ) { delete _s1; delete _s2; delete _s3; } - - // construct the extended poll points: - virtual void construct_extended_points ( const Eval_Point & ); - + + // constructor: + My_Extended_Poll ( Parameters & ); + + // destructor: + virtual ~My_Extended_Poll ( void ) { delete _s1; delete _s2; delete _s3; } + + // construct the extended poll points: + virtual void construct_extended_points ( const Eval_Point & ); + }; /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) { - - // NOMAD initializations: - begin ( argc , argv ); - - // display: - Display out ( cout ); - out.precision ( DISPLAY_PRECISION_STD ); - - // check the number of processess: +int main ( int argc , char ** argv ) +{ + + // NOMAD initializations: + begin ( argc , argv ); + + // display: + Display out ( cout ); + out.precision ( DISPLAY_PRECISION_STD ); + + // check the number of processess: #ifdef USE_MPI - if ( Slave::get_nb_processes() < 2 ) { - if ( Slave::is_master() ) - cerr << "usage: \'mpirun -np p ./categorical\' with p>1" - << endl; - end(); - return EXIT_FAILURE; - } + if ( Slave::get_nb_processes() < 2 ) + { + if ( Slave::is_master() ) + cerr << "usage: \'mpirun -np p ./categorical\' with p>1" + << endl; + end(); + return EXIT_FAILURE; + } #endif - - try { - - // parameters creation: - Parameters p ( out ); - - if ( USE_SURROGATE ) - p.set_HAS_SGTE ( true ); - - // p.set_DISPLAY_DEGREE ( FULL_DISPLAY ); - p.set_MAX_BB_EVAL ( 200 ); - - p.set_DIMENSION (3); - - vector<bb_output_type> bbot (3); - bbot[0] = EB; // budget constraint - bbot[1] = EB; // total value >= 1$ - bbot[2] = OBJ; // objective - p.set_BB_OUTPUT_TYPE ( bbot ); - - // categorical variables: - p.set_BB_INPUT_TYPE ( 0 , CATEGORICAL ); - p.set_BB_INPUT_TYPE ( 1 , CATEGORICAL ); - - // initial point - Point x0 ( 3 , 0 ); - x0[0] = 1; // 1 asset - x0[1] = 0; // of type 0 - x0[2] = 100; // 100$ - p.set_X0 ( x0 ); - - Point lb ( 3 ); - Point ub ( 3 ); - // Categorical variables 0 and 1 don't need bounds - lb[2] = 0; ub[2] = 10000; - - p.set_LOWER_BOUND ( lb ); - p.set_UPPER_BOUND ( ub ); - - p.set_DISPLAY_STATS ( "bbe ( sol ) obj" ); - - // extended poll trigger: - p.set_EXTENDED_POLL_TRIGGER ( 10 , false ); - - // parameters validation: - p.check(); - - // custom evaluator creation: - My_Evaluator ev ( p ); - - // extended poll: - My_Extended_Poll ep ( p ); - - // algorithm creation and execution: - Mads mads ( p , &ev , &ep , NULL , NULL ); - mads.run(); - } - catch ( exception & e ) { - string error = string ( "NOMAD has been interrupted: " ) + e.what(); - if ( Slave::is_master() ) - cerr << endl << error << endl << endl; - } - - - Slave::stop_slaves ( out ); - end(); - - return EXIT_SUCCESS; + + try + { + + // parameters creation: + Parameters p ( out ); + + if ( USE_SURROGATE ) + p.set_HAS_SGTE ( true ); + + // p.set_DISPLAY_DEGREE ( FULL_DISPLAY ); + + p.set_DIMENSION (3); + + vector<bb_output_type> bbot (3); + bbot[0] = EB; // budget constraint + bbot[1] = EB; // total value >= 1$ + bbot[2] = OBJ; // objective + p.set_BB_OUTPUT_TYPE ( bbot ); + + + // categorical variables: + p.set_BB_INPUT_TYPE ( 0 , CATEGORICAL ); + p.set_BB_INPUT_TYPE ( 1 , CATEGORICAL ); + + // initial point + Point x0 ( 3 , 0 ); + x0[0] = 1; // 1 asset + x0[1] = 0; // of type 0 + x0[2] = 100; // 100$ + p.set_X0 ( x0 ); + + Point lb ( 3 ); + Point ub ( 3 ); + // Categorical variables 0 and 1 don't need bounds + lb[2] = 0; ub[2] = 10000; + + p.set_LOWER_BOUND ( lb ); + p.set_UPPER_BOUND ( ub ); + + p.set_DISPLAY_STATS ( "bbe ( sol ) obj" ); + + // extended poll trigger: + p.set_EXTENDED_POLL_TRIGGER ( 10 , false ); + + // parameters validation: + p.check(); + + // custom evaluator creation: + My_Evaluator ev ( p ); + + // extended poll: + My_Extended_Poll ep ( p ); + + // algorithm creation and execution: + Mads mads ( p , &ev , &ep , NULL , NULL ); + mads.run(); + } + catch ( exception & e ) { + string error = string ( "NOMAD has been interrupted: " ) + e.what(); + if ( Slave::is_master() ) + cerr << endl << error << endl << endl; + } + + + Slave::stop_slaves ( out ); + end(); + + return EXIT_SUCCESS; } /*----------------------------------------------------*/ /* eval_x */ /*----------------------------------------------------*/ bool My_Evaluator::eval_x ( Eval_Point & x , - const Double & h_max , - bool & count_eval ) const { - - // number of assets: - int n = static_cast<int> ( x[0].value() ); - - // get the asset types and values: - Point v ( 3 , 0.0 ); - Double vmin = 10000 , tmp; - for ( int i = 0 ; i < n ; ++i ) { - tmp = v [ static_cast<int> ( x[2*i+1].value() ) ] = x[2*i+2]; - if ( tmp < vmin ) - vmin = tmp; - } - - // constraints (budget and each asset is considered with at least 1$): - Double vt = v[0] + v[1] + v[2]; - Double h = vt - 10000; - x.set_bb_output ( 0 , h ); - x.set_bb_output ( 1 , 1-vmin ); - - if ( h <= 0 && vmin >= 1 ) { - - // compute the risk and revenue: - Double vt2 = vt.pow2(); - Double rev = v[0] * 0.0891 + v[1] * 0.2137 + v[2] * 0.2346; - Double risk = 0.01 * (v[0]/vt).pow2() + - 0.05 * (v[1]/vt).pow2() + - 0.09 * (v[2]/vt).pow2() + - 0.02 * (v[0]*v[1]/vt2) + - 0.02 * (v[0]*v[2]/vt2) + - 0.10 * (v[1]*v[2]/vt2); - - // the objective is taken as a scaled distance - // between (risk,revenue) and (risk_best,rev_best): - Double a = ( risk - 0.01 ) * 100 / 0.08; - Double b = ( rev - 891 ) * 100 / 1455; - - x.set_bb_output ( 2 , ( a.pow2() + (100-b).pow2() ).sqrt() ); - - count_eval = true; - } - else - x.set_bb_output ( 2 , 145 ); - - // simulation of a surrogate: - if ( USE_SURROGATE && x.get_eval_type() == SGTE ) { - Double f = x.get_bb_outputs()[2]; - f.round(); - f += ( (rand()%2) ? -1.0 : 1.0 ) * ( (rand()%1000) / 1000.0 ); - x.set_bb_output ( 2 , f ); - } - - return true; + const Double & h_max , + bool & count_eval ) const +{ + + // number of assets: + int n = static_cast<int> ( x[0].value() ); + + count_eval=false; + + // get the asset types and values: + Point v ( 3 , 0.0 ); + Double vmin = 10000 , tmp; + for ( int i = 0 ; i < n ; ++i ) + { + tmp = v [ static_cast<int> ( x[2*i+1].value() ) ] = x[2*i+2]; + if ( tmp < vmin ) + vmin = tmp; + } + + // constraints (budget and each asset is considered with at least 1$): + Double vt = v[0] + v[1] + v[2]; + Double h = vt - 10000; + x.set_bb_output ( 0 , h ); + x.set_bb_output ( 1 , 1-vmin ); + + if ( h <= 0 && vmin >= 1 ) + { + + // compute the risk and revenue: + Double vt2 = vt.pow2(); + Double rev = v[0] * 0.0891 + v[1] * 0.2137 + v[2] * 0.2346; + Double risk = 0.01 * (v[0]/vt).pow2() + + 0.05 * (v[1]/vt).pow2() + + 0.09 * (v[2]/vt).pow2() + + 0.02 * (v[0]*v[1]/vt2) + + 0.02 * (v[0]*v[2]/vt2) + + 0.10 * (v[1]*v[2]/vt2); + + // the objective is taken as a scaled distance + // between (risk,revenue) and (risk_best,rev_best): + Double a = ( risk - 0.01 ) * 100 / 0.08; + Double b = ( rev - 891 ) * 100 / 1455; + + x.set_bb_output ( 2 , ( a.pow2() + (100-b).pow2() ).sqrt() ); + + count_eval = true; + } + else + x.set_bb_output ( 2 , 145 ); + + // simulation of a surrogate: + if ( USE_SURROGATE && x.get_eval_type() == SGTE ) + { + Double f = x.get_bb_outputs()[2]; + f.round(); + f += ( (rand()%2) ? -1.0 : 1.0 ) * ( (rand()%1000) / 1000.0 ); + x.set_bb_output ( 2 , f ); + } + + return true; } /*-----------------------------------------*/ /* constructor: creates the 3 signatures */ /*-----------------------------------------*/ My_Extended_Poll::My_Extended_Poll ( Parameters & p ) - : Extended_Poll ( p ) , - _s1 ( NULL ) , - _s2 ( NULL ) , - _s3 ( NULL ) +: Extended_Poll ( p ) , +_s1 ( NULL ) , +_s2 ( NULL ) , +_s3 ( NULL ) { - - // signature for 1 asset: - // ---------------------- - vector<bb_input_type> bbit_1 (3); - bbit_1[0] = bbit_1[1] = CATEGORICAL; - bbit_1[2] = CONTINUOUS; - - const Point & d0_1 = p.get_initial_mesh_size(); - const Point & lb_1 = p.get_lb(); - const Point & ub_1 = p.get_ub(); - - - int halton_seed = p.get_halton_seed(); - - _s1 = new Signature ( 3 , - bbit_1 , - d0_1 , - lb_1 , - ub_1 , - p.get_direction_types () , - p.get_sec_poll_dir_types() , - halton_seed++ , - _p.out() ); - - // signature for 2 assets: - // ----------------------- - { - vector<bb_input_type> bbit_2 (5); - Point d0_2 (5); - Point lb_2 (5); - Point ub_2 (5); - - // Categorical variables don't need bounds - for ( int i = 0 ; i < 5 ; ++i ) + + // signature for 1 asset: + // ---------------------- + vector<bb_input_type> bbit_1 (3); + bbit_1[0] = bbit_1[1] = CATEGORICAL; + bbit_1[2] = CONTINUOUS; + + const Point & d0_1 = p.get_initial_poll_size(); + const Point & lb_1 = p.get_lb(); + const Point & ub_1 = p.get_ub(); + + _s1 = new Signature ( 3 , + bbit_1 , + d0_1 , + lb_1 , + ub_1 , + p.get_direction_types () , + p.get_sec_poll_dir_types() , + _p.out() ); + + // signature for 2 assets: + // ----------------------- { - bbit_2[i] = bbit_1[1+(i-1)%2]; - d0_2 [i] = d0_1 [1+(i-1)%2]; - lb_2 [i] = lb_1 [1+(i-1)%2]; - ub_2 [i] = ub_1 [1+(i-1)%2]; - } - - _s2 = new Signature ( 5 , - bbit_2 , - d0_2 , - lb_2 , - ub_2 , - p.get_direction_types () , - p.get_sec_poll_dir_types() , - halton_seed++ , - _p.out() ); - } - - // signature for 3 assets: - // ----------------------- - { - vector<bb_input_type> bbit_3 (7); - Point d0_3 (7); - Point lb_3 (7); - Point ub_3 (7); - - // Categorical variables don't need bounds - for ( int i = 0 ; i < 7 ; ++i ) + vector<bb_input_type> bbit_2 (5); + Point d0_2 (5); + Point lb_2 (5); + Point ub_2 (5); + + // Categorical variables don't need bounds + for ( int i = 0 ; i < 5 ; ++i ) + { + bbit_2[i] = bbit_1[1+(i-1)%2]; + d0_2 [i] = d0_1 [1+(i-1)%2]; + lb_2 [i] = lb_1 [1+(i-1)%2]; + ub_2 [i] = ub_1 [1+(i-1)%2]; + } + + _s2 = new Signature ( 5 , + bbit_2 , + d0_2 , + lb_2 , + ub_2 , + p.get_direction_types () , + p.get_sec_poll_dir_types() , + _p.out() ); + } + + // signature for 3 assets: + // ----------------------- { - bbit_3[i] = bbit_1[1+(i-1)%2]; - d0_3 [i] = d0_1 [1+(i-1)%2]; - lb_3 [i] = lb_1 [1+(i-1)%2]; - ub_3 [i] = ub_1 [1+(i-1)%2]; - } - - _s3 = new Signature ( 7 , - bbit_3 , - d0_3 , - lb_3 , - ub_3 , - p.get_direction_types () , - p.get_sec_poll_dir_types() , - halton_seed , - _p.out() ); - } + vector<bb_input_type> bbit_3 (7); + Point d0_3 (7); + Point lb_3 (7); + Point ub_3 (7); + + // Categorical variables don't need bounds + for ( int i = 0 ; i < 7 ; ++i ) + { + bbit_3[i] = bbit_1[1+(i-1)%2]; + d0_3 [i] = d0_1 [1+(i-1)%2]; + lb_3 [i] = lb_1 [1+(i-1)%2]; + ub_3 [i] = ub_1 [1+(i-1)%2]; + } + + _s3 = new Signature ( 7 , + bbit_3 , + d0_3 , + lb_3 , + ub_3 , + p.get_direction_types () , + p.get_sec_poll_dir_types() , + _p.out() ); + } } /*--------------------------------------*/ /* construct the extended poll points */ /* (categorical neighborhoods) */ /*--------------------------------------*/ -void My_Extended_Poll::construct_extended_points ( const Eval_Point & x ) { - - // number of assets: - int n = static_cast<int> ( x[0].value() ); - - // 1 asset: - // -------- - if ( n==1 ) { - - int cur_type = static_cast<int> ( x[1].value() ); - - // this vector contains the types of the other assets: - vector<int> other_types; - switch ( cur_type ) { - case 0: - case 2: - other_types.push_back(1); - break; - default: - other_types.push_back(0); - other_types.push_back(2); - } - - // add 1 asset (1 or 2 neighbors): - for ( size_t k = 0 ; k < other_types.size() ; ++k ) { - Point y (5); - y[0] = 2; - y[1] = cur_type; - y[3] = other_types[k]; - y[2] = y[4] = x[2]/2.0; - - add_extended_poll_point ( y , *_s2 ); - } - - // change the type of the asset to the other types (1 or 2 neighbors): - for ( size_t k = 0 ; k < other_types.size() ; ++k ) { - Point y = x ; - y[1] = other_types[k]; - - add_extended_poll_point ( y , *_s1 ); - } - } - - // 2 assets: - // --------- - else if ( n == 2 ) { - - int other_type = static_cast<int> ( (3 - x[1] - x[3]).value() ); - - // change the type of one asset (2 neighbors): - { - Point y1 = x; - Point y2 = x; - - y1[1] = y2[3] = other_type; - - add_extended_poll_point ( y1 , *_s2 ); - add_extended_poll_point ( y2 , *_s2 ); - } - - // remove 1 asset (2 neighbors): - { - Point y1(3) , y2(3); - y1[0] = y2[0] = 1; - y1[1] = x[1]; - y2[1] = x[3]; - y1[2] = y2[2] = x[2]+x[4]; - - add_extended_poll_point ( y1 , *_s1 ); - add_extended_poll_point ( y2 , *_s1 ); - } - - // add one asset (1 neighbor): - { - Point y(7); - y[0] = 3; - - y[1] = x[1]; - y[3] = x[3]; - y[5] = other_type; - - y[2] = y[4] = y[6] = (x[2]+x[4])/3.0; - - add_extended_poll_point ( y , *_s3 ); - } - - } - - // 3 assets: - // --------- - else { - - // remove one asset (3 neighbors): - Point y1(5); - Point y2(5); - Point y3(5); - - y1[0] = y2[0] = y3[0] = 2; - - y1[1] = x[1]; - y1[3] = x[3]; - - y2[1] = x[1]; - y2[3] = x[5]; - - y3[1] = x[3]; - y3[3] = x[5]; - - y1[2] = y1[4] = y2[2] = y2[4] = y3[2] = y3[4] = (x[2]+x[4]+x[6]) / 2.0; - - add_extended_poll_point ( y1 , *_s2 ); - add_extended_poll_point ( y2 , *_s2 ); - add_extended_poll_point ( y3 , *_s2 ); - } +void My_Extended_Poll::construct_extended_points ( const Eval_Point & x ) +{ + + // number of assets: + int n = static_cast<int> ( x[0].value() ); + + // 1 asset: + // -------- + if ( n==1 ) + { + + int cur_type = static_cast<int> ( x[1].value() ); + + // this vector contains the types of the other assets: + vector<int> other_types; + switch ( cur_type ) + { + case 0: + case 2: + other_types.push_back(1); + break; + default: + other_types.push_back(0); + other_types.push_back(2); + } + + // add 1 asset (1 or 2 neighbors): + for ( size_t k = 0 ; k < other_types.size() ; ++k ) + { + Point y (5); + y[0] = 2; + y[1] = cur_type; + y[3] = other_types[k]; + y[2] = y[4] = x[2]/2.0; + + add_extended_poll_point ( y , *_s2 ); + } + + // change the type of the asset to the other types (1 or 2 neighbors): + for ( size_t k = 0 ; k < other_types.size() ; ++k ) + { + Point y = x ; + y[1] = other_types[k]; + + add_extended_poll_point ( y , *_s1 ); + } + } + + // 2 assets: + // --------- + else if ( n == 2 ) + { + + int other_type = static_cast<int> ( (3 - x[1] - x[3]).value() ); + + // change the type of one asset (2 neighbors): + { + Point y1 = x; + Point y2 = x; + + y1[1] = y2[3] = other_type; + + add_extended_poll_point ( y1 , *_s2 ); + add_extended_poll_point ( y2 , *_s2 ); + } + + // remove 1 asset (2 neighbors): + { + Point y1(3) , y2(3); + y1[0] = y2[0] = 1; + y1[1] = x[1]; + y2[1] = x[3]; + y1[2] = y2[2] = x[2]+x[4]; + + add_extended_poll_point ( y1 , *_s1 ); + add_extended_poll_point ( y2 , *_s1 ); + } + + // add one asset (1 neighbor): + { + Point y(7); + y[0] = 3; + + y[1] = x[1]; + y[3] = x[3]; + y[5] = other_type; + + y[2] = y[4] = y[6] = (x[2]+x[4])/3.0; + + add_extended_poll_point ( y , *_s3 ); + } + + } + + // 3 assets: + // --------- + else { + + // remove one asset (3 neighbors): + Point y1(5); + Point y2(5); + Point y3(5); + + y1[0] = y2[0] = y3[0] = 2; + + y1[1] = x[1]; + y1[3] = x[3]; + + y2[1] = x[1]; + y2[3] = x[5]; + + y3[1] = x[3]; + y3[3] = x[5]; + + y1[2] = y1[4] = y2[2] = y2[4] = y3[2] = y3[4] = (x[2]+x[4]+x[6]) / 2.0; + + add_extended_poll_point ( y1 , *_s2 ); + add_extended_poll_point ( y2 , *_s2 ); + add_extended_poll_point ( y3 , *_s2 ); + } } diff --git a/examples/advanced/categorical/single_obj/runExample.log b/examples/advanced/categorical/single_obj/runExample.log index 8be251a..d4a89ba 100644 --- a/examples/advanced/categorical/single_obj/runExample.log +++ b/examples/advanced/categorical/single_obj/runExample.log @@ -1,36 +1,761 @@ Warning: { Model use is disabled for problem with categorical variables. } +Warning: { + Anisotropic mesh are not supported with categorical and binary variables. +} MADS run { BBE ( SOL ) OBJ - 1 ( 1 0 100.0000000000 ) 160.6247422680 - 3 ( 1 0 1100.0000000000 ) 154.5010309278 - 4 ( 1 0 4100.0000000000 ) 136.1298969072 - 5 ( 1 0 10000.0000000000 ) 100.0000000000 - 7 ( 2 0 5000.0000000000 1 5000.0000000000 ) 58.5324359492 - 11 ( 2 0 5000.0000000000 2 5000.0000000000 ) 55.9016994375 - 17 ( 3 0 3333.3333333333 2 3333.3333333333 1 3333.3333333333 ) 47.1682905221 - 57+ 3 ( 2 0 4000.0000000000 2 6000.0000000000 ) 53.8144961883 (ExtendedPoll) - 85+ 3 ( 2 0 4937.5000000000 2 5062.5000000000 ) 55.6303106280 (ExtendedPoll) - 85+ 4 ( 2 0 4750.0000000000 2 5250.0000000000 ) 54.9175874038 (ExtendedPoll) - 85+ 12 ( 2 0 4125.0000000000 2 5875.0000000000 ) 53.7856009462 (ExtendedPoll) - 171 ( 3 0 3333.2365055879 2 3333.4012826284 1 3333.3571751912 ) 47.1681115325 - 172 ( 3 0 3332.9460223516 2 3333.6051305135 1 3333.4287007650 ) 47.1675747997 - 173 ( 3 0 3331.7840894063 2 3334.4205220540 1 3333.7148030599 ) 47.1654314112 - 174 ( 3 0 3327.1363576253 2 3337.6820882161 1 3334.8592122396 ) 47.1569145813 - 175 ( 3 0 3308.5454305013 2 3350.7283528646 1 3339.4368489583 ) 47.1237573269 - 176 ( 3 0 3234.1817220052 2 3402.9134114583 1 3357.7473958333 ) 47.0058461470 - 177 ( 3 0 2936.7268880208 2 3611.6536458333 1 3430.9895833333 ) 46.7791198645 - 180 ( 3 0 2939.6565755208 2 3626.3020833333 1 3433.4309895833 ) 46.5971165597 - 188+ 3 ( 2 0 4968.4448242188 2 5030.9448242188 ) 55.7700229860 (ExtendedPoll) - 188+ 4 ( 2 0 4874.6948242188 2 5124.6948242188 ) 55.3815102271 (ExtendedPoll) - 188+ 5 ( 2 0 4499.6948242188 2 5499.6948242188 ) 54.2281651973 (ExtendedPoll) - 200 ( 3 0 2939.6565755208 2 3626.3020833333 1 3433.4309895833 ) 46.5971165597 + 1 ( 1 0 100.0000000000 ) 160.6247422680 + 2 ( 1 0 1254.7005383793 ) 153.5536894866 + 3 ( 1 0 4718.8021535170 ) 132.3405311424 + 4 ( 1 0 10000.0000000000 ) 100.0000000000 + 6 ( 2 0 5000.0000000000 1 5000.0000000000 ) 58.5324359492 + 9 ( 2 0 5000.0000000000 2 5000.0000000000 ) 55.9016994375 + 13 ( 3 0 3333.3333333333 2 3333.3333333333 1 3333.3333333333 ) 47.1682905221 + 25+1 ( 2 0 4664.5898033750 2 5335.4101966250 ) 54.6460175208 (ExtendedPoll) + 25+2 ( 2 0 3658.3592135001 2 6341.6407864999 ) 54.3665216385 (ExtendedPoll) + 36+5 ( 2 0 4853.2580389766 2 5104.8156864453 ) 55.7859562011 (ExtendedPoll) + 46+6 ( 2 0 4952.8329410996 2 5040.1793464707 ) 55.7796437455 (ExtendedPoll) + 46+7 ( 2 0 4811.3317643985 2 5160.7173858828 ) 55.4595714411 (ExtendedPoll) + 46+8 ( 2 0 4245.3270575938 2 5642.8695435312 ) 54.9467100128 (ExtendedPoll) + 46+14 ( 2 0 4217.3762078751 2 5761.6606548359 ) 54.0237235981 (ExtendedPoll) + 68+2 ( 2 0 4105.5728090001 2 5894.4271909999 ) 53.7841727607 (ExtendedPoll) + 83+6 ( 2 0 4077.6219592813 2 5838.5254915624 ) 54.5583352238 (ExtendedPoll) + 83+13 ( 2 0 4079.3688873888 2 5901.4149034296 ) 53.9607874220 (ExtendedPoll) + 83+17 ( 2 0 4048.3609134820 2 5933.2963413900 ) 53.9575135294 (ExtendedPoll) + 83+20 ( 2 0 4114.7441815640 2 5872.1538576303 ) 53.9056113440 (ExtendedPoll) + 83+26 ( 2 0 4103.7166978859 2 5883.2905243151 ) 53.9036253851 (ExtendedPoll) + 83+27 ( 2 0 4070.6342468517 2 5916.7005243695 ) 53.9019093307 (ExtendedPoll) + 83+33 ( 2 0 4066.9220246234 2 5931.8769623028 ) 53.7986288783 (ExtendedPoll) + 135+3 ( 2 0 4552.7864045000 2 5447.2135955000 ) 54.3435557967 (ExtendedPoll) + 135+17 ( 2 0 4547.0542966476 2 5452.5362670773 ) 54.3341271736 (ExtendedPoll) + 135+18 ( 2 0 4529.8579730901 2 5468.5042818092 ) 54.3067391679 (ExtendedPoll) + 135+19 ( 2 0 4461.0726788604 2 5532.3763407368 ) 54.2108013388 (ExtendedPoll) + 135+20 ( 2 0 4185.9315019415 2 5787.8645764472 ) 54.0536810905 (ExtendedPoll) + 135+24 ( 2 0 4166.7152927598 2 5812.7583019780 ) 53.9898429352 (ExtendedPoll) + 135+25 ( 2 0 4109.0666652149 2 5887.4394785702 ) 53.8164151300 (ExtendedPoll) + 135+30 ( 2 0 4087.2300638722 2 5910.1495439667 ) 53.8086966314 (ExtendedPoll) + 135+31 ( 2 0 4021.7202598438 2 5978.2797401562 ) 53.8029621572 (ExtendedPoll) + 178+9 ( 2 0 4997.1817136392 2 5002.7091033541 ) 55.8904416155 (ExtendedPoll) + 178+10 ( 2 0 4988.7268545568 2 5010.8364134164 ) 55.8568544583 (ExtendedPoll) + 178+11 ( 2 0 4954.9074182272 2 5043.3456536654 ) 55.7253209743 (ExtendedPoll) + 178+12 ( 2 0 4819.6296729087 2 5173.3826146616 ) 55.2455191020 (ExtendedPoll) + 178+13 ( 2 0 4278.5186916348 2 5693.5304586464 ) 54.1478187840 (ExtendedPoll) + 178+17 ( 2 0 4250.5678419161 2 5749.4321580839 ) 53.8463541922 (ExtendedPoll) + 209+11 ( 2 0 4991.4018382213 2 5006.9604166780 ) 55.8833196229 (ExtendedPoll) + 209+12 ( 2 0 4965.6073528851 2 5027.8416667120 ) 55.8295760866 (ExtendedPoll) + 209+13 ( 2 0 4862.4294115405 2 5111.3666668481 ) 55.6359728814 (ExtendedPoll) + 209+14 ( 2 0 4449.7176461622 2 5445.4666673925 ) 55.2305749540 (ExtendedPoll) + 209+18 ( 2 0 4416.5260121211 2 5499.6214387226 ) 54.9360602700 (ExtendedPoll) + 209+19 ( 2 0 4316.9511099981 2 5662.0857527128 ) 54.1235694449 (ExtendedPoll) + 209+21 ( 2 0 4226.1108484122 2 5745.9383018691 ) 54.0981732449 (ExtendedPoll) + 209+28 ( 2 0 4295.9879727091 2 5690.0366024316 ) 54.0285296848 (ExtendedPoll) + 209+39 ( 2 0 4295.1963959104 2 5693.8580076666 ) 53.9975464791 (ExtendedPoll) + 209+40 ( 2 0 4292.8216655143 2 5705.3222233715 ) 53.9048916226 (ExtendedPoll) + 258+8 ( 2 0 4991.6202042347 2 5007.1787826914 ) 55.8789766881 (ExtendedPoll) + 258+9 ( 2 0 4966.4808169388 2 5028.7151307657 ) 55.8122316385 (ExtendedPoll) + 258+10 ( 2 0 4865.9232677554 2 5114.8605230630 ) 55.5670382161 (ExtendedPoll) + 258+11 ( 2 0 4463.6930710215 2 5459.4420922519 ) 54.9622403869 (ExtendedPoll) + 258+15 ( 2 0 4465.4399991290 2 5522.3315041191 ) 54.2792880205 (ExtendedPoll) + 258+22 ( 2 0 4465.8494354041 2 5530.1380890991 ) 54.1936457881 (ExtendedPoll) + 258+25 ( 2 0 4460.3083978134 2 5535.6518309382 ) 54.1829242335 (ExtendedPoll) + 258+26 ( 2 0 4443.6852850412 2 5552.1930564553 ) 54.1517073596 (ExtendedPoll) + 258+27 ( 2 0 4377.1928339525 2 5618.3579585239 ) 54.0411998177 (ExtendedPoll) + 258+28 ( 2 0 4111.2230295975 2 5883.0175667983 ) 53.8374230147 (ExtendedPoll) + 258+38 ( 2 0 4118.0196717655 2 5879.1961615633 ) 53.8105466009 (ExtendedPoll) + 258+41 ( 2 0 4124.3795819065 2 5874.6650667847 ) 53.7943634220 (ExtendedPoll) + 258+50 ( 2 0 4124.8617357702 2 5874.5877643630 ) 53.7906784892 (ExtendedPoll) + 258+51 ( 2 0 4125.6516065844 2 5874.0132740894 ) 53.7887889498 (ExtendedPoll) + 258+53 ( 2 0 4123.8654408339 2 5876.1201649220 ) 53.7855913617 (ExtendedPoll) + 345+4 ( 2 0 4926.6290194883 2 5050.6609151152 ) 55.8573545355 (ExtendedPoll) + 345+5 ( 2 0 4706.5160779532 2 5202.6436604609 ) 55.8124774768 (ExtendedPoll) + 345+9 ( 2 0 4650.6143785157 2 5314.4470593359 ) 54.9951723917 (ExtendedPoll) + 345+18 ( 2 0 4648.1031693612 2 5329.8418632826 ) 54.8434056052 (ExtendedPoll) + 345+21 ( 2 0 4663.2796072945 2 5326.0204580476 ) 54.7617474708 (ExtendedPoll) + 345+24 ( 2 0 4676.3815681001 2 5317.5041835239 ) 54.7500380050 (ExtendedPoll) + 345+31 ( 2 0 4680.0460227630 2 5316.1598677537 ) 54.7351963289 (ExtendedPoll) + 345+34 ( 2 0 4683.8264843704 2 5315.1840446312 ) 54.7152907223 (ExtendedPoll) + 345+39 ( 2 0 4684.6722261763 2 5314.6957065739 ) 54.7138745538 (ExtendedPoll) + 345+42 ( 2 0 4683.5902055200 2 5315.5546697595 ) 54.7130556687 (ExtendedPoll) + 345+43 ( 2 0 4680.3441435508 2 5318.1315593164 ) 54.7106238781 (ExtendedPoll) + 345+44 ( 2 0 4667.3598956743 2 5328.4391175440 ) 54.7012704968 (ExtendedPoll) + 345+45 ( 2 0 4615.4229041681 2 5369.6693504543 ) 54.6698883036 (ExtendedPoll) + 345+46 ( 2 0 4407.6749381433 2 5534.5902820956 ) 54.6440687766 (ExtendedPoll) + 345+48 ( 2 0 4390.6423890959 2 5560.7942037069 ) 54.5173881146 (ExtendedPoll) + 345+49 ( 2 0 4339.5447419538 2 5639.4059685409 ) 54.1546080629 (ExtendedPoll) + 345+53 ( 2 0 4329.0631733093 2 5668.6670143402 ) 53.9515249195 (ExtendedPoll) + 345+60 ( 2 0 4327.2889494502 2 5672.1472226792 ) 53.9321944673 (ExtendedPoll) + 345+66 ( 2 0 4327.7553229574 2 5672.0024272464 ) 53.9295614439 (ExtendedPoll) + 345+67 ( 2 0 4328.5409288104 2 5671.4219660272 ) 53.9284968785 (ExtendedPoll) + 345+75 ( 2 0 4328.4706502466 2 5671.5217727832 ) 53.9281125932 (ExtendedPoll) + 425+16 ( 2 0 4999.6291616237 2 5000.3176329854 ) 55.9006895585 (ExtendedPoll) + 425+17 ( 2 0 4998.5166464947 2 5001.2705319414 ) 55.8976626910 (ExtendedPoll) + 425+18 ( 2 0 4994.0665859789 2 5005.0821277656 ) 55.8855968012 (ExtendedPoll) + 425+19 ( 2 0 4976.2663439156 2 5020.3285110625 ) 55.8380009177 (ExtendedPoll) + 425+20 ( 2 0 4905.0653756623 2 5081.3140442501 ) 55.6584535115 (ExtendedPoll) + 425+21 ( 2 0 4620.2615026492 2 5325.2561770006 ) 55.1234133107 (ExtendedPoll) + 425+24 ( 2 0 4630.7430712937 2 5354.9539548267 ) 54.7064652424 (ExtendedPoll) + 425+27 ( 2 0 4621.4625157231 2 5367.5100005988 ) 54.6438867561 (ExtendedPoll) + 425+28 ( 2 0 4593.6208490110 2 5405.1781379151 ) 54.4600465872 (ExtendedPoll) + 425+29 ( 2 0 4549.9476463255 2 5448.8513406007 ) 54.3496410161 (ExtendedPoll) + 425+30 ( 2 0 4418.9280382689 2 5579.8709486573 ) 54.0763891883 (ExtendedPoll) + 425+31 ( 2 0 3894.8496060423 2 6103.9493808838 ) 53.9197049939 (ExtendedPoll) + 425+44 ( 2 0 3903.2294018076 2 6096.7705981924 ) 53.8996693169 (ExtendedPoll) + 425+51 ( 2 0 3903.5746504167 2 6096.4253495832 ) 53.8992666551 (ExtendedPoll) + 425+52 ( 2 0 3904.6103962441 2 6095.3896037559 ) 53.8980629375 (ExtendedPoll) + 425+53 ( 2 0 3908.7533795536 2 6091.2466204464 ) 53.8933120622 (ExtendedPoll) + 425+54 ( 2 0 3925.3253127913 2 6074.6746872087 ) 53.8753312613 (ExtendedPoll) + 425+55 ( 2 0 3991.6130457425 2 6008.3869542575 ) 53.8196897705 (ExtendedPoll) + 525+3 ( 2 0 4720.4915028125 2 5223.6067977500 ) 55.4583179735 (ExtendedPoll) + 525+4 ( 2 0 4385.0813061876 2 5559.0169943749 ) 54.5837536207 (ExtendedPoll) + 525+15 ( 2 0 4367.6120251133 2 5584.7841839594 ) 54.4682528290 (ExtendedPoll) + 525+16 ( 2 0 4315.2041818907 2 5662.0857527128 ) 54.1388753912 (ExtendedPoll) + 525+18 ( 2 0 4283.7594759571 2 5716.2405240429 ) 53.8770977719 (ExtendedPoll) + 566+16 ( 2 0 3661.9622527217 2 6337.4508886172 ) 54.3613643939 (ExtendedPoll) + 566+17 ( 2 0 3672.7713703864 2 6324.8811949693 ) 54.3464807033 (ExtendedPoll) + 566+18 ( 2 0 3716.0078410450 2 6274.6024203776 ) 54.2957519362 (ExtendedPoll) + 566+19 ( 2 0 3888.9537236798 2 6073.4873220106 ) 54.2325516547 (ExtendedPoll) + 566+23 ( 2 0 3910.7903250226 2 6051.2139886410 ) 54.2135842543 (ExtendedPoll) + 566+24 ( 2 0 3976.3001290509 2 5984.3939885321 ) 54.1740869612 (ExtendedPoll) + 566+28 ( 2 0 4033.9487565958 2 5959.9369950282 ) 53.8521950489 (ExtendedPoll) + 566+34 ( 2 0 4047.3782664216 2 5951.9666355381 ) 53.7987546224 (ExtendedPoll) + 566+46 ( 2 0 4047.6136123118 2 5951.9017281599 ) 53.7971533414 (ExtendedPoll) + 566+50 ( 2 0 4047.8134790560 2 5952.0419387593 ) 53.7940433602 (ExtendedPoll) + 566+52 ( 2 0 4047.6531698269 2 5952.2260518031 ) 53.7938806683 (ExtendedPoll) + 566+53 ( 2 0 4047.1722421396 2 5952.7783909345 ) 53.7933936767 (ExtendedPoll) + 566+59 ( 2 0 4047.2240480902 2 5952.7461205054 ) 53.7932021747 (ExtendedPoll) + 566+64 ( 2 0 4047.2545309008 2 5952.7446673365 ) 53.7929324376 (ExtendedPoll) + 638+17 ( 2 0 4999.9134679357 2 5000.0860989042 ) 55.9013177479 (ExtendedPoll) + 638+18 ( 2 0 4999.6538717426 2 5000.3443956169 ) 55.9001728626 (ExtendedPoll) + 638+19 ( 2 0 4998.6154869705 2 5001.3775824675 ) 55.8955960762 (ExtendedPoll) + 638+20 ( 2 0 4994.4619478821 2 5005.5103298701 ) 55.8773330446 (ExtendedPoll) + 638+21 ( 2 0 4977.8477915284 2 5022.0413194804 ) 55.8049893023 (ExtendedPoll) + 638+22 ( 2 0 4911.3911661138 2 5088.1652779214 ) 55.5271121019 (ExtendedPoll) + 638+23 ( 2 0 4645.5646644551 2 5352.6611116858 ) 54.6099568042 (ExtendedPoll) + 638+29 ( 2 0 4643.1899340591 2 5355.7660034392 ) 54.5949958366 (ExtendedPoll) + 638+37 ( 2 0 4643.2514561244 2 5356.2503964074 ) 54.5891116760 (ExtendedPoll) + 638+39 ( 2 0 4642.9300912980 2 5356.6179294388 ) 54.5876751049 (ExtendedPoll) + 638+40 ( 2 0 4641.9659968188 2 5357.7205285330 ) 54.5833690042 (ExtendedPoll) + 638+41 ( 2 0 4640.6472708158 2 5359.1620854185 ) 54.5782267385 (ExtendedPoll) + 638+46 ( 2 0 4639.9154034740 2 5359.8086535364 ) 54.5770790094 (ExtendedPoll) + 638+47 ( 2 0 4637.7198014483 2 5361.7483578901 ) 54.5736490458 (ExtendedPoll) + 638+48 ( 2 0 4628.9373933458 2 5369.5071753047 ) 54.5601278395 (ExtendedPoll) + 638+49 ( 2 0 4593.8077609356 2 5400.5424449631 ) 54.5092397286 (ExtendedPoll) + 638+50 ( 2 0 4453.2892312949 2 5524.6835235967 ) 54.3579916958 (ExtendedPoll) + 638+55 ( 2 0 4453.1800482882 2 5540.2966935568 ) 54.1950044054 (ExtendedPoll) + 638+59 ( 2 0 4449.7953750800 2 5547.3389974899 ) 54.1501982295 (ExtendedPoll) + 638+63 ( 2 0 4458.8302688856 2 5540.9790873488 ) 54.1396632915 (ExtendedPoll) + 638+73 ( 2 0 4458.3987614362 2 5541.5182850685 ) 54.1376935988 (ExtendedPoll) + 638+86 ( 2 0 4458.4198350926 2 5541.5559487575 ) 54.1371193459 (ExtendedPoll) + 638+88 ( 2 0 4458.4486331602 2 5541.5458498792 ) 54.1369795760 (ExtendedPoll) + 638+95 ( 2 0 4458.4524474032 2 5541.5457910551 ) 54.1369476680 (ExtendedPoll) + 738+11 ( 2 0 4695.1610452549 2 5241.9495428779 ) 55.4530370223 (ExtendedPoll) + 738+12 ( 2 0 4619.1696725821 2 5296.9777782617 ) 55.4492782592 (ExtendedPoll) + 738+15 ( 2 0 4772.8993460352 2 5199.1498042461 ) 55.3189871998 (ExtendedPoll) + 738+21 ( 2 0 4803.9073199419 2 5194.3457519507 ) 55.1267190068 (ExtendedPoll) + 738+24 ( 2 0 4779.8870584649 2 5214.4354251860 ) 55.0861821831 (ExtendedPoll) + 738+25 ( 2 0 4707.8262740337 2 5274.7044448921 ) 54.9771582390 (ExtendedPoll) + 738+26 ( 2 0 4419.5831363091 2 5515.7805237163 ) 54.7394753219 (ExtendedPoll) + 738+28 ( 2 0 4251.8780379967 2 5711.4364717475 ) 54.2065798938 (ExtendedPoll) + 738+29 ( 2 0 3916.4678413717 2 6046.8466683725 ) 54.1969206166 (ExtendedPoll) + 738+38 ( 2 0 3947.9125473053 2 6047.2834003993 ) 53.8946625323 (ExtendedPoll) + 738+43 ( 2 0 3960.2502270639 2 6037.7844788152 ) 53.8597225819 (ExtendedPoll) + 738+52 ( 2 0 3961.1262500944 2 6037.3528647418 ) 53.8551714185 (ExtendedPoll) + 738+53 ( 2 0 3963.7543191857 2 6036.0580225215 ) 53.8415309007 (ExtendedPoll) + 738+63 ( 2 0 3963.8724386189 2 6036.0888168742 ) 53.8401500357 (ExtendedPoll) + 738+69 ( 2 0 3963.8977126790 2 6036.0717128804 ) 53.8400591085 (ExtendedPoll) + 738+70 ( 2 0 3963.9735348593 2 6036.0204008990 ) 53.8397863412 (ExtendedPoll) + 738+71 ( 2 0 3964.0565483307 2 6035.9309033538 ) 53.8397753773 (ExtendedPoll) + 738+72 ( 2 0 3964.3055887447 2 6035.6624107183 ) 53.8397427557 (ExtendedPoll) + 738+73 ( 2 0 3965.3017504010 2 6034.5884401761 ) 53.8396163244 (ExtendedPoll) + 738+74 ( 2 0 3969.2863970259 2 6030.2925580077 ) 53.8391754528 (ExtendedPoll) + 738+75 ( 2 0 3985.2249835255 2 6013.1090293339 ) 53.8384482501 (ExtendedPoll) + 738+78 ( 2 0 3987.0145612449 2 6012.3276884421 ) 53.8284510125 (ExtendedPoll) + 738+83 ( 2 0 3987.3798551717 2 6012.0036580149 ) 53.8278471786 (ExtendedPoll) + 738+84 ( 2 0 3988.4757369520 2 6011.0315667334 ) 53.8260397128 (ExtendedPoll) + 738+86 ( 2 0 3986.7339267980 2 6013.1742832402 ) 53.8237018301 (ExtendedPoll) + 738+95 ( 2 0 3986.6783090383 2 6013.2829464548 ) 53.8232765676 (ExtendedPoll) + 738+99 ( 2 0 3986.8030524894 2 6013.1636141732 ) 53.8231454979 (ExtendedPoll) + 738+100 ( 2 0 3987.1772828427 2 6012.8056173285 ) 53.8227528066 (ExtendedPoll) + 738+110 ( 2 0 3987.1736824074 2 6012.8204452533 ) 53.8226572738 (ExtendedPoll) + 738+112 ( 2 0 3987.1869497063 2 6012.8129081631 ) 53.8225983976 (ExtendedPoll) + 738+113 ( 2 0 3987.2077526376 2 6012.7905795918 ) 53.8225977726 (ExtendedPoll) + 738+114 ( 2 0 3987.2701614317 2 6012.7235938779 ) 53.8225959146 (ExtendedPoll) + 738+115 ( 2 0 3987.5197966079 2 6012.4556510226 ) 53.8225887344 (ExtendedPoll) + 738+116 ( 2 0 3988.5183373128 2 6011.3838796011 ) 53.8225640459 (ExtendedPoll) + 738+117 ( 2 0 3992.5125001324 2 6007.0967939151 ) 53.8225297822 (ExtendedPoll) + 738+121 ( 2 0 3992.8719297375 2 6006.7662594221 ) 53.8220484338 (ExtendedPoll) + 738+122 ( 2 0 3993.9502185528 2 6005.7746559431 ) 53.8206084721 (ExtendedPoll) + 738+130 ( 2 0 3994.1935345893 2 6005.7947812288 ) 53.8181500804 (ExtendedPoll) + 738+138 ( 2 0 3994.2169631374 2 6005.7752257153 ) 53.8181014599 (ExtendedPoll) + 738+143 ( 2 0 3994.2052365766 2 6005.7933405549 ) 53.8180529267 (ExtendedPoll) + 738+149 ( 2 0 3994.2070325934 2 6005.7926984484 ) 53.8180416998 (ExtendedPoll) + 892+10 ( 2 0 4983.7317319996 2 5014.9580719198 ) 55.8453986667 (ExtendedPoll) + 892+11 ( 2 0 4934.9269279985 2 5059.8322876792 ) 55.6824111014 (ExtendedPoll) + 892+12 ( 2 0 4739.7077119942 2 5239.3291507168 ) 55.1228042284 (ExtendedPoll) + 892+13 ( 2 0 3958.8308479767 2 5957.3166028671 ) 54.5781023915 (ExtendedPoll) + 892+20 ( 2 0 3979.7939852657 2 6016.7121585194 ) 53.8581095439 (ExtendedPoll) + 892+27 ( 2 0 3988.6378088095 2 6010.1065866132 ) 53.8325947095 (ExtendedPoll) + 892+35 ( 2 0 3989.5633053899 2 6010.4187817731 ) 53.8211783096 (ExtendedPoll) + 892+45 ( 2 0 3989.5756322315 2 6010.4097884943 ) 53.8211411134 (ExtendedPoll) + 892+46 ( 2 0 3989.6126127563 2 6010.3828086579 ) 53.8210295286 (ExtendedPoll) + 892+51 ( 2 0 3989.6241534539 2 6010.3728265038 ) 53.8210083518 (ExtendedPoll) + 892+55 ( 2 0 3989.6276603588 2 6010.3713253267 ) 53.8209885364 (ExtendedPoll) + 957+13 ( 2 0 3659.6318779221 2 6340.1599919713 ) 54.3646950351 (ExtendedPoll) + 957+14 ( 2 0 3663.4498711882 2 6335.7176083856 ) 54.3592886738 (ExtendedPoll) + 957+15 ( 2 0 3678.7218442523 2 6317.9480740430 ) 54.3387643534 (ExtendedPoll) + 957+16 ( 2 0 3739.8097365087 2 6246.8699366722 ) 54.2742427310 (ExtendedPoll) + 957+22 ( 2 0 3747.2068852135 2 6244.3587275178 ) 54.2206960776 (ExtendedPoll) + 957+24 ( 2 0 3733.7773753877 2 6261.9371915988 ) 54.2169921066 (ExtendedPoll) + 957+28 ( 2 0 3729.6284211326 2 6268.5700592566 ) 54.2069023761 (ExtendedPoll) + 957+39 ( 2 0 3729.8079759991 2 6269.9395382979 ) 54.1945664870 (ExtendedPoll) + 957+46 ( 2 0 3730.0391102401 2 6269.8609297318 ) 54.1928795948 (ExtendedPoll) + 957+47 ( 2 0 3730.4171990505 2 6269.5520399169 ) 54.1915098832 (ExtendedPoll) + 957+54 ( 2 0 3730.5280413937 2 6269.4196928396 ) 54.1914305422 (ExtendedPoll) + 957+55 ( 2 0 3730.8605684232 2 6269.0226516079 ) 54.1911930941 (ExtendedPoll) + 957+56 ( 2 0 3732.1906765414 2 6267.4344866812 ) 54.1902519228 (ExtendedPoll) + 957+57 ( 2 0 3737.5111090140 2 6261.0818269741 ) 54.1866251399 (ExtendedPoll) + 957+58 ( 2 0 3758.7928389047 2 6235.6711881460 ) 54.1743221404 (ExtendedPoll) + 957+59 ( 2 0 3843.9197584675 2 6134.0286328333 ) 54.1602124163 (ExtendedPoll) + 957+61 ( 2 0 3850.7164006354 2 6130.1799318466 ) 54.1262487754 (ExtendedPoll) + 957+62 ( 2 0 3871.1063271392 2 6118.6338288866 ) 54.0252546165 (ExtendedPoll) + 957+68 ( 2 0 3874.9618520638 2 6118.0196744739 ) 53.9932699228 (ExtendedPoll) + 957+71 ( 2 0 3878.5580673474 2 6116.4979363178 ) 53.9713481391 (ExtendedPoll) + 957+74 ( 2 0 3882.4477119616 2 6116.1772112356 ) 53.9366512244 (ExtendedPoll) + 957+77 ( 2 0 3883.8176174990 2 6114.7851279000 ) 53.9350795566 (ExtendedPoll) + 957+78 ( 2 0 3887.9273341111 2 6110.6088778932 ) 53.9304333927 (ExtendedPoll) + 957+79 ( 2 0 3904.3662005594 2 6093.9038778659 ) 53.9128801378 (ExtendedPoll) + 957+80 ( 2 0 3970.1216663528 2 6027.0838777571 ) 53.8590909037 (ExtendedPoll) + 957+86 ( 2 0 3973.0218399687 2 6024.4703095339 ) 53.8544261587 (ExtendedPoll) + 957+87 ( 2 0 3981.7223608162 2 6016.6296048642 ) 53.8406919834 (ExtendedPoll) + 957+92 ( 2 0 3984.9637313280 2 6014.4459447299 ) 53.8292462452 (ExtendedPoll) + 957+97 ( 2 0 3985.8052081727 2 6013.9503562385 ) 53.8256595333 (ExtendedPoll) + 957+105 ( 2 0 3985.8396877184 2 6014.0674560795 ) 53.8243145748 (ExtendedPoll) + 957+108 ( 2 0 3985.9527091902 2 6014.0213411865 ) 53.8236546852 (ExtendedPoll) + 957+113 ( 2 0 3986.0162471161 2 6013.9629145501 ) 53.8235671131 (ExtendedPoll) + 957+114 ( 2 0 3986.2068608937 2 6013.7876346407 ) 53.8233045248 (ExtendedPoll) + 957+120 ( 2 0 3986.1976307305 2 6013.7997850945 ) 53.8232852967 (ExtendedPoll) + 957+126 ( 2 0 3986.2011589420 2 6013.7983347110 ) 53.8232647945 (ExtendedPoll) + 957+130 ( 2 0 3986.1999003828 2 6013.7997678928 ) 53.8232641222 (ExtendedPoll) + 957+133 ( 2 0 3986.1980746415 2 6013.8017534985 ) 53.8232639619 (ExtendedPoll) + 1130+15 ( 2 0 4999.7419965034 2 5000.2294282565 ) 55.9008939292 (ExtendedPoll) + 1130+16 ( 2 0 4998.9679860137 2 5000.9177130262 ) 55.8984788107 (ExtendedPoll) + 1130+17 ( 2 0 4995.8719440548 2 5003.6708521046 ) 55.8888394453 (ExtendedPoll) + 1130+18 ( 2 0 4983.4877762190 2 5014.6834084185 ) 55.8506205863 (ExtendedPoll) + 1130+19 ( 2 0 4933.9511048760 2 5058.7336336741 ) 55.7032178511 (ExtendedPoll) + 1130+20 ( 2 0 4735.8044195041 2 5234.9345346965 ) 55.2046851896 (ExtendedPoll) + 1130+21 ( 2 0 3943.2176780166 2 5939.7381387862 ) 54.8819022435 (ExtendedPoll) + 1130+23 ( 2 0 3935.3565015332 2 5969.8726486392 ) 54.6880709245 (ExtendedPoll) + 1130+24 ( 2 0 3911.7729720830 2 6060.2761781983 ) 54.1268308179 (ExtendedPoll) + 1130+30 ( 2 0 3902.3832335056 2 6072.7230409636 ) 54.1106121774 (ExtendedPoll) + 1130+31 ( 2 0 3874.2140177734 2 6110.0636292598 ) 54.0666592435 (ExtendedPoll) + 1130+34 ( 2 0 3854.9978085918 2 6134.5206227637 ) 54.0491056788 (ExtendedPoll) + 1130+41 ( 2 0 3852.6503739474 2 6141.9723629719 ) 54.0104767054 (ExtendedPoll) + 1130+45 ( 2 0 3860.8118036993 2 6134.5206227637 ) 53.9930000229 (ExtendedPoll) + 1130+46 ( 2 0 3885.2960929549 2 6112.1654021390 ) 53.9427035432 (ExtendedPoll) + 1130+54 ( 2 0 3886.8263610334 2 6110.9507411893 ) 53.9381441910 (ExtendedPoll) + 1130+55 ( 2 0 3891.4171652688 2 6107.3067583403 ) 53.9245293625 (ExtendedPoll) + 1130+56 ( 2 0 3897.5041178931 2 6102.3935230381 ) 53.9073073325 (ExtendedPoll) + 1130+66 ( 2 0 3897.7068634861 2 6102.2575240879 ) 53.9065051034 (ExtendedPoll) + 1130+74 ( 2 0 3897.7316573216 2 6102.2397316194 ) 53.9064167304 (ExtendedPoll) + 1130+75 ( 2 0 3897.8060388280 2 6102.1863542139 ) 53.9061516260 (ExtendedPoll) + 1130+81 ( 2 0 3897.8185626742 2 6102.1776373870 ) 53.9061047270 (ExtendedPoll) + 1130+87 ( 2 0 3897.8165360562 2 6102.1808692197 ) 53.9060970673 (ExtendedPoll) + 1130+90 ( 2 0 3897.8201618133 2 6102.1796835545 ) 53.9060722877 (ExtendedPoll) + 1130+103 ( 2 0 3897.8200835182 2 6102.1797734473 ) 53.9060722845 (ExtendedPoll) + 1130+104 ( 2 0 3897.8198486328 2 6102.1800431259 ) 53.9060722750 (ExtendedPoll) + 1241+5 ( 2 0 4966.3716339321 2 5028.8243137725 ) 55.8117570732 (ExtendedPoll) + 1241+6 ( 2 0 4865.4865357285 2 5115.2972550898 ) 55.5653095642 (ExtendedPoll) + 1241+7 ( 2 0 4461.9461429141 2 5461.1890203593 ) 54.9583349271 (ExtendedPoll) + 1241+13 ( 2 0 4468.9338553438 2 5524.0784322265 ) 54.2311656305 (ExtendedPoll) + 1241+14 ( 2 0 4385.0813061876 2 5614.9186938124 ) 54.0080105561 (ExtendedPoll) + 1291+22 ( 2 0 4999.9828435272 2 5000.0130887244 ) 55.9016722791 (ExtendedPoll) + 1291+23 ( 2 0 4999.9313741087 2 5000.0523548977 ) 55.9015908089 (ExtendedPoll) + 1291+24 ( 2 0 4999.7254964348 2 5000.2094195909 ) 55.9012650053 (ExtendedPoll) + 1291+25 ( 2 0 4998.9019857391 2 5000.8376783636 ) 55.8999630243 (ExtendedPoll) + 1291+26 ( 2 0 4995.6079429565 2 5003.3507134546 ) 55.8947748483 (ExtendedPoll) + 1291+27 ( 2 0 4982.4317718259 2 5013.4028538183 ) 55.8743389196 (ExtendedPoll) + 1291+28 ( 2 0 4929.7270873038 2 5053.6114152732 ) 55.7977153969 (ExtendedPoll) + 1291+29 ( 2 0 4718.9083492152 2 5214.4456610929 ) 55.5764644844 (ExtendedPoll) + 1291+32 ( 2 0 4720.0070032202 2 5218.1920030108 ) 55.5244848408 (ExtendedPoll) + 1291+33 ( 2 0 4723.3029652354 2 5229.4310287644 ) 55.3687307229 (ExtendedPoll) + 1291+34 ( 2 0 4734.5488149269 2 5240.3493294358 ) 55.1527367318 (ExtendedPoll) + 1291+35 ( 2 0 4725.8141743898 2 5270.4838392888 ) 54.8793050383 (ExtendedPoll) + 1291+43 ( 2 0 4724.6472810056 2 5274.2097093929 ) 54.8463890957 (ExtendedPoll) + 1291+48 ( 2 0 4723.8706315711 2 5274.8016860074 ) 54.8459531010 (ExtendedPoll) + 1291+49 ( 2 0 4721.5406832677 2 5276.5776158510 ) 54.8446571102 (ExtendedPoll) + 1291+50 ( 2 0 4712.2208900540 2 5283.6813352253 ) 54.8396533297 (ExtendedPoll) + 1291+51 ( 2 0 4674.9417171991 2 5312.0962127226 ) 54.8225390616 (ExtendedPoll) + 1291+52 ( 2 0 4525.8250257796 2 5425.7557227117 ) 54.8016355518 (ExtendedPoll) + 1291+55 ( 2 0 4527.5719538871 2 5456.7636966185 ) 54.4520740351 (ExtendedPoll) + 1291+59 ( 2 0 4517.3087512560 2 5468.5554613436 ) 54.4117744769 (ExtendedPoll) + 1291+60 ( 2 0 4486.5191433627 2 5503.9307555188 ) 54.2947627479 (ExtendedPoll) + 1291+61 ( 2 0 4439.3520844623 2 5545.8570300970 ) 54.2549299012 (ExtendedPoll) + 1291+62 ( 2 0 4297.8509077611 2 5671.6358538313 ) 54.1955288613 (ExtendedPoll) + 1291+64 ( 2 0 4130.1458094486 2 5867.2918018626 ) 53.8101176125 (ExtendedPoll) + 1291+75 ( 2 0 4128.0235647556 2 5870.5672920640 ) 53.7990789831 (ExtendedPoll) + 1291+79 ( 2 0 4127.0989211675 2 5872.2886304042 ) 53.7915583989 (ExtendedPoll) + 1291+85 ( 2 0 4128.1741178860 2 5871.4215637923 ) 53.7897866464 (ExtendedPoll) + 1291+88 ( 2 0 4127.2012802363 2 5872.4020783721 ) 53.7895735461 (ExtendedPoll) + 1291+89 ( 2 0 4124.2827672873 2 5875.3436221116 ) 53.7889669943 (ExtendedPoll) + 1291+90 ( 2 0 4112.6087154913 2 5887.1097970695 ) 53.7870326237 (ExtendedPoll) + 1291+103 ( 2 0 4112.6224699912 2 5887.2310885676 ) 53.7857898087 (ExtendedPoll) + 1291+105 ( 2 0 4112.6068429068 2 5887.3521534897 ) 53.7848179668 (ExtendedPoll) + 1291+111 ( 2 0 4112.6094751875 2 5887.3825571652 ) 53.7845139164 (ExtendedPoll) + 1291+115 ( 2 0 4112.6011895425 2 5887.3953703748 ) 53.7844717434 (ExtendedPoll) + 1291+121 ( 2 0 4112.6098291866 2 5887.3889072301 ) 53.7844522046 (ExtendedPoll) + 1291+126 ( 2 0 4112.6115497632 2 5887.3880840681 ) 53.7844440412 (ExtendedPoll) + 1291+133 ( 2 0 4112.6117769427 2 5887.3881564070 ) 53.7844412964 (ExtendedPoll) + 1291+139 ( 2 0 4112.6117384418 2 5887.3882019087 ) 53.7844412297 (ExtendedPoll) + 1291+140 ( 2 0 4112.6116229393 2 5887.3883384136 ) 53.7844410296 (ExtendedPoll) + 1291+144 ( 2 0 4112.6116767374 2 5887.3883127527 ) 53.7844407736 (ExtendedPoll) + 1291+147 ( 2 0 4112.6116387835 2 5887.3883587115 ) 53.7844406977 (ExtendedPoll) + 1444+2 ( 2 0 4902.1720259844 2 5076.8648367266 ) 55.7342800977 (ExtendedPoll) + 1444+3 ( 2 0 4608.6881039375 2 5307.4593469062 ) 55.4177822439 (ExtendedPoll) + 1444+6 ( 2 0 4440.9830056251 2 5503.1152949375 ) 54.6903788761 (ExtendedPoll) + 1444+9 ( 2 0 4273.2779073126 2 5698.7712429687 ) 54.1421759642 (ExtendedPoll) + 1444+10 ( 2 0 3937.8677106876 2 6034.1814395937 ) 54.1025876908 (ExtendedPoll) + 1444+19 ( 2 0 3985.0347695880 2 5992.2551650155 ) 54.0228541969 (ExtendedPoll) + 1444+20 ( 2 0 4126.5359462891 2 5866.4763412812 ) 53.8506010417 (ExtendedPoll) + 1444+30 ( 2 0 4130.4392387792 2 5866.5172849087 ) 53.8146342551 (ExtendedPoll) + 1444+32 ( 2 0 4128.6854867338 2 5870.0111411235 ) 53.7981997187 (ExtendedPoll) + 1444+38 ( 2 0 4129.0689067457 2 5870.9093419522 ) 53.7863749691 (ExtendedPoll) + 1444+51 ( 2 0 4129.0636273984 2 5870.9236583107 ) 53.7862903829 (ExtendedPoll) + 1444+56 ( 2 0 4129.0651471032 2 5870.9311348262 ) 53.7862072107 (ExtendedPoll) + 1444+60 ( 2 0 4129.0646772976 2 5870.9349204804 ) 53.7861763981 (ExtendedPoll) + 1444+66 ( 2 0 4129.0641711296 2 5870.9357287432 ) 53.7861735204 (ExtendedPoll) + 1444+74 ( 2 0 4129.0643025908 2 5870.9356231986 ) 53.7861733001 (ExtendedPoll) + 1444+77 ( 2 0 4129.0644472731 2 5870.9355366612 ) 53.7861727831 (ExtendedPoll) + 1444+82 ( 2 0 4129.0644281460 2 5870.9355595157 ) 53.7861727456 (ExtendedPoll) + 1444+83 ( 2 0 4129.0643707645 2 5870.9356280794 ) 53.7861726332 (ExtendedPoll) + 1626+2 ( 2 0 4867.2334638359 2 5118.7911113047 ) 55.5101747565 (ExtendedPoll) + 1626+3 ( 2 0 4468.9338553438 2 5475.1644452187 ) 54.7497453707 (ExtendedPoll) + 1626+10 ( 2 0 4531.8232672110 2 5468.1767327890 ) 54.2937328699 (ExtendedPoll) + 1626+12 ( 2 0 4406.0444434766 2 5593.9555565234 ) 54.0419580454 (ExtendedPoll) + 1626+13 ( 2 0 4028.7079722735 2 5971.2920277265 ) 53.7998378556 (ExtendedPoll) + 1626+19 ( 2 0 4154.4867960079 2 5845.5132039921 ) 53.7918826239 (ExtendedPoll) + 1690+27 ( 2 0 4999.9918793150 2 5000.0071042165 ) 55.9016755069 (ExtendedPoll) + 1690+28 ( 2 0 4999.9675172600 2 5000.0284168659 ) 55.9016037165 (ExtendedPoll) + 1690+29 ( 2 0 4999.8700690400 2 5000.1136674635 ) 55.9013165752 (ExtendedPoll) + 1690+30 ( 2 0 4999.4802761598 2 5000.4546698539 ) 55.9001683374 (ExtendedPoll) + 1690+31 ( 2 0 4997.9211046392 2 5001.8186794156 ) 55.8955806263 (ExtendedPoll) + 1690+32 ( 2 0 4991.6844185568 2 5007.2747176624 ) 55.8773137258 (ExtendedPoll) + 1690+33 ( 2 0 4966.7376742271 2 5029.0988706497 ) 55.8055960661 (ExtendedPoll) + 1690+34 ( 2 0 4866.9506969084 2 5116.3954825988 ) 55.5407618647 (ExtendedPoll) + 1690+35 ( 2 0 4467.8027876336 2 5465.5819303951 ) 54.8617064546 (ExtendedPoll) + 1690+37 ( 2 0 4466.8269645111 2 5469.3623920026 ) 54.8295561915 (ExtendedPoll) + 1690+38 ( 2 0 4463.8994951436 2 5480.7037768250 ) 54.7333779337 (ExtendedPoll) + 1690+39 ( 2 0 4452.1896176735 2 5526.0693161146 ) 54.3527873521 (ExtendedPoll) + 1690+40 ( 2 0 4432.0999444382 2 5550.0895775916 ) 54.2727755505 (ExtendedPoll) + 1690+41 ( 2 0 4371.8309247321 2 5622.1503620228 ) 54.0490159101 (ExtendedPoll) + 1690+48 ( 2 0 4367.1633511951 2 5628.4010891571 ) 54.0259049915 (ExtendedPoll) + 1690+52 ( 2 0 4367.4363087119 2 5632.2975577092 ) 53.9839463746 (ExtendedPoll) + 1690+64 ( 2 0 4367.5173563027 2 5632.3888412069 ) 53.9823156833 (ExtendedPoll) + 1690+67 ( 2 0 4367.5750698909 2 5632.4087032645 ) 53.9816128497 (ExtendedPoll) + 1690+77 ( 2 0 4367.5769053809 2 5632.4193356014 ) 53.9814889495 (ExtendedPoll) + 1690+82 ( 2 0 4367.5805624212 2 5632.4182502476 ) 53.9814682147 (ExtendedPoll) + 1690+86 ( 2 0 4367.5821046999 2 5632.4171280385 ) 53.9814662175 (ExtendedPoll) + 1690+90 ( 2 0 4367.5818878523 2 5632.4180567321 ) 53.9814586704 (ExtendedPoll) + 1690+104 ( 2 0 4367.5819056985 2 5632.4180679393 ) 53.9814584017 (ExtendedPoll) + 1690+105 ( 2 0 4367.5819346476 2 5632.4180608593 ) 53.9814582222 (ExtendedPoll) + 1690+109 ( 2 0 4367.5819216978 2 5632.4180774844 ) 53.9814581658 (ExtendedPoll) + 1690+115 ( 2 0 4367.5819257648 2 5632.4180741356 ) 53.9814581645 (ExtendedPoll) + 1690+120 ( 2 0 4367.5819244247 2 5632.4180754292 ) 53.9814581630 (ExtendedPoll) + 1690+121 ( 2 0 4367.5819204043 2 5632.4180793101 ) 53.9814581585 (ExtendedPoll) + 1690+122 ( 2 0 4367.5819043228 2 5632.4180948339 ) 53.9814581405 (ExtendedPoll) + 1690+123 ( 2 0 4367.5818399969 2 5632.4181569287 ) 53.9814580686 (ExtendedPoll) + 1690+124 ( 2 0 4367.5815826929 2 5632.4184053083 ) 53.9814577808 (ExtendedPoll) + 1690+125 ( 2 0 4367.5805534773 2 5632.4193988263 ) 53.9814566296 (ExtendedPoll) + 1690+126 ( 2 0 4367.5764366146 2 5632.4233728987 ) 53.9814520249 (ExtendedPoll) + 1690+127 ( 2 0 4367.5599691638 2 5632.4392691879 ) 53.9814336068 (ExtendedPoll) + 1690+128 ( 2 0 4367.4940993607 2 5632.5028543451 ) 53.9813599484 (ExtendedPoll) + 1690+129 ( 2 0 4367.2306201483 2 5632.7571949737 ) 53.9810655359 (ExtendedPoll) + 1690+130 ( 2 0 4366.1767032985 2 5633.7745574881 ) 53.9798914222 (ExtendedPoll) + 1690+131 ( 2 0 4361.9610358996 2 5637.8440075457 ) 53.9752515834 (ExtendedPoll) + 1690+132 ( 2 0 4345.0983663039 2 5654.1218077760 ) 53.9576001475 (ExtendedPoll) + 1690+133 ( 2 0 4277.6476879210 2 5719.2330086971 ) 53.9016513465 (ExtendedPoll) + 1690+135 ( 2 0 4277.6290591203 2 5719.2571811144 ) 53.9015782727 (ExtendedPoll) + 1690+136 ( 2 0 4277.5731727181 2 5719.3296983663 ) 53.9013590679 (ExtendedPoll) + 1690+137 ( 2 0 4277.3496271092 2 5719.6197673739 ) 53.9004824970 (ExtendedPoll) + 1690+138 ( 2 0 4276.4554446736 2 5720.7800434043 ) 53.8969801836 (ExtendedPoll) + 1690+139 ( 2 0 4272.8787149315 2 5725.4211475259 ) 53.8830344924 (ExtendedPoll) + 1690+140 ( 2 0 4272.2449416972 2 5726.1641037669 ) 53.8813532804 (ExtendedPoll) + 1690+141 ( 2 0 4270.3436219944 2 5728.3929724899 ) 53.8763261624 (ExtendedPoll) + 1690+145 ( 2 0 4269.8544309447 2 5729.2382877997 ) 53.8723721175 (ExtendedPoll) + 1690+146 ( 2 0 4268.9604950773 2 5730.9749800002 ) 53.8632736922 (ExtendedPoll) + 1690+157 ( 2 0 4268.9281879962 2 5731.0267642928 ) 53.8630526551 (ExtendedPoll) + 1690+162 ( 2 0 4268.9081672520 2 5731.0497967493 ) 53.8630044126 (ExtendedPoll) + 1690+163 ( 2 0 4268.8481050197 2 5731.1188941187 ) 53.8628597009 (ExtendedPoll) + 1690+167 ( 2 0 4268.9130457179 2 5731.0620335227 ) 53.8628413313 (ExtendedPoll) + 1690+168 ( 2 0 4269.1078678127 2 5730.8914517347 ) 53.8627863397 (ExtendedPoll) + 1690+172 ( 2 0 4268.9798523367 2 5731.0072720873 ) 53.8627858887 (ExtendedPoll) + 1690+173 ( 2 0 4268.5958059087 2 5731.3547331451 ) 53.8627850104 (ExtendedPoll) + 1690+182 ( 2 0 4268.5734598444 2 5731.3755169174 ) 53.8627794333 (ExtendedPoll) + 1690+183 ( 2 0 4268.5064216515 2 5731.4378682344 ) 53.8627627170 (ExtendedPoll) + 1690+184 ( 2 0 4268.2382688801 2 5731.6872735026 ) 53.8626960762 (ExtendedPoll) + 1690+185 ( 2 0 4267.1656577944 2 5732.6848945752 ) 53.8624331084 (ExtendedPoll) + 1690+186 ( 2 0 4262.8752134514 2 5736.6753788658 ) 53.8614387941 (ExtendedPoll) + 1690+187 ( 2 0 4245.7134360797 2 5752.6373160280 ) 53.8583843412 (ExtendedPoll) + 1690+190 ( 2 0 4247.8459166796 2 5750.8801520137 ) 53.8564841075 (ExtendedPoll) + 1690+191 ( 2 0 4254.2433584792 2 5745.6086599708 ) 53.8509013362 (ExtendedPoll) + 1690+203 ( 2 0 4254.3648432334 2 5745.5967180794 ) 53.8499381914 (ExtendedPoll) + 1690+208 ( 2 0 4254.3884937761 2 5745.5774316250 ) 53.8499159225 (ExtendedPoll) + 1690+209 ( 2 0 4254.4594454040 2 5745.5195722617 ) 53.8498491302 (ExtendedPoll) + 1690+216 ( 2 0 4254.4747041982 2 5745.5195660142 ) 53.8497136099 (ExtendedPoll) + 1690+222 ( 2 0 4254.4785171266 2 5745.5196821982 ) 53.8496785985 (ExtendedPoll) + 1690+225 ( 2 0 4254.4745684192 2 5745.5233580070 ) 53.8496778754 (ExtendedPoll) + 1690+226 ( 2 0 4254.4627222968 2 5745.5343854333 ) 53.8496757065 (ExtendedPoll) + 1690+227 ( 2 0 4254.4153378073 2 5745.5784951385 ) 53.8496670379 (ExtendedPoll) + 1690+228 ( 2 0 4254.2257998495 2 5745.7549339594 ) 53.8496324765 (ExtendedPoll) + 1690+229 ( 2 0 4253.4676480183 2 5746.4606892429 ) 53.8494960362 (ExtendedPoll) + 1690+230 ( 2 0 4250.4350406932 2 5749.2837103771 ) 53.8489791731 (ExtendedPoll) + 1690+231 ( 2 0 4238.3046113928 2 5760.5757949136 ) 53.8473747522 (ExtendedPoll) + 1690+233 ( 2 0 4237.9514726055 2 5760.9129400964 ) 53.8472576934 (ExtendedPoll) + 1690+234 ( 2 0 4236.8920562434 2 5761.9243756450 ) 53.8469104201 (ExtendedPoll) + 1690+235 ( 2 0 4232.6543907954 2 5765.9701178391 ) 53.8455799016 (ExtendedPoll) + 1690+236 ( 2 0 4215.7037290030 2 5782.1530866154 ) 53.8411968855 (ExtendedPoll) + 1690+237 ( 2 0 4147.9010818337 2 5846.8849617209 ) 53.8388064213 (ExtendedPoll) + 1690+239 ( 2 0 4139.4939903168 2 5859.9869225266 ) 53.7929039460 (ExtendedPoll) + 1690+243 ( 2 0 4134.1713187395 2 5865.6917346274 ) 53.7882968215 (ExtendedPoll) + 1690+250 ( 2 0 4133.4948958932 2 5866.3963062176 ) 53.7879136446 (ExtendedPoll) + 1690+251 ( 2 0 4131.4656273543 2 5868.5100209882 ) 53.7867806418 (ExtendedPoll) + 1690+261 ( 2 0 4131.5933562783 2 5868.3938874275 ) 53.7866942837 (ExtendedPoll) + 1690+270 ( 2 0 4131.5998202039 2 5868.3898345950 ) 53.7866729850 (ExtendedPoll) + 1690+271 ( 2 0 4131.6192119808 2 5868.3776760976 ) 53.7866090899 (ExtendedPoll) + 1690+279 ( 2 0 4131.6209541211 2 5868.3784525807 ) 53.7865860060 (ExtendedPoll) + 1690+284 ( 2 0 4131.6214166274 2 5868.3783365570 ) 53.7865828676 (ExtendedPoll) + 1690+287 ( 2 0 4131.6210066099 2 5868.3788719382 ) 53.7865816357 (ExtendedPoll) + 1690+293 ( 2 0 4131.6209362583 2 5868.3789681750 ) 53.7865813838 (ExtendedPoll) + 1690+294 ( 2 0 4131.6207252036 2 5868.3792568852 ) 53.7865806279 (ExtendedPoll) + 1690+298 ( 2 0 4131.6206891940 2 5868.3793043828 ) 53.7865805153 (ExtendedPoll) + 1690+304 ( 2 0 4131.6206796375 2 5868.3793158160 ) 53.7865804962 (ExtendedPoll) + 1690+308 ( 2 0 4131.6206768768 2 5868.3793227362 ) 53.7865804572 (ExtendedPoll) + 1690+313 ( 2 0 4131.6206782642 2 5868.3793214934 ) 53.7865804561 (ExtendedPoll) + 1690+315 ( 2 0 4131.6206745081 2 5868.3793251876 ) 53.7865804560 (ExtendedPoll) + 1690+316 ( 2 0 4131.6206632396 2 5868.3793362702 ) 53.7865804559 (ExtendedPoll) + 1690+317 ( 2 0 4131.6206181660 2 5868.3793806004 ) 53.7865804552 (ExtendedPoll) + 1690+318 ( 2 0 4131.6204378713 2 5868.3795579212 ) 53.7865804528 (ExtendedPoll) + 1690+319 ( 2 0 4131.6197166927 2 5868.3802672046 ) 53.7865804428 (ExtendedPoll) + 1690+320 ( 2 0 4131.6168319783 2 5868.3831043383 ) 53.7865804032 (ExtendedPoll) + 1690+321 ( 2 0 4131.6052931206 2 5868.3944528729 ) 53.7865802452 (ExtendedPoll) + 1690+322 ( 2 0 4131.5591376898 2 5868.4398470112 ) 53.7865796204 (ExtendedPoll) + 1690+323 ( 2 0 4131.3745159668 2 5868.6214235646 ) 53.7865772402 (ExtendedPoll) + 1690+324 ( 2 0 4130.6360290747 2 5869.3477297782 ) 53.7865696199 (ExtendedPoll) + 1690+325 ( 2 0 4127.6820815062 2 5872.2529546326 ) 53.7865695587 (ExtendedPoll) + 1690+328 ( 2 0 4127.6840140147 2 5872.2603352230 ) 53.7864835442 (ExtendedPoll) + 1690+329 ( 2 0 4127.6898115401 2 5872.2824769939 ) 53.7862255016 (ExtendedPoll) + 1690+330 ( 2 0 4127.6796235307 2 5872.3112438240 ) 53.7860518834 (ExtendedPoll) + 1690+338 ( 2 0 4127.6784943469 2 5872.3148875688 ) 53.7860284213 (ExtendedPoll) + 1690+339 ( 2 0 4127.6750287014 2 5872.3216844082 ) 53.7859970553 (ExtendedPoll) + 1690+345 ( 2 0 4127.6738721701 2 5872.3232011194 ) 53.7859935510 (ExtendedPoll) + 1690+346 ( 2 0 4127.6704025761 2 5872.3277512530 ) 53.7859830384 (ExtendedPoll) + 1690+352 ( 2 0 4127.6704920471 2 5872.3287007212 ) 53.7859734249 (ExtendedPoll) + 1690+357 ( 2 0 4127.6702519860 2 5872.3291127215 ) 53.7859717972 (ExtendedPoll) + 1690+358 ( 2 0 4127.6695318024 2 5872.3303487226 ) 53.7859669139 (ExtendedPoll) + 1690+364 ( 2 0 4127.6693723329 2 5872.3305259594 ) 53.7859667262 (ExtendedPoll) + 1690+365 ( 2 0 4127.6688939242 2 5872.3310576698 ) 53.7859661633 (ExtendedPoll) + 1690+372 ( 2 0 4127.6688751072 2 5872.3311142263 ) 53.7859658109 (ExtendedPoll) + 1690+374 ( 2 0 4127.6689990935 2 5872.3309999936 ) 53.7859657384 (ExtendedPoll) + 1690+382 ( 2 0 4127.6690021165 2 5872.3309978166 ) 53.7859657310 (ExtendedPoll) + 2080+20 ( 2 0 4999.9878997345 2 5000.0092959702 ) 55.9016794952 (ExtendedPoll) + 2080+21 ( 2 0 4999.9515989379 2 5000.0371838810 ) 55.9016196708 (ExtendedPoll) + 2080+22 ( 2 0 4999.8063957515 2 5000.1487355238 ) 55.9013804121 (ExtendedPoll) + 2080+23 ( 2 0 4999.2255830062 2 5000.5949420954 ) 55.9004239959 (ExtendedPoll) + 2080+24 ( 2 0 4996.9023320246 2 5002.3797683814 ) 55.8966082342 (ExtendedPoll) + 2080+25 ( 2 0 4987.6093280984 2 5009.5190735258 ) 55.8815039246 (ExtendedPoll) + 2080+26 ( 2 0 4950.4373123937 2 5038.0762941031 ) 55.8236448341 (ExtendedPoll) + 2080+27 ( 2 0 4801.7492495748 2 5152.3051764124 ) 55.6343152023 (ExtendedPoll) + 2080+28 ( 2 0 4206.9969982993 2 5609.2207056496 ) 55.6253373563 (ExtendedPoll) + 2080+32 ( 2 0 4217.9971862258 2 5610.1214654550 ) 55.5187948731 (ExtendedPoll) + 2080+33 ( 2 0 4250.9977500050 2 5612.8237448711 ) 55.2000072940 (ExtendedPoll) + 2080+34 ( 2 0 4279.8220637775 2 5600.5952481192 ) 55.0710067569 (ExtendedPoll) + 2080+35 ( 2 0 4366.2950050949 2 5563.9097578633 ) 54.6951789859 (ExtendedPoll) + 2080+39 ( 2 0 4393.3723907599 2 5548.1874048965 ) 54.6249740689 (ExtendedPoll) + 2080+40 ( 2 0 4474.6045477550 2 5501.0203459961 ) 54.4266469861 (ExtendedPoll) + 2080+42 ( 2 0 4525.2654628702 2 5464.3348557403 ) 54.3900963042 (ExtendedPoll) + 2080+48 ( 2 0 4514.4563452056 2 5483.6602479286 ) 54.2742359116 (ExtendedPoll) + 2080+49 ( 2 0 4491.7462798091 2 5505.0601172445 ) 54.2385084897 (ExtendedPoll) + 2080+50 ( 2 0 4423.6160836196 2 5569.2597251923 ) 54.1460338788 (ExtendedPoll) + 2080+51 ( 2 0 4151.0952988618 2 5826.0581569833 ) 54.0054730693 (ExtendedPoll) + 2080+57 ( 2 0 4119.6505929283 2 5880.2129283134 ) 53.7862527117 (ExtendedPoll) + 2080+75 ( 2 0 4119.5665931846 2 5880.3014995623 ) 53.7862021958 (ExtendedPoll) + 2080+76 ( 2 0 4119.3145939537 2 5880.5672133090 ) 53.7860509080 (ExtendedPoll) + 2080+77 ( 2 0 4118.3065970302 2 5881.6300682960 ) 53.7854496575 (ExtendedPoll) + 2080+88 ( 2 0 4118.3108711544 2 5881.6602849630 ) 53.7851316932 (ExtendedPoll) + 2080+96 ( 2 0 4118.3198847115 2 5881.6662155602 ) 53.7849945777 (ExtendedPoll) + 2080+97 ( 2 0 4118.3348277986 2 5881.6631276284 ) 53.7848865134 (ExtendedPoll) + 2080+99 ( 2 0 4118.3462668702 2 5881.6530292707 ) 53.7848751796 (ExtendedPoll) + 2080+108 ( 2 0 4118.3455932557 2 5881.6537043543 ) 53.7848751047 (ExtendedPoll) + 2080+109 ( 2 0 4118.3435724122 2 5881.6557296052 ) 53.7848748801 (ExtendedPoll) + 2080+110 ( 2 0 4118.3354890381 2 5881.6638306090 ) 53.7848739818 (ExtendedPoll) + 2080+111 ( 2 0 4118.3031555418 2 5881.6962346240 ) 53.7848703922 (ExtendedPoll) + 2080+112 ( 2 0 4118.1738215565 2 5881.8258506839 ) 53.7848560937 (ExtendedPoll) + 2080+122 ( 2 0 4118.1735085463 2 5881.8262104036 ) 53.7848556344 (ExtendedPoll) + 2080+123 ( 2 0 4118.1725695157 2 5881.8272895629 ) 53.7848542566 (ExtendedPoll) + 2080+132 ( 2 0 4118.1726545887 2 5881.8272060557 ) 53.7848542498 (ExtendedPoll) + 2080+133 ( 2 0 4118.1729098077 2 5881.8269555344 ) 53.7848542294 (ExtendedPoll) + 2080+134 ( 2 0 4118.1739306837 2 5881.8259534489 ) 53.7848541479 (ExtendedPoll) + 2080+135 ( 2 0 4118.1780141879 2 5881.8219451070 ) 53.7848538220 (ExtendedPoll) + 2080+151 ( 2 0 4118.1780093963 2 5881.8219592167 ) 53.7848537356 (ExtendedPoll) + 2080+152 ( 2 0 4118.1779950216 2 5881.8220015460 ) 53.7848534763 (ExtendedPoll) + 2080+159 ( 2 0 4118.1779947385 2 5881.8220052606 ) 53.7848534446 (ExtendedPoll) + 2251+6 ( 2 0 4168.4622208673 2 5740.6975175468 ) 54.6654457702 (ExtendedPoll) + 2251+7 ( 2 0 3937.8677106876 2 6034.1814395937 ) 54.1025876908 (ExtendedPoll) + 2251+15 ( 2 0 3968.8756845943 2 6029.8141193251 ) 53.8471893590 (ExtendedPoll) + 2251+23 ( 2 0 3966.3440036262 2 6032.7893562581 ) 53.8453293272 (ExtendedPoll) + 2251+29 ( 2 0 3967.2852805629 2 6032.5287671287 ) 53.8387026417 (ExtendedPoll) + 2251+32 ( 2 0 3966.9613567598 2 6032.8941676795 ) 53.8385991104 (ExtendedPoll) + 2251+33 ( 2 0 3965.9895853505 2 6033.9903693319 ) 53.8382928991 (ExtendedPoll) + 2251+45 ( 2 0 3966.0039197226 2 6033.9851390276 ) 53.8382028409 (ExtendedPoll) + 2251+46 ( 2 0 3966.0291479677 2 6033.9679675607 ) 53.8381131770 (ExtendedPoll) + 2251+52 ( 2 0 3966.0378553973 2 6033.9615960721 ) 53.8380860741 (ExtendedPoll) + 2251+64 ( 2 0 3966.0380469160 2 6033.9618735742 ) 53.8380818691 (ExtendedPoll) + 2251+69 ( 2 0 3966.0381004053 2 6033.9618472758 ) 53.8380815916 (ExtendedPoll) + 2251+74 ( 2 0 3966.0381302064 2 6033.9618470067 ) 53.8380813128 (ExtendedPoll) + 2251+79 ( 2 0 3966.0381451069 2 6033.9618471499 ) 53.8380811710 (ExtendedPoll) + 2251+84 ( 2 0 3966.0381513080 2 6033.9618430199 ) 53.8380811481 (ExtendedPoll) + 2251+86 ( 2 0 3966.0381381930 2 6033.9618595149 ) 53.8380811293 (ExtendedPoll) + 2251+91 ( 2 0 3966.0381418784 2 6033.9618557502 ) 53.8380811271 (ExtendedPoll) + 2251+92 ( 2 0 3966.0381529347 2 6033.9618444560 ) 53.8380811204 (ExtendedPoll) + 2251+93 ( 2 0 3966.0381971599 2 6033.9617992793 ) 53.8380810935 (ExtendedPoll) + 2251+94 ( 2 0 3966.0383740607 2 6033.9616185725 ) 53.8380809858 (ExtendedPoll) + 2251+95 ( 2 0 3966.0390816638 2 6033.9608957451 ) 53.8380805552 (ExtendedPoll) + 2251+96 ( 2 0 3966.0419120761 2 6033.9580044356 ) 53.8380788327 (ExtendedPoll) + 2251+97 ( 2 0 3966.0532337255 2 6033.9464391976 ) 53.8380719433 (ExtendedPoll) + 2251+98 ( 2 0 3966.0985203229 2 6033.9001782457 ) 53.8380443936 (ExtendedPoll) + 2251+99 ( 2 0 3966.2796667126 2 6033.7151344380 ) 53.8379343190 (ExtendedPoll) + 2251+100 ( 2 0 3967.0042522715 2 6032.9749592074 ) 53.8374960138 (ExtendedPoll) + 2251+101 ( 2 0 3969.9025945070 2 6030.0142582847 ) 53.8357746693 (ExtendedPoll) + 2251+102 ( 2 0 3981.4959634492 2 6018.1714545940 ) 53.8293988351 (ExtendedPoll) + 2251+103 ( 2 0 4027.8694392178 2 5970.8002398312 ) 53.8120165816 (ExtendedPoll) + 2251+105 ( 2 0 4027.8996279793 2 5970.7957732839 ) 53.8117751288 (ExtendedPoll) + 2251+106 ( 2 0 4027.9901942637 2 5970.7823736422 ) 53.8110507797 (ExtendedPoll) + 2251+107 ( 2 0 4028.3524594017 2 5970.7287750751 ) 53.8081535202 (ExtendedPoll) + 2251+108 ( 2 0 4028.5782890972 2 5970.8215646372 ) 53.8052259801 (ExtendedPoll) + 2251+109 ( 2 0 4029.0659874104 2 5970.8447020517 ) 53.8004791353 (ExtendedPoll) + 2251+117 ( 2 0 4029.1224148462 2 5970.8679660822 ) 53.7997469853 (ExtendedPoll) + 2251+125 ( 2 0 4029.1289146169 2 5970.8639709871 ) 53.7997219690 (ExtendedPoll) + 2251+129 ( 2 0 4029.1327113864 2 5970.8636015775 ) 53.7996898997 (ExtendedPoll) + 2251+134 ( 2 0 4029.1345329350 2 5970.8641672091 ) 53.7996679124 (ExtendedPoll) + 2251+136 ( 2 0 4029.1361890843 2 5970.8632210851 ) 53.7996608999 (ExtendedPoll) + 2251+142 ( 2 0 4029.1366590260 2 5970.8631402857 ) 53.7996572423 (ExtendedPoll) + 2251+146 ( 2 0 4029.1368554851 2 5970.8630052034 ) 53.7996566135 (ExtendedPoll) + 2251+147 ( 2 0 4029.1372198865 2 5970.8626976562 ) 53.7996559536 (ExtendedPoll) + 2251+158 ( 2 0 4029.1372434032 2 5970.8627159631 ) 53.7996555720 (ExtendedPoll) + 2251+159 ( 2 0 4029.1372160758 2 5970.8627689341 ) 53.7996553557 (ExtendedPoll) + 2251+165 ( 2 0 4029.1372107574 2 5970.8627828538 ) 53.7996552815 (ExtendedPoll) + 2251+168 ( 2 0 4029.1372020883 2 5970.8627949737 ) 53.7996552545 (ExtendedPoll) + 2251+172 ( 2 0 4029.1371973626 2 5970.8628007338 ) 53.7996552473 (ExtendedPoll) + 2251+179 ( 2 0 4029.1371969852 2 5970.8628025579 ) 53.7996552346 (ExtendedPoll) + 2251+181 ( 2 0 4029.1372006890 2 5970.8627988111 ) 53.7996552334 (ExtendedPoll) + 2251+182 ( 2 0 4029.1372118001 2 5970.8627875709 ) 53.7996552298 (ExtendedPoll) + 2251+183 ( 2 0 4029.1372562449 2 5970.8627426102 ) 53.7996552156 (ExtendedPoll) + 2251+184 ( 2 0 4029.1374340239 2 5970.8625627674 ) 53.7996551585 (ExtendedPoll) + 2251+185 ( 2 0 4029.1381451401 2 5970.8618433959 ) 53.7996549302 (ExtendedPoll) + 2251+186 ( 2 0 4029.1409896047 2 5970.8589659099 ) 53.7996540170 (ExtendedPoll) + 2251+187 ( 2 0 4029.1523674632 2 5970.8474559659 ) 53.7996503647 (ExtendedPoll) + 2251+188 ( 2 0 4029.1978788972 2 5970.8014161900 ) 53.7996357631 (ExtendedPoll) + 2251+189 ( 2 0 4029.3799246331 2 5970.6172570866 ) 53.7995774796 (ExtendedPoll) + 2251+190 ( 2 0 4030.1081075767 2 5969.8806206727 ) 53.7993463077 (ExtendedPoll) + 2251+191 ( 2 0 4033.0208393511 2 5966.9340750174 ) 53.7984530101 (ExtendedPoll) + 2251+192 ( 2 0 4044.6717664489 2 5955.1478923961 ) 53.7953815270 (ExtendedPoll) + 2251+193 ( 2 0 4091.2754748399 2 5908.0031619108 ) 53.7910882360 (ExtendedPoll) + 2251+196 ( 2 0 4091.3024169829 2 5908.0174949293 ) 53.7907097823 (ExtendedPoll) + 2251+197 ( 2 0 4091.3832434122 2 5908.0604939849 ) 53.7895744291 (ExtendedPoll) + 2251+198 ( 2 0 4091.7065491291 2 5908.2324902073 ) 53.7850331320 (ExtendedPoll) + 2251+201 ( 2 0 4091.7062625770 2 5908.2935241345 ) 53.7844786297 (ExtendedPoll) + 2251+218 ( 2 0 4091.7061814853 2 5908.2937483387 ) 53.7844773284 (ExtendedPoll) + 2251+225 ( 2 0 4091.7061774429 2 5908.2938078061 ) 53.7844768227 (ExtendedPoll) + 2251+228 ( 2 0 4091.7061404988 2 5908.2938545806 ) 53.7844767353 (ExtendedPoll) + 2251+237 ( 2 0 4091.7061392073 2 5908.2938580748 ) 53.7844767152 (ExtendedPoll) + 2251+242 ( 2 0 4091.7061402086 2 5908.2938596455 ) 53.7844766917 (ExtendedPoll) + 2251+251 ( 2 0 4091.7061402086 2 5908.2938597496 ) 53.7844766907 (ExtendedPoll) + 2507+6 ( 2 0 4987.7715032480 2 5009.7172875975 ) 55.8778410034 (ExtendedPoll) + 2507+7 ( 2 0 4951.0860129922 2 5038.8691503901 ) 55.8090330212 (ExtendedPoll) + 2507+8 ( 2 0 4804.3440519688 2 5155.4766015605 ) 55.5765193455 (ExtendedPoll) + 2507+9 ( 2 0 4217.3762078751 2 5621.9064062421 ) 55.4051303015 (ExtendedPoll) + 2507+11 ( 2 0 4105.5728090001 2 5845.5132039921 ) 54.2371769988 (ExtendedPoll) + 2507+17 ( 2 0 4084.6096717110 2 5904.9087596444 ) 53.8806341533 (ExtendedPoll) + 2507+25 ( 2 0 4086.4930785768 2 5912.4969786111 ) 53.7940773323 (ExtendedPoll) + 2507+28 ( 2 0 4089.6866815232 2 5910.2450790976 ) 53.7852355401 (ExtendedPoll) + 2507+40 ( 2 0 4089.7473972443 2 5910.2388432578 ) 53.7847342099 (ExtendedPoll) + 2507+48 ( 2 0 4089.7542955796 2 5910.2355843266 ) 53.7847005125 (ExtendedPoll) + 2507+49 ( 2 0 4089.7673972155 2 5910.2277626627 ) 53.7846513996 (ExtendedPoll) + 2507+51 ( 2 0 4089.7801055712 2 5910.2193169774 ) 53.7846115945 (ExtendedPoll) + 2507+62 ( 2 0 4089.7805040628 2 5910.2190551032 ) 53.7846103195 (ExtendedPoll) + 2507+63 ( 2 0 4089.7816995375 2 5910.2182694805 ) 53.7846064942 (ExtendedPoll) + 2507+73 ( 2 0 4089.7816945523 2 5910.2182988629 ) 53.7846062720 (ExtendedPoll) + 2507+80 ( 2 0 4089.7816938911 2 5910.2183025290 ) 53.7846062447 (ExtendedPoll) + 2507+83 ( 2 0 4089.7816931323 2 5910.2183061762 ) 53.7846062184 (ExtendedPoll) + 2507+86 ( 2 0 4089.7816946030 2 5910.2183050332 ) 53.7846062153 (ExtendedPoll) + 2507+97 ( 2 0 4089.7816947071 2 5910.2183050332 ) 53.7846062143 (ExtendedPoll) + 2609+6 ( 2 0 4993.6127941072 2 5004.5037990269 ) 55.8961392637 (ExtendedPoll) + 2609+7 ( 2 0 4974.4511764290 2 5018.0151961078 ) 55.8801113087 (ExtendedPoll) + 2609+8 ( 2 0 4897.8047057158 2 5072.0607844311 ) 55.8259328921 (ExtendedPoll) + 2609+9 ( 2 0 4591.2188228633 2 5288.2431377246 ) 55.7773330381 (ExtendedPoll) + 2609+12 ( 2 0 4584.2311104336 2 5414.0219614589 ) 54.4414663757 (ExtendedPoll) + 2609+22 ( 2 0 4587.3564740008 2 5411.6745268146 ) 54.4410956907 (ExtendedPoll) + 2609+29 ( 2 0 4587.5587397857 2 5412.1189357716 ) 54.4345618898 (ExtendedPoll) + 2609+33 ( 2 0 4587.4405737045 2 5412.3325570157 ) 54.4332122013 (ExtendedPoll) + 2609+34 ( 2 0 4587.0527821074 2 5412.6292916912 ) 54.4331973113 (ExtendedPoll) + 2609+35 ( 2 0 4585.8894073161 2 5413.5194957176 ) 54.4331558220 (ExtendedPoll) + 2609+36 ( 2 0 4581.2359081511 2 5417.0803118233 ) 54.4330376116 (ExtendedPoll) + 2609+38 ( 2 0 4579.3525012852 2 5420.4991047210 ) 54.4114704020 (ExtendedPoll) + 2609+39 ( 2 0 4573.3201401643 2 5425.4669315265 ) 54.4076771370 (ExtendedPoll) + 2609+40 ( 2 0 4555.2230568015 2 5440.3704119429 ) 54.3971432812 (ExtendedPoll) + 2609+41 ( 2 0 4482.8347233502 2 5499.9843336087 ) 54.3678394409 (ExtendedPoll) + 2609+49 ( 2 0 4485.3459325046 2 5507.3814823136 ) 54.2681454161 (ExtendedPoll) + 2609+50 ( 2 0 4475.1919128802 2 5519.2824300454 ) 54.2285251876 (ExtendedPoll) + 2609+51 ( 2 0 4444.7298540071 2 5554.9852732408 ) 54.1136470777 (ExtendedPoll) + 2609+58 ( 2 0 4443.9800738281 2 5555.6109430488 ) 54.1135341068 (ExtendedPoll) + 2609+59 ( 2 0 4441.7307332914 2 5557.4879524728 ) 54.1132091099 (ExtendedPoll) + 2609+60 ( 2 0 4432.7333711444 2 5564.9959901689 ) 54.1121181220 (ExtendedPoll) + 2609+61 ( 2 0 4396.7439225563 2 5595.0281409531 ) 54.1111148301 (ExtendedPoll) + 2609+63 ( 2 0 4386.2623539118 2 5606.6015396648 ) 54.0828747897 (ExtendedPoll) + 2609+64 ( 2 0 4354.8176479782 2 5641.3217357998 ) 54.0021675011 (ExtendedPoll) + 2609+67 ( 2 0 4332.5443146086 2 5663.1583371426 ) 53.9763377152 (ExtendedPoll) + 2609+68 ( 2 0 4265.7243144997 2 5728.6681411709 ) 53.9145504521 (ExtendedPoll) + 2609+69 ( 2 0 3998.4443140642 2 5990.7073572841 ) 53.9107416673 (ExtendedPoll) + 2609+77 ( 2 0 3977.9179088020 2 6014.2908867343 ) 53.8968485442 (ExtendedPoll) + 2609+85 ( 2 0 3977.6108315956 2 6018.1873552864 ) 53.8658100136 (ExtendedPoll) + 2609+87 ( 2 0 3985.4720080790 2 6010.4353618097 ) 53.8594585168 (ExtendedPoll) + 2609+88 ( 2 0 4009.0555375292 2 5987.1793813797 ) 53.8425419841 (ExtendedPoll) + 2609+89 ( 2 0 4103.3896553299 2 5894.1554596595 ) 53.8066758321 (ExtendedPoll) + 2609+98 ( 2 0 4105.0239884617 2 5893.0858073906 ) 53.8015202481 (ExtendedPoll) + 2609+99 ( 2 0 4109.9269878569 2 5889.8768505839 ) 53.7861093451 (ExtendedPoll) + 2609+108 ( 2 0 4110.1419152454 2 5889.7610302313 ) 53.7852071379 (ExtendedPoll) + 2609+116 ( 2 0 4110.1058896513 2 5889.8103005292 ) 53.7850837032 (ExtendedPoll) + 2609+117 ( 2 0 4109.9978128689 2 5889.9581114227 ) 53.7847134692 (ExtendedPoll) + 2609+120 ( 2 0 4110.1308929863 2 5889.8481353998 ) 53.7845067680 (ExtendedPoll) + 2609+123 ( 2 0 4110.2185046189 2 5889.7631360559 ) 53.7844866226 (ExtendedPoll) + 2609+124 ( 2 0 4110.4813395169 2 5889.5081380242 ) 53.7844264399 (ExtendedPoll) + 2609+134 ( 2 0 4110.4929230099 2 5889.4982056417 ) 53.7844117835 (ExtendedPoll) + 2609+135 ( 2 0 4110.5276734889 2 5889.4684084945 ) 53.7843678178 (ExtendedPoll) + 2609+142 ( 2 0 4110.5308528491 2 5889.4663005158 ) 53.7843581081 (ExtendedPoll) + 2609+143 ( 2 0 4110.5369402846 2 5889.4617014955 ) 53.7843446963 (ExtendedPoll) + 2609+148 ( 2 0 4110.5385864786 2 5889.4607381551 ) 53.7843384902 (ExtendedPoll) + 2609+154 ( 2 0 4110.5389368624 2 5889.4610615818 ) 53.7843323072 (ExtendedPoll) + 2609+174 ( 2 0 4110.5389372789 2 5889.4610615818 ) 53.7843323034 (ExtendedPoll) + 2609+179 ( 2 0 4110.5389372789 2 5889.4610619983 ) 53.7843322995 (ExtendedPoll) + 2609+185 ( 2 0 4110.5389372789 2 5889.4610621024 ) 53.7843322986 (ExtendedPoll) + 2609+186 ( 2 0 4110.5389372789 2 5889.4610624148 ) 53.7843322957 (ExtendedPoll) + 2609+193 ( 2 0 4110.5389373050 2 5889.4610624148 ) 53.7843322955 (ExtendedPoll) + 2609+194 ( 2 0 4110.5389373831 2 5889.4610624148 ) 53.7843322947 (ExtendedPoll) + 2808+6 ( 2 0 4329.1796067501 2 5670.8203932499 ) 53.9289318169 (ExtendedPoll) + 2867+10 ( 2 0 4992.1115277649 2 5007.7246977250 ) 55.8685413615 (ExtendedPoll) + 2867+11 ( 2 0 4968.4461110597 2 5030.8987909000 ) 55.7705699043 (ExtendedPoll) + 2867+12 ( 2 0 4873.7844442388 2 5123.5951636001 ) 55.4016911655 (ExtendedPoll) + 2867+13 ( 2 0 4495.1377769551 2 5494.3806544003 ) 54.3231819620 (ExtendedPoll) + 2867+15 ( 2 0 4411.2852277989 2 5585.2209159863 ) 54.0868469342 (ExtendedPoll) + 2867+22 ( 2 0 4407.4365268122 2 5592.0175581542 ) 54.0499159225 (ExtendedPoll) + 2867+28 ( 2 0 4405.3364599175 2 5593.8105478426 ) 54.0495510124 (ExtendedPoll) + 2867+29 ( 2 0 4399.0362592332 2 5599.1895169077 ) 54.0485700853 (ExtendedPoll) + 2867+30 ( 2 0 4373.8354564960 2 5620.7053931683 ) 54.0463593230 (ExtendedPoll) + 2867+33 ( 2 0 4369.7137979926 2 5627.3382608261 ) 54.0145749170 (ExtendedPoll) + 2867+40 ( 2 0 4368.6287918634 2 5628.9623580510 ) 54.0074781800 (ExtendedPoll) + 2867+41 ( 2 0 4365.3737734757 2 5633.8346497256 ) 53.9862560504 (ExtendedPoll) + 2867+43 ( 2 0 4362.6919658733 2 5636.6802318381 ) 53.9806946516 (ExtendedPoll) + 2867+44 ( 2 0 4354.6465430661 2 5645.2169781755 ) 53.9642607181 (ExtendedPoll) + 2867+50 ( 2 0 4354.0247117231 2 5645.9701703234 ) 53.9620624682 (ExtendedPoll) + 2867+61 ( 2 0 4354.0368388529 2 5645.9609094433 ) 53.9620504600 (ExtendedPoll) + 2867+65 ( 2 0 4354.0401585606 2 5645.9590302273 ) 53.9620405451 (ExtendedPoll) + 2867+71 ( 2 0 4354.0409392116 2 5645.9584824325 ) 53.9620392835 (ExtendedPoll) + 2867+74 ( 2 0 4354.0405359427 2 5645.9593466482 ) 53.9620340616 (ExtendedPoll) + 2867+87 ( 2 0 4354.0405617934 2 5645.9593318187 ) 53.9620339864 (ExtendedPoll) + 2867+88 ( 2 0 4354.0406393458 2 5645.9592873300 ) 53.9620337607 (ExtendedPoll) + 2867+89 ( 2 0 4354.0407417896 2 5645.9592263700 ) 53.9620334847 (ExtendedPoll) + 2867+98 ( 2 0 4354.0407563620 2 5645.9592294825 ) 53.9620333264 (ExtendedPoll) + 2867+99 ( 2 0 4354.0407811713 2 5645.9592129695 ) 53.9620332772 (ExtendedPoll) + 2867+106 ( 2 0 4354.0407786145 2 5645.9592156788 ) 53.9620332721 (ExtendedPoll) + 2867+107 ( 2 0 4354.0407709439 2 5645.9592238067 ) 53.9620332568 (ExtendedPoll) + 2867+108 ( 2 0 4354.0407402615 2 5645.9592563181 ) 53.9620331954 (ExtendedPoll) + 2867+114 ( 2 0 4354.0407434536 2 5645.9592543977 ) 53.9620331870 (ExtendedPoll) + 2867+122 ( 2 0 4354.0407434536 2 5645.9592560637 ) 53.9620331701 (ExtendedPoll) + 2867+123 ( 2 0 4354.0407422389 2 5645.9592574757 ) 53.9620331665 (ExtendedPoll) + 3058+8 ( 2 0 4991.1561764562 2 5006.6055719062 ) 55.8895337846 (ExtendedPoll) + 3058+9 ( 2 0 4964.6247058247 2 5026.4222876248 ) 55.8543769246 (ExtendedPoll) + 3058+10 ( 2 0 4858.4988232988 2 5105.6891504990 ) 55.7342678543 (ExtendedPoll) + 3058+11 ( 2 0 4433.9952931954 2 5422.7566019961 ) 55.6083992097 (ExtendedPoll) + 3058+16 ( 2 0 4468.9338553438 2 5473.4175171113 ) 54.7683907188 (ExtendedPoll) + 3058+17 ( 2 0 4371.1058813282 2 5557.2700662675 ) 54.7224471575 (ExtendedPoll) + 3058+22 ( 2 0 4374.5997375430 2 5620.1594781347 ) 54.0452990385 (ExtendedPoll) + 3058+26 ( 2 0 4353.6366002540 2 5643.3062755580 ) 53.9923716603 (ExtendedPoll) + 3058+34 ( 2 0 4352.3741717388 2 5647.0048499105 ) 53.9659824019 (ExtendedPoll) + 3058+41 ( 2 0 4352.7757178358 2 5646.7270943123 ) 53.9652910126 (ExtendedPoll) + 3058+42 ( 2 0 4353.9803561267 2 5645.8938275179 ) 53.9632201609 (ExtendedPoll) + 3058+50 ( 2 0 4353.8820221150 2 5646.1172848288 ) 53.9618183016 (ExtendedPoll) + 3058+67 ( 2 0 4353.8828862995 2 5646.1168814928 ) 53.9618148524 (ExtendedPoll) + 3058+70 ( 2 0 4353.8819301637 2 5646.1178326989 ) 53.9618135661 (ExtendedPoll) + 3058+71 ( 2 0 4353.8790617562 2 5646.1206863173 ) 53.9618097072 (ExtendedPoll) + 3058+72 ( 2 0 4353.8675881265 2 5646.1321007910 ) 53.9617942721 (ExtendedPoll) + 3058+73 ( 2 0 4353.8216936077 2 5646.1777586857 ) 53.9617325386 (ExtendedPoll) + 3058+74 ( 2 0 4353.6381155322 2 5646.3603902646 ) 53.9614857168 (ExtendedPoll) + 3058+75 ( 2 0 4352.9038032305 2 5647.0909165803 ) 53.9605002241 (ExtendedPoll) + 3058+76 ( 2 0 4349.9665540238 2 5650.0130218428 ) 53.9565869794 (ExtendedPoll) + 3058+77 ( 2 0 4338.2175571967 2 5661.7014428928 ) 53.9413943430 (ExtendedPoll) + 3058+78 ( 2 0 4291.2215698885 2 5708.4551270929 ) 53.8880355778 (ExtendedPoll) + 3058+79 ( 2 0 4103.2376206554 2 5895.4698638933 ) 53.7960048025 (ExtendedPoll) + 3058+83 ( 2 0 4103.0824826918 2 5895.9328254315 ) 53.7931789654 (ExtendedPoll) + 3058+84 ( 2 0 4102.6170688008 2 5897.3217100462 ) 53.7847063488 (ExtendedPoll) + 3058+88 ( 2 0 4102.3017815441 2 5897.6944676551 ) 53.7841793274 (ExtendedPoll) + 3058+104 ( 2 0 4102.3028217662 2 5897.6960663778 ) 53.7841551305 (ExtendedPoll) + 3058+106 ( 2 0 4102.3045951993 2 5897.6953642985 ) 53.7841453060 (ExtendedPoll) + 3058+116 ( 2 0 4102.3046242597 2 5897.6953709067 ) 53.7841449789 (ExtendedPoll) + 3058+126 ( 2 0 4102.3046246516 2 5897.6953727277 ) 53.7841449586 (ExtendedPoll) + 3058+128 ( 2 0 4102.3046253455 2 5897.6953744562 ) 53.7841449364 (ExtendedPoll) + 3058+140 ( 2 0 4102.3046253471 2 5897.6953744562 ) 53.7841449364 (ExtendedPoll) + 3058+141 ( 2 0 4102.3046253520 2 5897.6953744562 ) 53.7841449364 (ExtendedPoll) + 3058+142 ( 2 0 4102.3046253715 2 5897.6953744562 ) 53.7841449362 (ExtendedPoll) + 3058+143 ( 2 0 4102.3046254496 2 5897.6953744562 ) 53.7841449355 (ExtendedPoll) + 3211+9 ( 2 0 4999.2843395107 2 5000.6644809549 ) 55.8991235044 (ExtendedPoll) + 3211+10 ( 2 0 4997.1373580427 2 5002.6579238197 ) 55.8914071579 (ExtendedPoll) + 3211+11 ( 2 0 4988.5494321709 2 5010.6316952788 ) 55.8607138749 (ExtendedPoll) + 3211+12 ( 2 0 4954.1977286835 2 5042.5267811150 ) 55.7407142386 (ExtendedPoll) + 3211+13 ( 2 0 4816.7909147341 2 5170.1071244602 ) 55.3063592103 (ExtendedPoll) + 3211+14 ( 2 0 4267.1636589366 2 5680.4284978408 ) 54.3782156485 (ExtendedPoll) + 3211+16 ( 2 0 4258.4290183995 2 5741.5709816005 ) 53.8530873348 (ExtendedPoll) + 3275+16 ( 2 0 4999.4544048385 2 5000.4231907750 ) 55.9007514521 (ExtendedPoll) + 3275+17 ( 2 0 4997.8176193541 2 5001.6927631002 ) 55.8979127990 (ExtendedPoll) + 3275+18 ( 2 0 4991.2704774163 2 5006.7710524007 ) 55.8866378337 (ExtendedPoll) + 3275+19 ( 2 0 4965.0819096653 2 5027.0842096030 ) 55.8428188421 (ExtendedPoll) + 3275+20 ( 2 0 4860.3276386613 2 5108.3368384118 ) 55.6884538793 (ExtendedPoll) + 3275+21 ( 2 0 4441.3105546452 2 5433.3473536473 ) 55.4321933111 (ExtendedPoll) + 3275+24 ( 2 0 4440.4370905915 2 5464.7920595809 ) 55.1023491348 (ExtendedPoll) + 3275+25 ( 2 0 4437.8166984304 2 5559.1261773817 ) 54.1296401397 (ExtendedPoll) + 3275+28 ( 2 0 4394.1434957448 2 5604.5463081746 ) 54.0358312283 (ExtendedPoll) + 3275+31 ( 2 0 4348.7233649518 2 5648.2195108602 ) 53.9855229289 (ExtendedPoll) + 3275+32 ( 2 0 4212.4629725730 2 5779.2391189168 ) 53.8982210340 (ExtendedPoll) + 3275+39 ( 2 0 4246.9648026945 2 5751.7250012249 ) 53.8561122313 (ExtendedPoll) + 3275+44 ( 2 0 4253.1063468222 2 5746.8663574261 ) 53.8487569023 (ExtendedPoll) + 3275+54 ( 2 0 4253.0200213419 2 5746.9526629144 ) 53.8486838339 (ExtendedPoll) + 3275+55 ( 2 0 4252.7610449010 2 5747.2115793792 ) 53.8484648755 (ExtendedPoll) + 3275+56 ( 2 0 4251.7251391376 2 5748.2472452386 ) 53.8475927460 (ExtendedPoll) + 3275+57 ( 2 0 4247.5815160840 2 5752.3899086759 ) 53.8441635235 (ExtendedPoll) + 3275+58 ( 2 0 4231.0070238695 2 5768.9605624254 ) 53.8313972696 (ExtendedPoll) + 3275+59 ( 2 0 4164.7090550115 2 5835.2431774231 ) 53.7956619398 (ExtendedPoll) + 3275+72 ( 2 0 4164.7639497269 2 5835.2164964256 ) 53.7954160381 (ExtendedPoll) + 3275+76 ( 2 0 4164.7917332002 2 5835.2038710575 ) 53.7952833211 (ExtendedPoll) + 3275+77 ( 2 0 4164.8360404827 2 5835.1618928437 ) 53.7952771546 (ExtendedPoll) + 3275+85 ( 2 0 4164.8422068711 2 5835.1574002652 ) 53.7952636014 (ExtendedPoll) + 3275+97 ( 2 0 4164.8424175700 2 5835.1572886885 ) 53.7952627439 (ExtendedPoll) + 3275+102 ( 2 0 4164.8423842792 2 5835.1574031550 ) 53.7952619685 (ExtendedPoll) + 3275+109 ( 2 0 4164.8424622828 2 5835.1574351058 ) 53.7952609619 (ExtendedPoll) + 3275+110 ( 2 0 4164.8424186334 2 5835.1575460363 ) 53.7952603135 (ExtendedPoll) + 3275+117 ( 2 0 4164.8424468760 2 5835.1575365215 ) 53.7952601474 (ExtendedPoll) + 3275+121 ( 2 0 4164.8424209888 2 5835.1575697812 ) 53.7952600688 (ExtendedPoll) + 3275+129 ( 2 0 4164.8424239711 2 5835.1575675489 ) 53.7952600628 (ExtendedPoll) + 3275+130 ( 2 0 4164.8424329181 2 5835.1575608518 ) 53.7952600448 (ExtendedPoll) + 3275+135 ( 2 0 4164.8424361867 2 5835.1575626390 ) 53.7952599984 (ExtendedPoll) + 3275+138 ( 2 0 4164.8424402468 2 5835.1575592816 ) 53.7952599933 (ExtendedPoll) + 3275+145 ( 2 0 4164.8424410483 2 5835.1575588074 ) 53.7952599905 (ExtendedPoll) + 3275+147 ( 2 0 4164.8424392431 2 5835.1575607257 ) 53.7952599888 (ExtendedPoll) + 3436 ( 3 0 3333.3333333333 2 3333.3333333333 1 3333.3333333333 ) 47.1682905221 -} end of run (max number of blackbox evaluations) +} end of run (mesh size reached NOMAD precision) -blackbox evaluations : 200 -best feasible solution : ( 3 0 2939.656576 2 3626.302083 1 3433.43099 ) h=0 f=46.59711656 +blackbox evaluations : 3436 +best feasible solution : ( 3 0 3333.333333 2 3333.333333 1 3333.333333 ) h=0 f=47.16829052 diff --git a/examples/advanced/multi_start/best_x.txt b/examples/advanced/multi_start/best_x.txt index 6657267..7588ff3 100644 --- a/examples/advanced/multi_start/best_x.txt +++ b/examples/advanced/multi_start/best_x.txt @@ -1 +1 @@ -1.001496962026439119242127162579 0.00098876953124999995663191310057982 1.0009373918174639950251503250911 1.0017943110223916924894638214028 1.0001091153523589127871673554182 \ No newline at end of file +1.0065227779901828597530766273849 0.0061576008796691908409037807814457 0.99995827823866767491978180260048 1.0093326058145666301868459413527 1.0032484173774720570548879550188 \ No newline at end of file diff --git a/examples/advanced/multi_start/param.txt b/examples/advanced/multi_start/param.txt index 7a4df99..09df942 100644 --- a/examples/advanced/multi_start/param.txt +++ b/examples/advanced/multi_start/param.txt @@ -1,9 +1,7 @@ MAX_CACHE_MEMORY 750 -seed none - -#initial_mesh_size r0.1 +initial_mesh_size r0.1 opportunistic_eval no diff --git a/examples/advanced/multi_start/runExample.log b/examples/advanced/multi_start/runExample.log index 94584ab..51c3fae 100644 --- a/examples/advanced/multi_start/runExample.log +++ b/examples/advanced/multi_start/runExample.log @@ -1,18 +1,21 @@ -starting point # 0: ( 1.442943417 0.369140625 0.9823972059 0.8663984208 1.488629702 ) -starting point # 1: ( 4.046907118 0.2179386209 0.3995457903 2.86002185 2.869872299 ) -starting point # 2: ( 2.730496038 4.019688198 2.015450408 3.887235003 1.919237215 ) -starting point # 3: ( 1.986593711 1.814325217 1.166098379 0.9517739273 0.4086947283 ) -starting point # 4: ( 1.072412482 2.713920967 3.075009451 0.3310437183 1.032300187 ) +starting point # 0: ( 1.311638583 0.3116009987 0.9520390845 0.8088161243 1.540724398 1.619263445 0.9519058983 ) +starting point # 1: ( 4.046907118 0.2179386209 0.3995457903 2.86002185 2.869872299 1.805805862 0.9241232544 ) +starting point # 2: ( 2.730496038 4.019688198 2.015450408 3.887235003 1.919237215 0.004176816764 2.788539635 ) +starting point # 3: ( 1.986593711 1.814325217 1.166098379 0.9517739273 0.4086947283 3.9836116 2.239536416 ) +starting point # 4: ( 1.072412482 2.713920967 3.075009451 0.3310437183 1.032300187 3.079123794 3.985637823 ) -run # 0: f=1.506294281 -run # 1: f=1.415934966 -run # 2: f=2.001223577 -run # 3: f=1.799944829 -run # 4: f=2.61048503 +Warning: { + Anisotropic mesh is disabled for direction types other than OrthoMads. +} +run # 0: f=1.619155361 +run # 1: f=1.890750373 +run # 2: f=2.267307514 +run # 3: f=1.998968772 +run # 4: f=2.24968126 bb eval : 5000 -best : 1.415934966 -worst : 2.61048503 -solution: x = ( 1.001496962 0.0009887695312 1.000937392 1.001794311 1.000109115 ) f(x) = 1.415934966 +best : 1.619155361 +worst : 2.267307514 +solution: x = ( 1.310592306 0.3106177009 0.9507953978 0.8088442339 1.538847818 1.618878923 0.951419131 ) f(x) = 1.619155361 diff --git a/examples/advanced/plot/problems/02/parameters.txt b/examples/advanced/plot/problems/02/param.txt similarity index 100% rename from examples/advanced/plot/problems/02/parameters.txt rename to examples/advanced/plot/problems/02/param.txt diff --git a/examples/advanced/restart/restart.cpp b/examples/advanced/restart/restart.cpp index ae5b7a8..e41b0dc 100644 --- a/examples/advanced/restart/restart.cpp +++ b/examples/advanced/restart/restart.cpp @@ -11,32 +11,14 @@ using namespace NOMAD; class My_Evaluator : public Evaluator { private: - double _mesh_update_basis; - int _initial_mesh_index; - int _mesh_index; - Point _initial_mesh_size; - public: - My_Evaluator ( const Parameters & p ) : - Evaluator ( p ) , - _mesh_update_basis ( p.get_mesh_update_basis().value() ) , - _initial_mesh_index ( p.get_initial_mesh_index() ) , - _mesh_index ( _initial_mesh_index ) , - _initial_mesh_size ( p.get_initial_mesh_size() ) {} + + My_Evaluator ( const Parameters & p ) : Evaluator ( p ) { } + + ~My_Evaluator ( void ) {} - int get_mesh_index ( void ) const { return _mesh_index; } - - void get_mesh_size ( Point & mesh_size ) const - { - Mesh::get_delta_m ( mesh_size , - _initial_mesh_size , - _mesh_update_basis , - _initial_mesh_index , - _mesh_index ); - } - virtual bool eval_x ( Eval_Point & x , const Double & h_max , bool & count_eval ) const; @@ -82,7 +64,7 @@ void My_Evaluator::update_iteration ( success_type success , const Pareto_Front & pareto_front , bool & stop ) { - _mesh_index = Mesh::get_mesh_index(); + if ( success == UNSUCCESSFUL ) stop = true; } @@ -112,7 +94,7 @@ int main ( int argc , char ** argv ) bbot[2] = EB; p.set_BB_OUTPUT_TYPE ( bbot ); - // p.set_DISPLAY_DEGREE ( FULL_DISPLAY ); + p.set_DISPLAY_DEGREE ( 2 ); p.set_DISPLAY_STATS ( "bbe ( sol ) obj" ); @@ -127,9 +109,13 @@ int main ( int argc , char ** argv ) p.set_MAX_BB_EVAL (100); // the algorithm terminates after // 100 black-box evaluations + + // parameters validation: p.check(); + + OrthogonalMesh * oMesh=p.get_signature()->get_mesh(); // custom evaluator creation: My_Evaluator ev ( p ); @@ -140,8 +126,10 @@ int main ( int argc , char ** argv ) // algorithm creation: Mads mads ( p , &ev ); + // successive runs: - for ( int i = 0 ; i < 5 ; ++i ) { + for ( int i = 0 ; i < 5 ; ++i ) + { out << endl << open_block ( "MADS run #" + NOMAD::itos(i) ); @@ -161,18 +149,21 @@ int main ( int argc , char ** argv ) else p.set_LH_SEARCH(0,0); - - // initial mesh: - p.set_INITIAL_MESH_INDEX ( ev.get_mesh_index() ); - Point initial_mesh_size; - ev.get_mesh_size ( initial_mesh_size ); - p.set_INITIAL_MESH_SIZE ( initial_mesh_size ); - - // parameters validation: + // Update the mesh for an unsuccessful iteration and put current + // mesh and poll sizes as initial mesh and poll sizes for the next start. + oMesh->update(UNSUCCESSFUL); + Point delta_0, Delta_0; + oMesh->get_delta(delta_0); + oMesh->set_delta_0(delta_0); + oMesh->get_Delta(Delta_0); + oMesh->set_Delta_0(Delta_0); + + // parameters validation: p.check(); // reset the Mads object: mads.reset ( true , true ); + } // the run: diff --git a/examples/advanced/restart/runExample.log b/examples/advanced/restart/runExample.log index 08cd5d6..e0e3dcf 100644 --- a/examples/advanced/restart/runExample.log +++ b/examples/advanced/restart/runExample.log @@ -5,15 +5,15 @@ MADS run { BBE ( SOL ) OBJ - 2 ( 1.1000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 275.2281000000 (PhaseOne) - 3 ( 4.4000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 0.0000000000 (PhaseOne) - 3 ( 4.4000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 0.0000000000 - 9 ( 4.4000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 0.0000000000 + 2 ( 0.0000000000 0.5366563146 0.5813776741 -0.2683281573 0.2683281573 ) 288.7937255854 (PhaseOne) + 3 ( 0.0000000000 2.1466252584 2.3255106966 -1.0733126292 1.0733126292 ) 0.0000000000 (PhaseOne) + 3 ( 0.0000000000 2.1466252584 2.3255106966 -1.0733126292 1.0733126292 ) 1.0733126292 + 9 ( 0.0000000000 2.1466252584 2.3255106966 -1.0733126292 1.0733126292 ) 1.0733126292 } end of run (terminated by the user inside Evaluator::update_iteration()) blackbox evaluations : 9 -best feasible solution : ( 4.4 0 0 0 0 ) h=0 f=0 +best feasible solution : ( 0 2.146625258 2.325510697 -1.073312629 1.073312629 ) h=0 f=1.073312629 } MADS run #1 { @@ -22,13 +22,18 @@ MADS run { BBE ( SOL ) OBJ - 9 ( 4.4000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 0.0000000000 - 15 ( 4.4000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 0.0000000000 + 9 ( -0.4919349550 2.6832815730 2.9068883707 -0.5366563146 1.0733126292 ) 1.0733126292 + 11 ( -0.4919349550 3.0857738089 2.9068883707 -0.5366563146 0.8720665112 ) 0.8720665112 + 12 ( -0.4919349550 4.2932505168 2.9068883707 -0.5366563146 0.2683281573 ) 0.2683281573 + 20 ( 0.0000000000 3.6224301235 2.6161995337 -0.0670820393 -1.0733126292 ) -1.0733126292 + 27 ( -0.2459674775 4.1590864381 2.9068883707 -0.6037383539 -1.4087228258 ) -1.4087228258 + 29 ( 2.4596747752 1.4758048651 0.7267220927 -0.6708203932 -3.4211840056 ) -3.4211840056 + 36 ( 2.4596747752 1.4758048651 0.7267220927 -0.6708203932 -3.4211840056 ) -3.4211840056 } end of run (terminated by the user inside Evaluator::update_iteration()) -blackbox evaluations : 15 -best feasible solution : ( 4.4 0 0 0 0 ) h=0 f=0 +blackbox evaluations : 36 +best feasible solution : ( 2.459674775 1.475804865 0.7267220927 -0.6708203932 -3.421184006 ) h=0 f=-3.421184006 } MADS run #2 { @@ -37,14 +42,13 @@ MADS run { BBE ( SOL ) OBJ - 15 ( 4.4000000000 -0.6000000000 0.0000000000 0.0000000000 0.0000000000 ) 0.0000000000 - 16 ( 4.5375000000 -0.1500000000 0.4875000000 0.7500000000 -1.5000000000 ) -1.5000000000 - 23 ( 4.5375000000 -0.1500000000 0.4875000000 0.7500000000 -1.5000000000 ) -1.5000000000 + 36 ( 2.4596747752 1.4758048651 0.7267220927 -0.6708203932 -3.4211840056 ) -3.4211840056 + 42 ( 2.4596747752 1.4758048651 0.7267220927 -0.6708203932 -3.4211840056 ) -3.4211840056 } end of run (terminated by the user inside Evaluator::update_iteration()) -blackbox evaluations : 23 -best feasible solution : ( 4.5375 -0.15 0.4875 0.75 -1.5 ) h=0 f=-1.5 +blackbox evaluations : 42 +best feasible solution : ( 2.459674775 1.475804865 0.7267220927 -0.6708203932 -3.421184006 ) h=0 f=-3.421184006 } MADS run #3 { @@ -53,14 +57,13 @@ MADS run { BBE ( SOL ) OBJ - 23 ( 4.5375000000 -0.7500000000 0.4875000000 0.7500000000 -1.5000000000 ) -1.5000000000 - 30 ( 4.1250000000 -0.9750000000 0.3250000000 0.7500000000 -2.2500000000 ) -2.2500000000 - 38 ( 4.1250000000 -0.9750000000 0.3250000000 0.7500000000 -2.2500000000 ) -2.2500000000 + 42 ( 2.4596747752 1.4758048651 0.7267220927 -0.6708203932 -3.4211840056 ) -3.4211840056 + 48 ( 2.4596747752 1.4758048651 0.7267220927 -0.6708203932 -3.4211840056 ) -3.4211840056 } end of run (terminated by the user inside Evaluator::update_iteration()) -blackbox evaluations : 38 -best feasible solution : ( 4.125 -0.975 0.325 0.75 -2.25 ) h=0 f=-2.25 +blackbox evaluations : 48 +best feasible solution : ( 2.459674775 1.475804865 0.7267220927 -0.6708203932 -3.421184006 ) h=0 f=-3.421184006 } MADS run #4 { @@ -69,11 +72,13 @@ MADS run { BBE ( SOL ) OBJ - 38 ( 3.5750000000 -0.9750000000 0.3250000000 0.7500000000 -2.2500000000 ) -2.2500000000 - 44 ( 3.5750000000 -0.9750000000 0.3250000000 0.7500000000 -2.2500000000 ) -2.2500000000 + 48 ( 2.4596747752 1.4758048651 0.7267220927 -0.6708203932 -3.4211840056 ) -3.4211840056 + 52 ( 2.4750477426 1.4674196102 0.8902345635 0.5282710597 -3.4505323978 ) -3.4505323978 + 54 ( 0.9915563938 0.9978453350 1.0174109298 1.0230010997 -3.9997665948 ) -3.9997665948 + 61 ( 0.9915563938 0.9978453350 1.0174109298 1.0230010997 -3.9997665948 ) -3.9997665948 } end of run (terminated by the user inside Evaluator::update_iteration()) -blackbox evaluations : 44 -best feasible solution : ( 3.575 -0.975 0.325 0.75 -2.25 ) h=0 f=-2.25 +blackbox evaluations : 61 +best feasible solution : ( 0.9915563938 0.997845335 1.01741093 1.0230011 -3.999766595 ) h=0 f=-3.999766595 } diff --git a/examples/advanced/user_search/runExample.log b/examples/advanced/user_search/runExample.log index 78b04cf..60c785b 100644 --- a/examples/advanced/user_search/runExample.log +++ b/examples/advanced/user_search/runExample.log @@ -6,10 +6,16 @@ MADS search { list of points evaluation (user search) { - evaluation 1/1 { + submitted evaluation 1/1 { + + point #1 ( 0.132741232 ) + mesh indices: ( 0 ) + + } - point #1 ( 0.132741232 ) + evaluation 1/1 { + point #1 user search dominating point #1 { x = ( 0.132741232 ) @@ -33,10 +39,16 @@ MADS search { list of points evaluation (user search) { - evaluation 1/1 { + submitted evaluation 1/1 { - point #2 ( 0.061929856 ) + point #2 ( 0.061929856 ) + mesh indices: ( 0 ) + } + + evaluation 1/1 { + + point #2 user search dominating point #2 { x = ( 0.061929856 ) @@ -60,10 +72,16 @@ MADS search { list of points evaluation (user search) { - evaluation 1/1 { + submitted evaluation 1/1 { - point #3 ( 0.052807552 ) + point #3 ( 0.052807552 ) + mesh indices: ( 0 ) + } + + evaluation 1/1 { + + point #3 user search dominating point #3 { x = ( 0.052807552 ) @@ -87,10 +105,16 @@ MADS search { list of points evaluation (user search) { - evaluation 1/1 { + submitted evaluation 1/1 { - point #4 ( 0.003343488002 ) + point #4 ( 0.003343488002 ) + mesh indices: ( 0 ) + } + + evaluation 1/1 { + + point #4 user search dominating point #4 { x = ( 0.003343488002 ) @@ -114,10 +138,16 @@ MADS search { list of points evaluation (user search) { - evaluation 1/1 { + submitted evaluation 1/1 { - point #5 ( 0.003046400592 ) + point #5 ( 0.003046400592 ) + mesh indices: ( 0 ) + } + + evaluation 1/1 { + + point #5 user search dominating point #5 { x = ( 0.003046400592 ) @@ -141,10 +171,16 @@ MADS search { list of points evaluation (user search) { - evaluation 1/1 { + submitted evaluation 1/1 { - point #6 ( 0.002265794838 ) + point #6 ( 0.002265794838 ) + mesh indices: ( 0 ) + } + + evaluation 1/1 { + + point #6 user search dominating point #6 { x = ( 0.002265794838 ) @@ -168,10 +204,16 @@ MADS search { list of points evaluation (user search) { - evaluation 1/1 { + submitted evaluation 1/1 { + + point #7 ( 0.001481318181 ) + mesh indices: ( 0 ) + + } - point #7 ( 0.001481318181 ) + evaluation 1/1 { + point #7 user search dominating point #7 { x = ( 0.001481318181 ) @@ -195,10 +237,16 @@ MADS search { list of points evaluation (user search) { - evaluation 1/1 { + submitted evaluation 1/1 { + + point #8 ( 0.001371090082 ) + mesh indices: ( 0 ) - point #8 ( 0.001371090082 ) + } + + evaluation 1/1 { + point #8 user search dominating point #8 { x = ( 0.001371090082 ) @@ -222,10 +270,16 @@ MADS search { list of points evaluation (user search) { - evaluation 1/1 { + submitted evaluation 1/1 { + + point #9 ( 0.0008957599348 ) + mesh indices: ( 0 ) - point #9 ( 0.0008957599348 ) + } + + evaluation 1/1 { + point #9 user search dominating point #9 { x = ( 0.0008957599348 ) diff --git a/examples/advanced/user_search/user_search.cpp b/examples/advanced/user_search/user_search.cpp index 14d54e9..8c4870c 100755 --- a/examples/advanced/user_search/user_search.cpp +++ b/examples/advanced/user_search/user_search.cpp @@ -100,6 +100,29 @@ void My_Search::search ( Mads & mads , tk->set_signature ( signature ); (*tk)[0] = static_cast<int>(ceil(1.0/xk)) * xk - 1.0; + + + // Projection maybe needed + // const NOMAD::Display & out= _p.out(); + // NOMAD::dd_type display_degree = out.get_search_dd(); + // if ( display_degree == NOMAD::FULL_DISPLAY ) + // { + // out << "candidate"; + // out << " (before projection)"; + // out << ": ( " << *tk << " )" << std::endl; + // } + // + // // Project to the mesh + // tk->project_to_mesh(*feas_inc,signature->get_mesh()->get_delta(),signature->get_lb(),signature->get_ub() ); + // + // if ( display_degree == NOMAD::FULL_DISPLAY ) + // { + // out << "candidate"; + // out << " (after projection)"; + // out << ": ( " << *tk << " )" << std::endl; + // } + + // Evaluator_Control: Evaluator_Control & ev_control = mads.get_evaluator_control(); diff --git a/examples/basic/batch/bi_obj/param.txt b/examples/basic/batch/bi_obj/param.txt index af13c77..cc0d854 100644 --- a/examples/basic/batch/bi_obj/param.txt +++ b/examples/basic/batch/bi_obj/param.txt @@ -17,7 +17,7 @@ upper_bound * 1.0 MULTI_OVERALL_BB_EVAL 500 # ADD_SEED_TO_FILE_NAMES no -# STATS_FILE front.txt OBJ +STATS_FILE front.txt OBJ # HISTORY_FILE history.txt DISPLAY_STATS BBE ( SOL ) OBJ diff --git a/examples/basic/batch/bi_obj/runExample.log b/examples/basic/batch/bi_obj/runExample.log index c88b554..76994f3 100644 --- a/examples/basic/batch/bi_obj/runExample.log +++ b/examples/basic/batch/bi_obj/runExample.log @@ -1,7 +1,7 @@ -NOMAD - version 3.6.1 - www.gerad.ca/nomad +NOMAD - version 3.7.2 - www.gerad.ca/nomad -Copyright (C) 2001-2013 { +Copyright (C) 2001-2015 { Mark A. Abramson - The Boeing Company Charles Audet - Ecole Polytechnique de Montreal Gilles Couture - Ecole Polytechnique de Montreal @@ -21,21 +21,21 @@ Please report bugs to nomad@gerad.ca multi-MADS run { - MADS run 1 ...... OK [bb eval= 64] [overall bb eval= 64] [# dominant pts= 5] [# new pts= 5] [f1=0 f2=8.036326991] - MADS run 2 ...... OK [bb eval= 32] [overall bb eval= 96] [# dominant pts= 12] [# new pts= 7] [f1=0.5676487984 f2=0.1148721239] - MADS run 3 ...... OK [bb eval= 32] [overall bb eval= 128] [# dominant pts= 15] [# new pts= 3] [f1=0 f2=1] - MADS run 4 ...... OK [bb eval= 32] [overall bb eval= 160] [# dominant pts= 25] [# new pts= 10] [f1=0.08125 f2=0.9210041574] - MADS run 5 ...... OK [bb eval= 32] [overall bb eval= 192] [# dominant pts= 37] [# new pts= 12] [f1=0.5164769234 f2=0.5254339031] - MADS run 6 ...... OK [bb eval= 32] [overall bb eval= 224] [# dominant pts= 51] [# new pts= 14] [f1=0.4954991402 f2=0.8104114832] - MADS run 7 ...... OK [bb eval= 32] [overall bb eval= 256] [# dominant pts= 58] [# new pts= 7] [f1=0.4887608589 f2=0.8973446571] - MADS run 8 ...... OK [bb eval= 32] [overall bb eval= 288] [# dominant pts= 65] [# new pts= 7] [f1=0.4876866402 f2=0.9106878852] - MADS run 9 ...... OK [bb eval= 32] [overall bb eval= 320] [# dominant pts= 71] [# new pts= 6] [f1=0.08327636719 f2=0.9208860571] - MADS run 10 ...... OK [bb eval= 32] [overall bb eval= 352] [# dominant pts= 77] [# new pts= 6] [f1=0.08300170898 f2=0.9208857342] - MADS run 11 ...... OK [bb eval= 32] [overall bb eval= 384] [# dominant pts= 83] [# new pts= 6] [f1=0.08300170898 f2=0.9208857342] - MADS run 12 ...... OK [bb eval= 32] [overall bb eval= 416] [# dominant pts= 93] [# new pts= 10] [f1=0.4872792305 f2=0.9157055455] - MADS run 13 ...... OK [bb eval= 32] [overall bb eval= 448] [# dominant pts= 100] [# new pts= 7] [f1=0.487021357 f2=0.9188689839] - MADS run 14 ...... OK [bb eval= 32] [overall bb eval= 480] [# dominant pts= 108] [# new pts= 8] [f1=0.4869359077 f2=0.9202170697] - MADS run 15 ...... OK [bb eval= 20] [overall bb eval= 500] [# dominant pts= 112] [# new pts= 4] [f1=0.08319091797 f2=0.9208854025] + MADS run 1 ...... OK [bb eval= 64] [overall bb eval= 64] [# dominant pts= 10] [# new pts= 10] [f1=0 f2=6.231313115] + MADS run 2 ...... OK [bb eval= 32] [overall bb eval= 96] [# dominant pts= 15] [# new pts= 5] [f1=0.8169729819 f2=-0.479260869] + MADS run 3 ...... OK [bb eval= 32] [overall bb eval= 128] [# dominant pts= 14] [# new pts= -1] [f1=0 f2=1] + MADS run 4 ...... OK [bb eval= 32] [overall bb eval= 160] [# dominant pts= 25] [# new pts= 11] [f1=0.5612660076 f2=0.1239843648] + MADS run 5 ...... OK [bb eval= 32] [overall bb eval= 192] [# dominant pts= 33] [# new pts= 8] [f1=0.3137786342 f2=0.5879263396] + MADS run 6 ...... OK [bb eval= 32] [overall bb eval= 224] [# dominant pts= 47] [# new pts= 14] [f1=0.7805127885 f2=-0.1507861609] + MADS run 7 ...... OK [bb eval= 32] [overall bb eval= 256] [# dominant pts= 54] [# new pts= 7] [f1=0.5299157655 f2=0.357255587] + MADS run 8 ...... OK [bb eval= 32] [overall bb eval= 288] [# dominant pts= 66] [# new pts= 12] [f1=0.07954951288 f2=0.9213144638] + MADS run 9 ...... OK [bb eval= 32] [overall bb eval= 320] [# dominant pts= 76] [# new pts= 10] [f1=0.2748325185 f2=0.7638619206] + MADS run 10 ...... OK [bb eval= 32] [overall bb eval= 352] [# dominant pts= 85] [# new pts= 9] [f1=0.5181766881 f2=0.5029223883] + MADS run 11 ...... OK [bb eval= 32] [overall bb eval= 384] [# dominant pts= 89] [# new pts= 4] [f1=0.7680831771 f2=0.07286356753] + MADS run 12 ...... OK [bb eval= 32] [overall bb eval= 416] [# dominant pts= 99] [# new pts= 10] [f1=0.5151038119 f2=0.5437967797] + MADS run 13 ...... OK [bb eval= 32] [overall bb eval= 448] [# dominant pts= 111] [# new pts= 12] [f1=0.2592955042 f2=0.8727383732] + MADS run 14 ...... OK [bb eval= 32] [overall bb eval= 480] [# dominant pts= 117] [# new pts= 6] [f1=0.5684216658 f2=0.1147587127] + MADS run 15 ...... OK [bb eval= 20] [overall bb eval= 500] [# dominant pts= 120] [# new pts= 3] [f1=0.5684216658 f2=0.1147587127] } end of run (max number of bb evaluations) @@ -46,117 +46,125 @@ number of MADS runs : 15 Pareto front { BBE ( 0.0000000000 0.0000000000 ) 0.0000000000 1.0000000000 - BBE ( 0.0000962840 0.0000000000 ) 0.0000962840 0.9999997577 - BBE ( 0.0003906250 0.0000000000 ) 0.0003906250 0.9999960125 - BBE ( 0.0031250000 0.0000000000 ) 0.0031250000 0.9997450497 - BBE ( 0.0046875000 0.0000000000 ) 0.0046875000 0.9994270708 - BBE ( 0.0250000000 0.0000000000 ) 0.0250000000 0.9846803687 - BBE ( 0.0500000000 0.0000000000 ) 0.0500000000 0.9499471742 - BBE ( 0.0546875000 0.0000000000 ) 0.0546875000 0.9433725823 - BBE ( 0.0580017090 0.0000000000 ) 0.0580017090 0.9390043666 - BBE ( 0.0582763672 0.0000000000 ) 0.0582763672 0.9386555226 - BBE ( 0.0593750000 0.0000000000 ) 0.0593750000 0.9372826427 - BBE ( 0.0625000000 0.0000000000 ) 0.0625000000 0.9335937500 - BBE ( 0.0687500000 0.0000000000 ) 0.0687500000 0.9273698641 - BBE ( 0.0705017090 0.0000000000 ) 0.0705017090 0.9259486581 - BBE ( 0.0707763672 0.0000000000 ) 0.0707763672 0.9257399750 - BBE ( 0.0718750000 0.0000000000 ) 0.0718750000 0.9249448963 - BBE ( 0.0734375000 0.0000000000 ) 0.0734375000 0.9239266272 - BBE ( 0.0750000000 0.0000000000 ) 0.0750000000 0.9230457613 - BBE ( 0.0765625000 0.0000000000 ) 0.0765625000 0.9223079094 - BBE ( 0.0767517090 0.0000000000 ) 0.0767517090 0.9222285264 - BBE ( 0.0770263672 0.0000000000 ) 0.0770263672 0.9221171830 - BBE ( 0.0781250000 0.0000000000 ) 0.0781250000 0.9217183959 - BBE ( 0.0796875000 0.0000000000 ) 0.0796875000 0.9212822432 - BBE ( 0.0798767090 0.0000000000 ) 0.0798767090 0.9212400670 - BBE ( 0.0799804688 0.0000000000 ) 0.0799804688 0.9212179253 - BBE ( 0.0800781250 0.0000000000 ) 0.0800781250 0.9211977263 - BBE ( 0.0801513672 0.0000000000 ) 0.0801513672 0.9211829851 - BBE ( 0.0812500000 0.0000000000 ) 0.0812500000 0.9210041574 - BBE ( 0.0817016602 0.0000000000 ) 0.0817016602 0.9209538533 - BBE ( 0.0818115234 0.0000000000 ) 0.0818115234 0.9209436812 - BBE ( 0.0821777344 0.0000000000 ) 0.0821777344 0.9209156366 - BBE ( 0.0825134277 0.0000000000 ) 0.0825134277 0.9208978855 - BBE ( 0.0825927734 0.0000000000 ) 0.0825927734 0.9208948063 - BBE ( 0.0827270508 0.0000000000 ) 0.0827270508 0.9208905705 - BBE ( 0.0828674316 0.0000000000 ) 0.0828674316 0.9208874553 - BBE ( 0.0830017090 0.0000000000 ) 0.0830017090 0.9208857342 - BBE ( 0.0830135345 0.0000000000 ) 0.0830135345 0.9208856417 - BBE ( 0.0830490112 0.0000000000 ) 0.0830490112 0.9208854215 - BBE ( 0.0831909180 0.0000000000 ) 0.0831909180 0.9208854025 - BBE ( 0.4868870796 0.0000000000 ) 0.4868870796 0.9205123238 - BBE ( 0.4868992866 0.0000061035 ) 0.4868992866 0.9204385441 - BBE ( 0.4869359077 0.0000244141 ) 0.4869359077 0.9202170697 - BBE ( 0.4870213570 0.0000000000 ) 0.4870213570 0.9188689839 - BBE ( 0.4870335640 0.0000061035 ) 0.4870335640 0.9187949686 - BBE ( 0.4871007027 0.0000000000 ) 0.4871007027 0.9178966625 - BBE ( 0.4871129097 0.0000000000 ) 0.4871129097 0.9177469920 - BBE ( 0.4871617378 0.0000000000 ) 0.4871617378 0.9171480902 - BBE ( 0.4872052254 0.0000177383 ) 0.4872052254 0.9168338789 - BBE ( 0.4872288765 0.0000000000 ) 0.4872288765 0.9163240271 - BBE ( 0.4872777046 0.0000000000 ) 0.4872777046 0.9157242928 - BBE ( 0.4872792305 0.0000000000 ) 0.4872792305 0.9157055455 - BBE ( 0.4872960152 0.0000000000 ) 0.4872960152 0.9154993024 - BBE ( 0.4873021187 0.0000030518 ) 0.4873021187 0.9154620588 - BBE ( 0.4873078407 0.0000000000 ) 0.4873078407 0.9153539700 - BBE ( 0.4873631538 0.0000000000 ) 0.4873631538 0.9146739180 - BBE ( 0.4874119820 0.0000000000 ) 0.4874119820 0.9140732253 - BBE ( 0.4876378120 0.0000000000 ) 0.4876378120 0.9112905197 - BBE ( 0.4876866402 0.0000000000 ) 0.4876866402 0.9106878852 - BBE ( 0.4880589546 0.0003417969 ) 0.4880589546 0.9103109499 - BBE ( 0.4880772652 0.0000000000 ) 0.4880772652 0.9058545422 - BBE ( 0.4884251655 0.0000000000 ) 0.4884251655 0.9015317160 - BBE ( 0.4887608589 0.0000000000 ) 0.4887608589 0.8973446571 - BBE ( 0.4888585152 0.0000000000 ) 0.4888585152 0.8961237074 - BBE ( 0.4892491402 0.0000000000 ) 0.4892491402 0.8912270369 - BBE ( 0.4892796577 0.0000000000 ) 0.4892796577 0.8908436249 - BBE ( 0.4895237984 0.0000000000 ) 0.4895237984 0.8877718960 - BBE ( 0.4898655952 0.0000000000 ) 0.4898655952 0.8834583797 - BBE ( 0.4899144234 0.0000000000 ) 0.4899144234 0.8828409301 - BBE ( 0.4900120796 0.0000000000 ) 0.4900120796 0.8816051142 - BBE ( 0.4901463570 0.0000000000 ) 0.4901463570 0.8799038821 - BBE ( 0.4904210152 0.0000000000 ) 0.4904210152 0.8764169969 - BBE ( 0.4908116402 0.0000000000 ) 0.4908116402 0.8714417071 - BBE ( 0.4910862984 0.0000000000 ) 0.4910862984 0.8679322951 - BBE ( 0.4915745796 0.0000000000 ) 0.4915745796 0.8616710988 - BBE ( 0.4917088570 0.0000000000 ) 0.4917088570 0.8599443688 - BBE ( 0.4919835152 0.0000000000 ) 0.4919835152 0.8564059578 - BBE ( 0.4926487984 0.0000000000 ) 0.4926487984 0.8477999690 - BBE ( 0.4927464546 0.0000000000 ) 0.4927464546 0.8465326082 - BBE ( 0.4942112984 0.0000000000 ) 0.4942112984 0.8274026124 - BBE ( 0.4946751655 0.0000000000 ) 0.4946751655 0.8213002814 - BBE ( 0.4951146187 0.0002746582 ) 0.4951146187 0.8189185849 - BBE ( 0.4954991402 0.0000000000 ) 0.4954991402 0.8104114832 - BBE ( 0.4957737984 0.0000000000 ) 0.4957737984 0.8067685071 - BBE ( 0.4961155952 0.0000000000 ) 0.4961155952 0.8022260697 - BBE ( 0.4961644234 0.0000000000 ) 0.4961644234 0.8015763555 - BBE ( 0.4969456734 0.0003417969 ) 0.4969456734 0.7954140614 - BBE ( 0.4988987984 0.0000000000 ) 0.4988987984 0.7649058572 - BBE ( 0.5001866402 0.0000000000 ) 0.5001866402 0.7474670688 - BBE ( 0.5004612984 0.0000000000 ) 0.5004612984 0.7437364245 - BBE ( 0.5035862984 0.0000000000 ) 0.5035862984 0.7010722736 - BBE ( 0.5055394234 0.0000000000 ) 0.5055394234 0.6742753824 - BBE ( 0.5098362984 0.0000000000 ) 0.5098362984 0.6153085893 - BBE ( 0.5118870796 0.0000000000 ) 0.5118870796 0.5873076456 - BBE ( 0.5120213570 0.0000000000 ) 0.5120213570 0.5854800910 - BBE ( 0.5122960152 0.0000000000 ) 0.5122960152 0.5817445301 - BBE ( 0.5129612984 0.0000000000 ) 0.5129612984 0.5727116847 - BBE ( 0.5133519234 0.0000000000 ) 0.5133519234 0.5674189894 - BBE ( 0.5145237984 0.0000000000 ) 0.5145237984 0.5515953642 - BBE ( 0.5160862984 0.0000000000 ) 0.5160862984 0.5306427628 - BBE ( 0.5164769234 0.0000000000 ) 0.5164769234 0.5254339031 - BBE ( 0.5168675484 0.0000000000 ) 0.5168675484 0.5202377465 - BBE ( 0.5176487984 0.0000000000 ) 0.5176487984 0.5098855127 - BBE ( 0.5207737984 0.0000000000 ) 0.5207737984 0.4690828690 - BBE ( 0.5289769234 0.0000000000 ) 0.5289769234 0.3681074167 - BBE ( 0.5410862984 0.0000000000 ) 0.5410862984 0.2426270547 - BBE ( 0.5457737984 0.0000000000 ) 0.5457737984 0.2038744975 - BBE ( 0.5535862984 0.0000000000 ) 0.5535862984 0.1537894775 - BBE ( 0.5551487984 0.0000000000 ) 0.5551487984 0.1461090174 - BBE ( 0.5582737984 0.0000000000 ) 0.5582737984 0.1332027875 - BBE ( 0.5645237984 0.0000000000 ) 0.5645237984 0.1175191667 - BBE ( 0.5660862984 0.0000000000 ) 0.5660862984 0.1157579047 - BBE ( 0.5676487984 0.0000000000 ) 0.5676487984 0.1148721239 + BBE ( 0.0027621359 0.0000000000 ) 0.0027621359 0.9998007770 + BBE ( 0.0088388348 0.0000000000 ) 0.0088388348 0.9979744889 + BBE ( 0.0132582521 0.0000000000 ) 0.0132582521 0.9954876562 + BBE ( 0.0353553391 0.0000000000 ) 0.0353553391 0.9713080680 + BBE ( 0.0441941738 0.0000000000 ) 0.0441941738 0.9584480584 + BBE ( 0.0574524260 0.0000000000 ) 0.0574524260 0.9397084727 + BBE ( 0.0618718434 0.0000000000 ) 0.0618718434 0.9343077419 + BBE ( 0.0707106781 0.0000000000 ) 0.0707106781 0.9257895286 + BBE ( 0.0729203868 0.0000000000 ) 0.0729203868 0.9242486972 + BBE ( 0.0734728140 0.0000000000 ) 0.0734728140 0.9239051795 + BBE ( 0.0765111634 0.0000000000 ) 0.0765111634 0.9223298234 + BBE ( 0.0783065517 0.0000000000 ) 0.0783065517 0.9216597507 + BBE ( 0.0795495129 0.0000000000 ) 0.0795495129 0.9213144638 + BBE ( 0.0801709935 0.0000000000 ) 0.0801709935 0.9211790945 + BBE ( 0.0804989971 0.0000000000 ) 0.0804989971 0.9211178038 + BBE ( 0.0814830080 0.0000000000 ) 0.0814830080 0.9209765043 + BBE ( 0.0839689303 0.0000000000 ) 0.0839689303 0.9209099136 + BBE ( 0.2546689267 0.0000000000 ) 0.2546689267 0.9053286734 + BBE ( 0.2554285140 0.0000000000 ) 0.2554285140 0.9000152969 + BBE ( 0.2559809412 0.0000000000 ) 0.2559809412 0.8961400979 + BBE ( 0.2592955042 0.0000000000 ) 0.2592955042 0.8727383732 + BBE ( 0.2601241450 0.0002762136 ) 0.2601241450 0.8698079048 + BBE ( 0.2624029071 0.0011048543 ) 0.2624029071 0.8624679573 + BBE ( 0.2633006012 0.0008286408 ) 0.2633006012 0.8531427520 + BBE ( 0.2634387080 0.0001898968 ) 0.2634387080 0.8453357823 + BBE ( 0.2635077614 0.0000000000 ) 0.2635077614 0.8428146572 + BBE ( 0.2643364022 0.0000000000 ) 0.2643364022 0.8369299127 + BBE ( 0.2673747516 0.0000000000 ) 0.2673747516 0.8154302217 + BBE ( 0.2679271788 0.0000000000 ) 0.2679271788 0.8115410603 + BBE ( 0.2695844603 0.0000000000 ) 0.2695844603 0.7999251464 + BBE ( 0.2740038777 0.0022097087 ) 0.2740038777 0.7931862207 + BBE ( 0.2748325185 0.0000000000 ) 0.2748325185 0.7638619206 + BBE ( 0.2762135864 0.0002762136 ) 0.2762135864 0.7575848978 + BBE ( 0.2773184407 0.0000000000 ) 0.2773184407 0.7473019205 + BBE ( 0.2828427125 0.0000000000 ) 0.2828427125 0.7121565043 + BBE ( 0.2872621299 0.0000000000 ) 0.2872621299 0.6860941024 + BBE ( 0.2900242657 0.0000000000 ) 0.2900242657 0.6709156096 + BBE ( 0.2961009646 0.0000000000 ) 0.2961009646 0.6410185691 + BBE ( 0.3005203820 0.0000000000 ) 0.3005203820 0.6226855524 + BBE ( 0.3016252363 0.0000000000 ) 0.3016252363 0.6185926969 + BBE ( 0.3088067896 0.0000000000 ) 0.3088067896 0.5971609072 + BBE ( 0.3093592168 0.0000000000 ) 0.3093592168 0.5959009619 + BBE ( 0.3137786342 0.0000000000 ) 0.3137786342 0.5879263396 + BBE ( 0.3165407700 0.0000000000 ) 0.3165407700 0.5848920973 + BBE ( 0.3167479302 0.0000000000 ) 0.3167479302 0.5847262751 + BBE ( 0.3176456244 0.0000000000 ) 0.3176456244 0.5841081818 + BBE ( 0.3181980515 0.0000000000 ) 0.3181980515 0.5838092475 + BBE ( 0.3226174689 0.0000000000 ) 0.3226174689 0.5836743517 + BBE ( 0.5127214698 0.0000000000 ) 0.5127214698 0.5759653136 + BBE ( 0.5137572707 0.0002762136 ) 0.5137572707 0.5654252540 + BBE ( 0.5140334843 0.0000000000 ) 0.5140334843 0.5582055541 + BBE ( 0.5150347585 0.0000172633 ) 0.5150347585 0.5449424207 + BBE ( 0.5151038119 0.0000000000 ) 0.5151038119 0.5437967797 + BBE ( 0.5153886572 0.0000000000 ) 0.5153886572 0.5399756398 + BBE ( 0.5165194066 0.0000000000 ) 0.5165194066 0.5248681601 + BBE ( 0.5169337269 0.0000000000 ) 0.5169337269 0.5193587219 + BBE ( 0.5173135206 0.0000000000 ) 0.5173135206 0.5143215129 + BBE ( 0.5179004745 0.0002762136 ) 0.5179004745 0.5100634344 + BBE ( 0.5181076347 0.0000690534 ) 0.5181076347 0.5047074913 + BBE ( 0.5181766881 0.0000000000 ) 0.5181766881 0.5029223883 + BBE ( 0.5183147949 0.0000000000 ) 0.5183147949 0.5011051160 + BBE ( 0.5192124890 0.0000000000 ) 0.5192124890 0.4893395607 + BBE ( 0.5203173434 0.0002762136 ) 0.5203173434 0.4784843660 + BBE ( 0.5211459841 0.0010358009 ) 0.5211459841 0.4774378717 + BBE ( 0.5214912511 0.0000000000 ) 0.5214912511 0.4598694955 + BBE ( 0.5228723191 0.0000000000 ) 0.5228723191 0.4423168011 + BBE ( 0.5261868821 0.0000000000 ) 0.5261868821 0.4012836645 + BBE ( 0.5272917364 0.0000000000 ) 0.5272917364 0.3879862090 + BBE ( 0.5292252315 0.0000000000 ) 0.5292252315 0.3652213546 + BBE ( 0.5299157655 0.0000000000 ) 0.5299157655 0.3572555870 + BBE ( 0.5303300859 0.0000000000 ) 0.5303300859 0.3525194343 + BBE ( 0.5317111538 0.0000000000 ) 0.5317111538 0.3369744453 + BBE ( 0.5350257169 0.0000000000 ) 0.5350257169 0.3012827434 + BBE ( 0.5358543576 0.0000000000 ) 0.5358543576 0.2927387374 + BBE ( 0.5361305712 0.0000000000 ) 0.5361305712 0.2899259708 + BBE ( 0.5391689207 0.0000000000 ) 0.5391689207 0.2601947270 + BBE ( 0.5480077554 0.0000000000 ) 0.5480077554 0.1876299330 + BBE ( 0.5513223185 0.0000000000 ) 0.5513223185 0.1663336683 + BBE ( 0.5535320271 0.0000000000 ) 0.5535320271 0.1540707094 + BBE ( 0.5557417358 0.0000000000 ) 0.5557417358 0.1434067848 + BBE ( 0.5568465902 0.0000000000 ) 0.5568465902 0.1386867395 + BBE ( 0.5590562989 0.0000000000 ) 0.5590562989 0.1304923502 + BBE ( 0.5604373668 0.0000000000 ) 0.5604373668 0.1262254672 + BBE ( 0.5612660076 0.0000000000 ) 0.5612660076 0.1239843648 + BBE ( 0.5620687533 0.0000000000 ) 0.5620687533 0.1220429764 + BBE ( 0.5640022484 0.0000000000 ) 0.5640022484 0.1183011565 + BBE ( 0.5645805706 0.0000000000 ) 0.5645805706 0.1174398964 + BBE ( 0.5652020512 0.0000000000 ) 0.5652020512 0.1166473780 + BBE ( 0.5654092114 0.0000000000 ) 0.5654092114 0.1164138826 + BBE ( 0.5656854249 0.0000000000 ) 0.5656854249 0.1161264470 + BBE ( 0.5659616385 0.0000000000 ) 0.5659616385 0.1158663392 + BBE ( 0.5666866992 0.0000000000 ) 0.5666866992 0.1153137493 + BBE ( 0.5669024911 0.0000000000 ) 0.5669024911 0.1151857400 + BBE ( 0.5674462866 0.0000000000 ) 0.5674462866 0.1149374124 + BBE ( 0.5684216658 0.0000000000 ) 0.5684216658 0.1147587127 + BBE ( 0.7661496820 0.0000000000 ) 0.7661496820 0.1105136967 + BBE ( 0.7669783228 0.0000000000 ) 0.7669783228 0.0943075051 + BBE ( 0.7680831771 0.0000000000 ) 0.7680831771 0.0728635675 + BBE ( 0.7691880314 0.0000000000 ) 0.7691880314 0.0516220389 + BBE ( 0.7694642450 0.0000000000 ) 0.7694642450 0.0463451418 + BBE ( 0.7704309926 0.0007941141 ) 0.7704309926 0.0406045540 + BBE ( 0.7705690994 0.0000000000 ) 0.7705690994 0.0253788803 + BBE ( 0.7738836624 0.0000000000 ) 0.7738836624 -0.0360307769 + BBE ( 0.7741598760 0.0000000000 ) 0.7741598760 -0.0410385581 + BBE ( 0.7758171575 0.0000000000 ) 0.7758171575 -0.0706993622 + BBE ( 0.7760933711 0.0000000000 ) 0.7760933711 -0.0755763386 + BBE ( 0.7766457983 0.0000000000 ) 0.7766457983 -0.0852712175 + BBE ( 0.7771982255 0.0000000000 ) 0.7771982255 -0.0948858036 + BBE ( 0.7805127885 0.0000000000 ) 0.7805127885 -0.1507861609 + BBE ( 0.7816176428 0.0004488471 ) 0.7816176428 -0.1614780263 + BBE ( 0.7849322059 0.0000000000 ) 0.7849322059 -0.2200658533 + BBE ( 0.7854846330 0.0000000000 ) 0.7854846330 -0.2282658189 + BBE ( 0.7882467689 0.0000000000 ) 0.7882467689 -0.2676209257 + BBE ( 0.7937710406 0.0000000000 ) 0.7937710406 -0.3375181059 + BBE ( 0.7948758950 0.0000000000 ) 0.7948758950 -0.3499937714 + BBE ( 0.7970856037 0.0000000000 ) 0.7970856037 -0.3733607572 + BBE ( 0.8059244384 0.0000000000 ) 0.8059244384 -0.4444581650 + BBE ( 0.8103438558 0.0000000000 ) 0.8103438558 -0.4658115097 + BBE ( 0.8169729819 0.0000000000 ) 0.8169729819 -0.4792608690 } -number of Pareto points: 112 +number of Pareto points: 120 diff --git a/examples/basic/batch/single_obj/runExample.log b/examples/basic/batch/single_obj/runExample.log index 85fbaec..129534c 100644 --- a/examples/basic/batch/single_obj/runExample.log +++ b/examples/basic/batch/single_obj/runExample.log @@ -1,7 +1,7 @@ -NOMAD - version 3.6.1 - www.gerad.ca/nomad +NOMAD - version 3.7.2 - www.gerad.ca/nomad -Copyright (C) 2001-2013 { +Copyright (C) 2001-2015 { Mark A. Abramson - The Boeing Company Charles Audet - Ecole Polytechnique de Montreal Gilles Couture - Ecole Polytechnique de Montreal @@ -23,15 +23,21 @@ MADS run { BBE ( SOL ) OBJ - 2 ( 1.1000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 275.2281000000 (PhaseOne) - 3 ( 4.4000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 0.0000000000 (PhaseOne) - 3 ( 4.4000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 0.0000000000 - 11 ( 4.6750000000 0.9000000000 0.9750000000 1.5000000000 -1.5000000000 ) -1.5000000000 - 55 ( 1.6500000000 1.8000000000 1.9500000000 -1.5000000000 -3.0000000000 ) -3.0000000000 - 100 ( 1.6500000000 1.8000000000 1.9500000000 -1.5000000000 -3.0000000000 ) -3.0000000000 + 2 ( 0.0000000000 0.5366563146 0.5813776741 -0.2683281573 0.2683281573 ) 288.7926372100 (PhaseOne) + 3 ( 0.0000000000 2.1466252584 2.3255106966 -1.0733126292 1.0733126292 ) 0.0000000000 (PhaseOne) + 3 ( 0.0000000000 2.1466252584 2.3255106966 -1.0733126292 1.0733126292 ) 1.0733100000 + 10 ( 0.4919349550 2.8174456516 2.1801662781 -0.8720665112 1.0062305899 ) 1.0062300000 + 11 ( 1.9677398202 4.8299068314 1.7441330224 -0.2683281573 0.8049844719 ) 0.8049840000 + 13 ( 0.0000000000 1.6099689438 2.9068883707 -0.8049844719 0.5366563146 ) 0.5366560000 + 17 ( 3.5241951349 1.7067494832 0.5813776741 -0.5366563146 0.2683281573 ) 0.2683280000 + 28 ( 2.0483902697 -2.5865010336 3.4882660449 1.8782971011 0.0000000000 ) 0.0000000000 + 67 ( 2.0483902697 1.7067494832 2.3255106966 -0.5366563146 -2.4149534157 ) -2.4149500000 + 86 ( 3.0322601798 0.6334368540 0.0000000000 2.6832815730 -2.9516097303 ) -2.9516100000 + 96 ( 1.5564553147 1.7067494832 -0.5813776741 1.6099689438 -3.4882660449 ) -3.4882700000 + 100 ( 1.5564553147 1.7067494832 -0.5813776741 1.6099689438 -3.4882660449 ) -3.4882700000 } end of run (max number of blackbox evaluations) blackbox evaluations : 100 -best infeasible solution (min. violation): ( 1.65 1.8 2.6 -1.5 -3 ) h=0.8725 f=-3 -best feasible solution : ( 1.65 1.8 1.95 -1.5 -3 ) h=0 f=-3 +best infeasible solution (min. violation): ( -0.9032194606 -0.4398757752 4.069643719 -0.2683281573 -1.878297101 ) h=0.0114496 f=-1.8783 +best feasible solution : ( 1.556455315 1.706749483 -0.5813776741 1.609968944 -3.488266045 ) h=0 f=-3.48827 diff --git a/examples/basic/batch/single_obj_parallel/bb.cpp b/examples/basic/batch/single_obj_parallel/bb.cpp new file mode 100644 index 0000000..2c3bf75 --- /dev/null +++ b/examples/basic/batch/single_obj_parallel/bb.cpp @@ -0,0 +1,31 @@ +#include <cmath> +#include <iostream> +#include <fstream> +#include <cstdlib> +using namespace std; + +int main ( int argc , char ** argv ) { + + double f = 1e20, c1 = 1e20 , c2 = 1e20; + double x[5]; + + if ( argc >= 2 ) { + c1 = 0.0 , c2 = 0.0; + ifstream in ( argv[1] ); + for ( int i = 0 ; i < 5 ; i++ ) { + in >> x[i]; + c1 += pow ( x[i]-1 , 2 ); + c2 += pow ( x[i]+1 , 2 ); + } + f = x[4]; + if ( in.fail() ) + f = c1 = c2 = 1e20; + else { + c1 = c1 - 25; + c2 = 25 - c2; + } + in.close(); + } + cout << f << " " << c1 << " " << c2 << endl; + return 0; +} diff --git a/examples/basic/batch/single_obj_parallel/bb_parallel.cpp b/examples/basic/batch/single_obj_parallel/bb_parallel.cpp new file mode 100644 index 0000000..c17a350 --- /dev/null +++ b/examples/basic/batch/single_obj_parallel/bb_parallel.cpp @@ -0,0 +1,113 @@ +#include <cmath> +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <vector> +#include <pthread.h> +#include <semaphore.h> + +using namespace std; + +// Number of threads to be used in parallel +#define NUM_THREADS 4 + +static void * eval_x ( void * dummy_eval_arg ) +{ + + double c1 = 0.0 , c2 = 0.0 ,f; + double * x = static_cast<double *>(dummy_eval_arg); + for ( int i = 0 ; i < 5 ; i++) + { + c1 += pow ( x[i]-1 , 2 ); + c2 += pow ( x[i]+1 , 2 ); + } + x[5]= x[4]; + x[6] = c1 - 25; + x[7] = 25 - c2; + + // cout << x[0] << " " << x[1] <<" " << x[2] <<" "<< x[3] <<" "<< x[4] << " " << x[5] << " " << x[6] << " " << x[7] << endl; + + pthread_exit(NULL); + +} + + + +int main ( int argc , char ** argv ) + { + + double f = 1e20, c1 = 1e20 , c2 = 1e20; + std::vector< double * > X; + + if ( argc >= 2 ) + { + + ifstream in ( argv[1] ); + + while( ! in.eof() ) + { + double *x = new double [8]; + for ( int i = 0 ; i < 5 ; i++ ) + in >> x[i]; + + X.push_back(x); + + //char c; + // in >> c; + + // cout << x[0] << " " << x[1] <<endl; + + } + in.close(); + X.pop_back(); + + int nb_pts=X.size(); + + // All threads are created + pthread_t threads[nb_pts]; + + // The semaphore will allow to run NUM_THREADS in parallel + sem_t *mySemaphore; + mySemaphore=sem_open("sem",0,NUM_THREADS); + + // The list of points is evaluated under the control of a semaphore + int i=0; + for (std::vector< double * >::iterator it_x=X.begin(); it_x!=X.end(); ++it_x,++i) + { + // cout << (*it_x)[0] << " " << (*it_x)[1] << " " << (*it_x)[2] << endl; + int rc=pthread_create(&threads[i], NULL, eval_x,(*it_x)); + if (rc) + { + cout << "Error:unable to create thread," << rc << endl; + return false; + } + // wait until value of semaphore is greater than 0 + // decrement the value of semaphore by 1 + sem_wait(mySemaphore); + + } + + int ret; + + // cout << nb_pts << endl; + for (i=0; i<nb_pts; ++i) + { + // Wait for all the threads to finish + ret=pthread_join(threads[i],0); + if (ret!=0) + { + perror("pthread join has failed"); + return false; + } + cout << (X[i])[5] << " " << (X[i])[6] << " " << (X[i])[7] << endl; + delete [](X[i]); + } + + sem_unlink("sem"); + + + } + + return 0; + +} diff --git a/examples/basic/batch/single_obj_parallel/parallel_BBWrapper.pl b/examples/basic/batch/single_obj_parallel/parallel_BBWrapper.pl new file mode 100755 index 0000000..1de8132 --- /dev/null +++ b/examples/basic/batch/single_obj_parallel/parallel_BBWrapper.pl @@ -0,0 +1,117 @@ +#!/usr/bin/perl +# use strict; +use warnings; + +use Data::Dumper; + +use threads; +use threads::shared; +use Thread::Semaphore; + + +# quelques variables partagées +my $BBdotEXE:shared="./bb.exe"; ## The blackbox executable + +my $numberParallelJobs:shared=4; +my $semaphoreBBEval = Thread::Semaphore->new($numberParallelJobs); + + +if ( ! exists $ARGV[0]) { + $nameInputFile = ""; +} else { + $nameInputFile = $ARGV[0]; +} + +sub OneEvalBB($$$$$){ + my $x = shift; + my $index = shift; + my $completedEval = shift; + my $sema_ref = shift; + my $output = shift; + + + + my $input_file_name=""; + #if ($index > 3) { # arbitrarily reject evaluation with index > 3!!!!! THIS IS NOT A GOOF THING TO DO + # $$output="REJECT\n"; + #} else { + + # write single evaluation input file + $input_file_name="x.$$.$index.txt"; + open(SINGLE_INPUT_FILE,"> $input_file_name"); + print SINGLE_INPUT_FILE "$x \n"; + close(SINGLE_INPUT_FILE); + + + # start single evaluation and get output + open(OUTPUT_I,"$BBdotEXE $input_file_name |") ; # or die "Can't run blackbox executable: $!\n"; + $$output=<OUTPUT_I>; + close(OUTPUT_I); + #} + + + $$completedEval++; + + # on a une place de libre. Ne pas oublier de libérer le sémaphore même en cas d'erreur + $$sema_ref->up(); + + if ( -e $input_file_name) { + unlink $input_file_name ; + } + + return; +} + +open(LIST_INPUT_FILE,"$ARGV[0]") or die "Can't open input file: $ARGV[0]\n"; +@X = <LIST_INPUT_FILE>; +my $started = 0; +my $completedBBEval:shared =0; +my @output:shared; + +my @thrList= (); + + + +# démarre tous les jobs +while ( $started < scalar @X ){ + + my $x=$X[$started]; + + $started++; + + # avons nous une place de libre ? + $semaphoreBBEval->down(); + + # si le sémaphore est a 0, le processus principal va se bloquer en attendant une nouvelle place + my $thr= threads->create("OneEvalBB", ( + $x, + $started, + \$completedBBEval, + \$semaphoreBBEval, + \$output[$started-1] + ) + ); + + push(@thrList,$thr); + + # détache le job du thread principal, rend la main au thread principal + $thr->detach(); + +} + + +# attend les derniers jobs +while ( @thrList ){ + sleep(0.01); + + my $r=0; + foreach $thr (@thrList) + { + if ( $thr->is_running() ) { + $r=1; + last; + } + } + last if ($r==0); +} +print "@output"; diff --git a/examples/basic/batch/single_obj_parallel/param.txt b/examples/basic/batch/single_obj_parallel/param.txt new file mode 100644 index 0000000..bd84342 --- /dev/null +++ b/examples/basic/batch/single_obj_parallel/param.txt @@ -0,0 +1,20 @@ +DIMENSION 5 # number of variables + +BB_EXE "$perl parallel_BBWrapper.pl" +# BB_EXE bb_parallel.exe +BB_MAX_BLOCK_SIZE 2 + +BB_OUTPUT_TYPE OBJ PB EB + +X0 ( 0 0 0 0 0 ) # starting point + +LOWER_BOUND * -6.0 # all variables are >= -6 +UPPER_BOUND ( 5 6 7 - - ) # x_1 <= 5, x_2 <= 6, x_3 <= 7 + # x_4 and x_5 have no bounds + +MAX_BB_EVAL 100 # the algorithm terminates when + # 100 black-box evaluations have + # been made + +TMP_DIR /tmp +DISPLAY_DEGREE 2 diff --git a/examples/basic/batch/single_obj_parallel/runExample.log b/examples/basic/batch/single_obj_parallel/runExample.log new file mode 100644 index 0000000..2cad690 --- /dev/null +++ b/examples/basic/batch/single_obj_parallel/runExample.log @@ -0,0 +1,43 @@ +Warning: { + The maximum number of evaluations may be exceeded when BB_MAX_BLOCK_SIZE>1. +} + +NOMAD - version 3.7.2 - www.gerad.ca/nomad + +Copyright (C) 2001-2015 { + Mark A. Abramson - The Boeing Company + Charles Audet - Ecole Polytechnique de Montreal + Gilles Couture - Ecole Polytechnique de Montreal + John E. Dennis, Jr. - Rice University + Sebastien Le Digabel - Ecole Polytechnique de Montreal + Christophe Tribes - Ecole Polytechnique de Montreal +} + +Funded in part by AFOSR and Exxon Mobil. + +License : '$NOMAD_HOME/src/lgpl.txt' +User guide: '$NOMAD_HOME/doc/user_guide.pdf' +Examples : '$NOMAD_HOME/examples' +Tools : '$NOMAD_HOME/tools' + +Please report bugs to nomad@gerad.ca + +MADS run { + + BBE OBJ + + 2 288.7926372100 (PhaseOne) + 3 254.0899760400 (PhaseOne) + 4 0.0000000000 (PhaseOne) + 4 -1.0733100000 + 10 -1.6099700000 + 23 -2.4149500000 + 26 -3.4882700000 + 48 -3.7565900000 + 101 -3.7565900000 + +} end of run (max number of blackbox evaluations) + +blackbox evaluations : 101 +best infeasible solution (min. violation): ( 1.106853649 0.9391485505 1.01741093 1.00623059 -4.024922359 ) h=0.265307 f=-4.02492 +best feasible solution : ( 0.9838699101 0.5366563146 1.744133022 1.341640786 -3.756594202 ) h=0 f=-3.75659 diff --git a/examples/basic/batch/single_obj_parallel/x.txt b/examples/basic/batch/single_obj_parallel/x.txt new file mode 100644 index 0000000..64decd0 --- /dev/null +++ b/examples/basic/batch/single_obj_parallel/x.txt @@ -0,0 +1,4 @@ +1 2 3 4 5 +0 0 0 0 0 +2 2 2 2 2 +5 4 3 2 1 diff --git a/examples/basic/batch/single_obj_parallel/x0.txt b/examples/basic/batch/single_obj_parallel/x0.txt new file mode 100644 index 0000000..f51ebb0 --- /dev/null +++ b/examples/basic/batch/single_obj_parallel/x0.txt @@ -0,0 +1 @@ +0 0 0 0 0 0 diff --git a/examples/basic/library/bi_obj/runExample.log b/examples/basic/library/bi_obj/runExample.log index 511ba6f..368fa2e 100644 --- a/examples/basic/library/bi_obj/runExample.log +++ b/examples/basic/library/bi_obj/runExample.log @@ -1,10 +1,10 @@ multi-MADS run { - MADS run 1 ...... OK [bb eval= 46] [overall bb eval= 46] [# dominant pts= 3] [# new pts= 3] [f1=-6 f2=94.436255] - MADS run 2 ...... OK [bb eval= 23] [overall bb eval= 69] [# dominant pts= 3] [# new pts= 0] [f1=-4.5 f2=16.5199438] - MADS run 3 ...... OK [bb eval= 23] [overall bb eval= 92] [# dominant pts= 3] [# new pts= 0] [f1=-5.25 f2=15.24515131] - MADS run 4 ...... OK [bb eval= 8] [overall bb eval= 100] [# dominant pts= 3] [# new pts= 0] [f1=-5.25 f2=15.24515131] + MADS run 1 ...... OK [bb eval= 46] [overall bb eval= 46] [# dominant pts= 3] [# new pts= 3] [f1=-6 f2=152.5555363] + MADS run 2 ...... OK [bb eval= 23] [overall bb eval= 69] [# dominant pts= 6] [# new pts= 3] [f1=-1.170093169 f2=-7.948136425] + MADS run 3 ...... OK [bb eval= 23] [overall bb eval= 92] [# dominant pts= 8] [# new pts= 2] [f1=-6 f2=27.18734544] + MADS run 4 ...... OK [bb eval= 8] [overall bb eval= 100] [# dominant pts= 9] [# new pts= 1] [f1=-4.390031056 f2=12.07995483] } end of run (max number of bb evaluations) @@ -14,9 +14,15 @@ number of MADS runs : 4 Pareto front { - -6.0000000000 25.1826513073 - -5.2500000000 15.2451513073 - 0.7500000000 12.8461452933 + -6.0000000000 27.1873454385 + -5.4633436854 20.4877802253 + -4.9266873708 17.7107260310 + -4.3900310562 12.0799548321 + -4.1217028989 4.6477802253 + -3.8533747416 1.3742832861 + -3.5850465843 -0.2031008969 + -3.3167184270 -3.6003194012 + -1.1700931686 -7.9481364246 } -number of Pareto points: 3 +number of Pareto points: 9 diff --git a/examples/basic/library/single_obj/basic_lib.cpp b/examples/basic/library/single_obj/basic_lib.cpp index 57a29c9..ea99384 100644 --- a/examples/basic/library/single_obj/basic_lib.cpp +++ b/examples/basic/library/single_obj/basic_lib.cpp @@ -52,9 +52,6 @@ int main ( int argc , char ** argv ) { // NOMAD initializations: NOMAD::begin ( argc , argv ); - NOMAD::RNG::set_seed(12345); - - // parameters creation: NOMAD::Parameters p ( out ); @@ -66,7 +63,7 @@ int main ( int argc , char ** argv ) { bbot[2] = NOMAD::EB; p.set_BB_OUTPUT_TYPE ( bbot ); - //p.set_DISPLAY_ALL_EVAL(true); // displays all evaluations. +// p.set_DISPLAY_ALL_EVAL(true); // displays all evaluations. p.set_DISPLAY_STATS ( "bbe ( sol ) obj" ); p.set_X0 ( NOMAD::Point(5,0.0) ); // starting point @@ -80,8 +77,8 @@ int main ( int argc , char ** argv ) { p.set_MAX_BB_EVAL (100); // the algorithm terminates after // 100 black-box evaluations - - // p.set_TMP_DIR ("/tmp"); // directory for temporary files + p.set_DISPLAY_DEGREE(2); + p.set_SOLUTION_FILE("sol.txt"); // parameters validation: p.check(); diff --git a/examples/basic/library/single_obj/runExample.log b/examples/basic/library/single_obj/runExample.log index 3bb3b04..062f2c3 100644 --- a/examples/basic/library/single_obj/runExample.log +++ b/examples/basic/library/single_obj/runExample.log @@ -3,15 +3,20 @@ MADS run { BBE ( SOL ) OBJ - 2 ( 1.1000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 275.2281000000 (PhaseOne) - 3 ( 4.4000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 0.0000000000 (PhaseOne) - 3 ( 4.4000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 ) 0.0000000000 - 11 ( 4.6750000000 0.9000000000 0.9750000000 1.5000000000 -1.5000000000 ) -1.5000000000 - 55 ( 1.6500000000 1.8000000000 1.9500000000 -1.5000000000 -3.0000000000 ) -3.0000000000 - 100 ( 1.6500000000 1.8000000000 1.9500000000 -1.5000000000 -3.0000000000 ) -3.0000000000 + 2 ( 0.0000000000 0.5366563146 0.5813776741 -0.2683281573 0.2683281573 ) 288.7937255854 (PhaseOne) + 3 ( 0.0000000000 2.1466252584 2.3255106966 -1.0733126292 1.0733126292 ) 0.0000000000 (PhaseOne) + 3 ( 0.0000000000 2.1466252584 2.3255106966 -1.0733126292 1.0733126292 ) 1.0733126292 + 11 ( 0.1229837388 2.5491174943 2.6161995337 -1.0733126292 0.8720665112 ) 0.8720665112 + 12 ( 0.4919349550 3.7565942022 3.4882660449 -1.0733126292 0.2683281573 ) 0.2683281573 + 21 ( 0.4919349550 4.2932505168 4.0696437190 -0.2683281573 -0.2683281573 ) -0.2683281573 + 23 ( 1.9677398202 1.6099689438 3.4882660449 -0.8049844719 -1.3416407865 ) -1.3416407865 + 38 ( 1.4758048651 3.2199378876 -0.5813776741 -0.2683281573 -2.9516097303 ) -2.9516097303 + 56 ( 1.9677398202 1.0733126292 1.7441330224 0.5366563146 -3.7565942022 ) -3.7565942022 + 85 ( 1.4758048651 0.9391485505 1.1627553483 0.8049844719 -3.8907582808 ) -3.8907582808 + 100 ( 1.4758048651 0.9391485505 1.1627553483 0.8049844719 -3.8907582808 ) -3.8907582808 } end of run (max number of blackbox evaluations) blackbox evaluations : 100 -best infeasible solution (min. violation): ( 0.55 1.8 2.6 -1.5 -3 ) h=0.6525 f=-3 -best feasible solution : ( 1.65 1.8 1.95 -1.5 -3 ) h=0 f=-3 +best infeasible solution (min. violation): ( 3.443544685 2.683281573 1.744133022 0.8049844719 -2.95160973 ) h=0.0113319552 f=-2.95160973 +best feasible solution : ( 1.475804865 0.9391485505 1.162755348 0.8049844719 -3.890758281 ) h=0 f=-3.890758281 diff --git a/examples/basic/library/single_obj_parallel/basic_lib.cpp b/examples/basic/library/single_obj_parallel/basic_lib.cpp new file mode 100644 index 0000000..408e841 --- /dev/null +++ b/examples/basic/library/single_obj_parallel/basic_lib.cpp @@ -0,0 +1,203 @@ +/*-----------------------------------------------------*/ +/* how to use the NOMAD library with a user function */ +/*-----------------------------------------------------*/ +#include "nomad.hpp" +#include <pthread.h> +#include <semaphore.h> + +using namespace std; +// using namespace NOMAD; avoids putting NOMAD:: everywhere + +// Number of threads to be used in parallel +#define NUM_THREADS 4 + +// A semaphore to manage parallel evaluations with NUM_THREADS +sem_t *mySemaphore; + +// A structure to pass arguments to the evaluation wrapper function +class My_Evaluator; +typedef struct Arg_Eval_tag { + NOMAD::Eval_Point * x ; + NOMAD::Double h_max; + bool * count_eval; + const My_Evaluator * ev; +} Arg_Eval_t; + + + +class My_Evaluator : public NOMAD::Evaluator { +public: + My_Evaluator ( const NOMAD::Parameters & p ) : + NOMAD::Evaluator ( p ) {} + + ~My_Evaluator ( void ) {} + + /*----------------------------------------*/ + /* The problem evaluatiom */ + /*----------------------------------------*/ + // Provide the objective and constraints here + bool eval_x ( NOMAD::Eval_Point & x , + const NOMAD::Double & h_max , + bool & count_eval ) const + { + + NOMAD::Double c1 = 0.0 , c2 = 0.0; + for ( int i = 0 ; i < 5 ; i++ ) + { + c1 += (x[i]-1).pow2(); + c2 += (x[i]+1).pow2(); + } + x.set_bb_output ( 0 , x[4] ); // objective value + x.set_bb_output ( 1 , c1-25 ); // constraint 1 + x.set_bb_output ( 2 , 25-c2 ); // constraint 2 + + count_eval = true; // count a black-box evaluation + + return true; // the evaluation succeeded + } + + // Wrapper of eval_x used for parallel evaluation (pthreads). + static void * wrapper_eval_x ( void * dummy_eval_arg ) + { + + Arg_Eval_t * eval_arg = static_cast<Arg_Eval_t *>(dummy_eval_arg); + + NOMAD::Eval_Point & x=*(eval_arg->x); + bool & count_eval = *(eval_arg->count_eval); + const NOMAD::Double & h_max = (eval_arg->h_max); + const My_Evaluator *ev=(eval_arg->ev); + + ev->eval_x(x,h_max,count_eval); + + pthread_exit(NULL); + + } + + // Implementation + bool eval_x ( std::list<NOMAD::Eval_Point *> &list_x , + const NOMAD::Double & h_max, + std::list<bool> & list_count_eval ) const + { + int rc; + + + + list_count_eval.assign(list_count_eval.size(),false); // Evaluations are not counted until eval_x is called and set count_eval + + // All threads are created + pthread_t threads[list_x.size()]; + + // The semaphore will allow to run NUM_THREADS in parallel + mySemaphore=sem_open("sem",0,NUM_THREADS); + + // Arguments passed to the evaluation wrapper + Arg_Eval_t * eval_arg=new Arg_Eval_t[list_x.size()]; + + std::list<NOMAD::Eval_Point *>::iterator it_x=list_x.begin(),end_x=list_x.end(); + std::list<bool>::iterator it_count=list_count_eval.begin(); + int i=0; + // The list of points is evaluated under the control of a semaphore + for (it_x=list_x.begin(); it_x!=end_x; ++it_x,++it_count,++i) + { + eval_arg[i].x=(*it_x); + eval_arg[i].h_max=h_max.value(); + eval_arg[i].count_eval=&(*it_count); + eval_arg[i].ev=this; + rc=pthread_create(&threads[i], NULL, wrapper_eval_x,&eval_arg[i]); + if (rc) + { + cout << "Error:unable to create thread," << rc << endl; + return false; + } + // wait until value of semaphore is greater than 0 + // decrement the value of semaphore by 1 + sem_wait(mySemaphore); + + } + + delete []eval_arg; + int ret; + for (i=0; i<list_x.size(); ++i) + { + // Wait for all the threads to finish + ret=pthread_join(threads[i],0); + if (ret!=0) + { + perror("pthread join has failed"); + return false; + } + } + + sem_unlink("sem"); + + return true; // the evaluation succeeded + } + + + +}; + +/*------------------------------------------*/ +/* NOMAD main function */ +/*------------------------------------------*/ +int main ( int argc , char ** argv ) { + + // display: + NOMAD::Display out ( std::cout ); + out.precision ( NOMAD::DISPLAY_PRECISION_STD ); + + try { + + // NOMAD initializations: + NOMAD::begin ( argc , argv ); + + // parameters creation: + NOMAD::Parameters p ( out ); + + p.set_DIMENSION (5); // number of variables + + vector<NOMAD::bb_output_type> bbot (3); // definition of + bbot[0] = NOMAD::OBJ; // output types + bbot[1] = NOMAD::PB; + bbot[2] = NOMAD::EB; + p.set_BB_OUTPUT_TYPE ( bbot ); + +// p.set_DISPLAY_ALL_EVAL(true); // displays all evaluations. + p.set_DISPLAY_DEGREE(2); + p.set_DISPLAY_STATS ( "bbe ( sol ) obj" ); + + p.set_X0 ( NOMAD::Point(5,0.0) ); // starting point + + p.set_LOWER_BOUND ( NOMAD::Point ( 5 , -6.0 ) ); // all var. >= -6 + NOMAD::Point ub ( 5 ); // x_4 and x_5 have no bounds + ub[0] = 5.0; // x_1 <= 5 + ub[1] = 6.0; // x_2 <= 6 + ub[2] = 7.0; // x_3 <= 7 + p.set_UPPER_BOUND ( ub ); + + p.set_MAX_BB_EVAL (100); // the algorithm terminates after + // 100 black-box evaluations + + // Max number of points to be given as a block for evaluation + // This option is required to perform parallel evaluations + p.set_BB_MAX_BLOCK_SIZE(NUM_THREADS); + + // parameters validation: + p.check(); + + // custom evaluator creation: + My_Evaluator ev ( p ); + + // algorithm creation and execution: + NOMAD::Mads mads ( p , &ev ); + mads.run(); + } + catch ( exception & e ) { + cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; + } + + NOMAD::Slave::stop_slaves ( out ); + NOMAD::end(); + + return EXIT_SUCCESS; +} diff --git a/examples/basic/library/single_obj_parallel/makefile b/examples/basic/library/single_obj_parallel/makefile new file mode 100644 index 0000000..d7af859 --- /dev/null +++ b/examples/basic/library/single_obj_parallel/makefile @@ -0,0 +1,50 @@ +EXE = basic_lib.exe + +COMPILATOR = g++ + +COMPILATOR_OPTIONS = -O2 -ansi +L1 = $(NOMAD_HOME)/lib/nomad.a +LIBS = $(L1) -lm +INCLUDE = -I$(NOMAD_HOME)/src -I. +COMPILE = $(COMPILATOR) $(COMPILATOR_OPTIONS) $(INCLUDE) -c +OBJS = basic_lib.o + + +ifndef NOMAD_HOME +define ECHO_NOMAD + @echo Please set NOMAD_HOME environment variable! + @false +endef +endif + + +$(EXE): $(L1) $(OBJS) + $(ECHO_NOMAD) + @echo " building the parallel (ptrhreads) version ..." + @echo " exe file : "$(EXE) + @$(COMPILATOR) -o $(EXE) $(OBJS) $(LIBS) $(COMPILATOR_OPTIONS) + @strip $(EXE) + +basic_lib.o: basic_lib.cpp + $(ECHO_NOMAD) + @$(COMPILE) basic_lib.cpp + +$(L1) : ; + $(ECHO_NOMAD) + + +all: $(EXE) + +clean: ; + @echo " cleaning obj files" + @rm -f $(OBJS) + +del: ; + @echo " cleaning trash files" + @rm -f core *~ + @echo " cleaning obj files" + @rm -f $(OBJS) + @echo " cleaning exe file" + @rm -f $(EXE) + + diff --git a/examples/basic/library/single_obj_parallel/runExample.log b/examples/basic/library/single_obj_parallel/runExample.log new file mode 100644 index 0000000..c69008c --- /dev/null +++ b/examples/basic/library/single_obj_parallel/runExample.log @@ -0,0 +1,27 @@ +Warning: { + The maximum number of evaluations may be exceeded when BB_MAX_BLOCK_SIZE>1. +} + +MADS run { + + BBE ( SOL ) OBJ + + 2 ( 0.0000000000 0.5366563146 0.5813776741 -0.2683281573 0.2683281573 ) 288.7937255854 (PhaseOne) + 3 ( 0.4919349550 1.0733126292 0.0000000000 0.0000000000 -0.2683281573 ) 254.0887373636 (PhaseOne) + 4 ( 0.4919349550 0.0000000000 1.1627553483 0.2683281573 -0.2683281573 ) 223.5808267209 (PhaseOne) + 6 ( 1.9677398202 0.0000000000 4.6510213932 1.0733126292 -1.0733126292 ) 0.0000000000 (PhaseOne) + 6 ( 1.9677398202 0.0000000000 4.6510213932 1.0733126292 -1.0733126292 ) -1.0733126292 + 12 ( 1.4758048651 -0.5366563146 4.0696437190 0.8049844719 -1.6099689438 ) -1.6099689438 + 14 ( 0.4919349550 0.5366563146 4.0696437190 0.2683281573 -2.4149534157 ) -2.4149534157 + 30 ( 1.9677398202 0.5366563146 1.1627553483 1.3416407865 -3.2199378876 ) -3.2199378876 + 52 ( 0.9838699101 0.5366563146 1.7441330224 1.3416407865 -3.7565942022 ) -3.7565942022 + 74 ( 0.9838699101 1.0733126292 1.7441330224 0.5366563146 -3.7565942022 ) -3.7565942022 + 92 ( 1.2298373876 1.2074767078 1.3080997668 1.0062305899 -3.8236762415 ) -3.8236762415 + 95 ( 0.8608861713 1.2074767078 1.1627553483 1.3416407865 -3.8907582808 ) -3.8907582808 + 101 ( 0.8608861713 1.2074767078 1.1627553483 1.3416407865 -3.8907582808 ) -3.8907582808 + +} end of run (max number of blackbox evaluations) + +blackbox evaluations : 101 +best infeasible solution (min. violation): ( 0.9838699101 1.073312629 1.162755348 1.073312629 -4.024922359 ) h=0.2873436854 f=-4.024922359 +best feasible solution : ( 0.8608861713 1.207476708 1.162755348 1.341640786 -3.890758281 ) h=0 f=-3.890758281 diff --git a/examples/interfaces/AMPL/runExample.log b/examples/interfaces/AMPL/runExample.log index 2e2d97d..4e5a25f 100644 --- a/examples/interfaces/AMPL/runExample.log +++ b/examples/interfaces/AMPL/runExample.log @@ -1,7 +1,7 @@ -NOMAD - version 3.6.1 - www.gerad.ca/nomad +NOMAD - version 3.7.1 - www.gerad.ca/nomad -Copyright (C) 2001-2013 { +Copyright (C) 2001-2015 { Mark A. Abramson - The Boeing Company Charles Audet - Ecole Polytechnique de Montreal Gilles Couture - Ecole Polytechnique de Montreal @@ -24,45 +24,57 @@ MADS run { BBE OBJ 1 0.0008855723 - 18 0.0008418472 - 27 0.0007858003 - 83 0.0007849247 - 107 0.0007587924 - 160 0.0007535678 - 177 0.0007479755 - 202 0.0007380410 - 245 0.0007340172 - 273 0.0007283297 - 338 0.0007280775 - 340 0.0007270988 - 341 0.0007260201 - 355 0.0007237479 - 375 0.0007236576 - 390 0.0007223485 - 404 0.0007218982 - 418 0.0007217642 - 462 0.0007206517 - 482 0.0007204212 - 523 0.0007202708 - 551 0.0007201867 - 591 0.0007200853 - 628 0.0007199875 - 673 0.0007199828 - 701 0.0007199638 - 730 0.0007199581 - 747 0.0007199510 - 748 0.0007199335 - 749 0.0007199166 - 758 0.0007198508 - 795 0.0007198372 - 853 0.0007198240 - 880 0.0007197980 - 887 0.0007197952 - 992 0.0007197935 - 1000 0.0007197935 + 13 0.0008629415 + 73 0.0007682919 + 158 0.0007674024 + 160 0.0007590596 + 176 0.0007580561 + 223 0.0007473508 + 238 0.0007418250 + 253 0.0007372242 + 313 0.0007347847 + 315 0.0007332118 + 317 0.0007326378 + 319 0.0007305500 + 349 0.0007267455 + 364 0.0007266172 + 387 0.0007257315 + 394 0.0007248895 + 435 0.0007231991 + 437 0.0007231585 + 439 0.0007228901 + 445 0.0007225342 + 475 0.0007215812 + 490 0.0007212792 + 505 0.0007211745 + 511 0.0007211392 + 532 0.0007207825 + 547 0.0007206714 + 606 0.0007200196 + 635 0.0007200045 + 653 0.0007198430 + 657 0.0007198134 + 684 0.0007197965 + 711 0.0007197807 + 712 0.0007197631 + 767 0.0007197518 + 783 0.0007197518 + 811 0.0007197377 + 825 0.0007197358 + 840 0.0007197336 + 841 0.0007197273 + 902 0.0007197266 + 904 0.0007197250 + 919 0.0007197244 + 920 0.0007197231 + 935 0.0007197211 + 963 0.0007197196 + 965 0.0007197191 + 993 0.0007197174 + 1000 0.0007197174 } end of run (max number of blackbox evaluations) blackbox evaluations : 1000 -best infeasible solution (min. violation): ( 0.848962364 2.324953675e-06 3.01413238e-06 2.850219607e-06 0.0001720577478 0.07897830494 0.03139281012 0.0110261865 ) h=0.05000000003 f=0.000719795225 -best feasible solution : ( 0.8489658805 0 0 0 0.0001777410507 0.07896998888 0.03139625052 0.01103117205 ) h=0 f=0.0007197935108 +best infeasible solution (min. violation): ( 0.8485876659 1.323962574e-06 2.55409902e-06 1.18495206e-06 4.478102654e-06 0.07926348224 0.03138097659 0.01128972406 ) h=0.05000000006 f=0.0007197247301 +best feasible solution : ( 0.8485431024 1.006379485e-06 7.250492715e-07 1.072192777e-06 2.36219915e-06 0.07937295341 0.03130849192 0.01130402409 ) h=0 f=0.0007197173872 diff --git a/examples/interfaces/CUTEr/parameters.txt b/examples/interfaces/CUTEr/param.txt similarity index 90% rename from examples/interfaces/CUTEr/parameters.txt rename to examples/interfaces/CUTEr/param.txt index a4e6a79..05b0dfb 100644 --- a/examples/interfaces/CUTEr/parameters.txt +++ b/examples/interfaces/CUTEr/param.txt @@ -10,7 +10,7 @@ BB_EXE bb.exe BB_OUTPUT_TYPE OBJ MAX_BB_EVAL 100 -DIRECTION_TYPE ortho n+1 +DIRECTION_TYPE ortho 2n #stats_file ortho.stats TIME BBE OBJ #solution_file ortho.sol diff --git a/examples/interfaces/CUTEr/readme.txt b/examples/interfaces/CUTEr/readme.txt index 8af17ea..4e88980 100644 --- a/examples/interfaces/CUTEr/readme.txt +++ b/examples/interfaces/CUTEr/readme.txt @@ -23,4 +23,4 @@ Compile with the C wrapper 'bb.c' by running the script 'compile' The black-box executable 'bb.exe' should be created. You can test it with the command 'bb.exe x0.txt', and run nomad with the command -'nomad.exe parameters.txt'. +'nomad.exe param.txt'. diff --git a/examples/interfaces/DLL/bi_obj/nomad_for_DLL.cpp b/examples/interfaces/DLL/bi_obj/nomad_for_DLL.cpp index f563568..316e94b 100755 --- a/examples/interfaces/DLL/bi_obj/nomad_for_DLL.cpp +++ b/examples/interfaces/DLL/bi_obj/nomad_for_DLL.cpp @@ -1,212 +1,212 @@ -/*---------------------------------------------------------------*/ -/* NOMAD for a DLL-black-box */ -/*---------------------------------------------------------------*/ -#include "nomad.hpp" -#include <windows.h> -using namespace std; -using namespace NOMAD; - -// black-box outputs (m): -// ---------------------- -// . the first one is the objective function -// . all the others (1 to m-1) are PB constraints with format g(x) <= 0 - - -/*------------------------------------------*/ -/* DLL functions */ -/*------------------------------------------*/ -typedef int (_stdcall *GET_NM)( void ); -typedef void (_stdcall *EVAL_X)( double * , double * , bool * ); -typedef void (_stdcall *INIT )( void ); - -GET_NM get_n_dll; -GET_NM get_m_dll; -EVAL_X eval_x_dll; -//INIT init_dll; -//INIT clear_dll; - -// simulate the DLL functions (for tests): -/* -void init ( void ) {} -void clear ( void ) {} -int get_n_dll ( void ) { return 5; } -int get_m_dll ( void ) { return 3; } -void eval_x_dll ( double * x , double * fx , bool & cnt_eval ) { - double c1 = 0.0 , c2 = 0.0; - for ( int i = 0 ; i < 5 ; ++i ) { - c1 += pow ( x[i]-1 , 2 ); - c2 += pow ( x[i]+1 , 2 ); - } - fx[0] = x[4]; - fx[1] = c1 - 25; - fx[2] = 25 - c2; - cnt_eval = true; -} -*/ - -/*--------------------------------------*/ -/* custom evaluator */ -/*--------------------------------------*/ -class My_Evaluator : public Multi_Obj_Evaluator { - -private: - - int _n; - int _m; - double * _px; - double * _fx; - -public: - - // ctor: - My_Evaluator ( const Parameters & p , int n , int m ) - : Multi_Obj_Evaluator ( p ) , - _n ( n ) , - _m ( m ) , - _px ( new double [_n] ) , - _fx ( new double [_m] ) {} - - // dtor: - ~My_Evaluator ( void ) { delete [] _px; delete [] _fx; } - - // eval_x: - bool eval_x ( Eval_Point & x , - const NOMAD::Double & h_max , - bool & cnt_eval ) const; -}; - -// eval_x: -bool My_Evaluator::eval_x ( Eval_Point & x , - const NOMAD::Double & h_max , - bool & cnt_eval ) const { - int i; - for ( i = 0 ; i < _n ; ++i ) - _px[i] = x[i].value(); - eval_x_dll ( _px , _fx , &cnt_eval ); - for ( i = 0 ; i < _m ; ++i ) - x.set_bb_output ( i , _fx[i] ); - return true; -} - -/*------------------------------------------*/ -/* NOMAD main function */ -/*------------------------------------------*/ -int main ( int argc , char ** argv ) { - - // use: - if ( argc != 2 ) { - cerr << "\nuse: nomad_for_DLL.exe param.txt\n\n"; - return 1; - } - - // NOMAD initializations: - begin ( argc , argv ); - - // display: - NOMAD::Display out ( std::cout ); - out.precision ( NOMAD::DISPLAY_PRECISION_STD ); - - // random seed: - unsigned seed = 0; - srand(seed); - - // define DLL functions: - // get handle to dll: - HINSTANCE hdll = LoadLibrary ( TEXT("bb.dll") ); - if ( !hdll ) { - cerr << "ERROR: unable to open bb.dll" << endl; - FreeLibrary ( hdll ); - return 1; - } - - // get function pointers: - get_n_dll = (GET_NM)GetProcAddress(hdll, "GET_N"); - if ( !get_n_dll ) { - cerr << "ERROR: unable to find GET_N function in dll" << endl; - FreeLibrary ( hdll ); - return 1; - } - - get_m_dll = (GET_NM)GetProcAddress(hdll, "GET_M"); - if ( !get_m_dll ) { - cerr << "ERROR: unable to find GET_M function in dll" << endl; - FreeLibrary ( hdll ); - return 1; - } - - eval_x_dll = (EVAL_X)GetProcAddress(hdll, "EVAL_X"); - if ( !eval_x_dll ) { - cerr << "ERROR: unable to find EVAL_X function in dll" << endl; - FreeLibrary ( hdll ); - return 1; - } - - /* init_dll = (INIT)GetProcAddress(hdll, "INIT"); - if ( !init_dll ) { - cerr << "ERROR: unable to find INIT function in dll" << endl; - FreeLibrary ( hdll ); - return 1; - } - - clear_dll = (INIT)GetProcAddress(hdll, "CLEAR"); - if ( !clear_dll ) { - cerr << "ERROR: unable to find CLEAR function in dll" << endl; - FreeLibrary ( hdll ); - return 1; - }*/ - - // MADS: - try { - - /* init_dll(); */ - - int n = get_n_dll(); - int m = get_m_dll(); - - // parameters creation: - // -------------------- - Parameters p ( out ); - - // dimension: - p.set_DIMENSION ( n ); - - // definition of output types: - vector<bb_output_type> bbot (m); - bbot[0] = bbot[1] = OBJ; - for ( int i = 2 ; i < m ; ++i ) - bbot[i] = PB; - p.set_BB_OUTPUT_TYPE ( bbot ); - - // read parameters file: - p.read ( argv[1] ); - - // parameters check: - p.check(); - - // display parameters: - // out << p << endl; - - // custom evaluator creation: - My_Evaluator ev ( p , n , m ); - - // algorithm creation and execution: - Mads mads ( p , &ev ); - mads.multi_run(); - - // algorithm display: - // out << mads << endl; - - /* clear_dll(); */ - } - catch ( exception & e ) { - cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; - } - - // Release the Dll: - FreeLibrary ( hdll ); - - NOMAD::Slave::stop_slaves ( out ); - NOMAD::end(); - - return EXIT_SUCCESS; -} +/*---------------------------------------------------------------*/ +/* NOMAD for a DLL-black-box */ +/*---------------------------------------------------------------*/ +#include "nomad.hpp" +#include <windows.h> +using namespace std; +using namespace NOMAD; + +// black-box outputs (m): +// ---------------------- +// . the first one is the objective function +// . all the others (1 to m-1) are PB constraints with format g(x) <= 0 + + +/*------------------------------------------*/ +/* DLL functions */ +/*------------------------------------------*/ +typedef int (_stdcall *GET_NM)( void ); +typedef void (_stdcall *EVAL_X)( double * , double * , bool * ); +typedef void (_stdcall *INIT )( void ); + +GET_NM get_n_dll; +GET_NM get_m_dll; +EVAL_X eval_x_dll; +//INIT init_dll; +//INIT clear_dll; + +// simulate the DLL functions (for tests): +/* +void init ( void ) {} +void clear ( void ) {} +int get_n_dll ( void ) { return 5; } +int get_m_dll ( void ) { return 3; } +void eval_x_dll ( double * x , double * fx , bool & cnt_eval ) { + double c1 = 0.0 , c2 = 0.0; + for ( int i = 0 ; i < 5 ; ++i ) { + c1 += pow ( x[i]-1 , 2 ); + c2 += pow ( x[i]+1 , 2 ); + } + fx[0] = x[4]; + fx[1] = c1 - 25; + fx[2] = 25 - c2; + cnt_eval = true; +} +*/ + +/*--------------------------------------*/ +/* custom evaluator */ +/*--------------------------------------*/ +class My_Evaluator : public Multi_Obj_Evaluator { + +private: + + int _n; + int _m; + double * _px; + double * _fx; + +public: + + // ctor: + My_Evaluator ( const Parameters & p , int n , int m ) + : Multi_Obj_Evaluator ( p ) , + _n ( n ) , + _m ( m ) , + _px ( new double [_n] ) , + _fx ( new double [_m] ) {} + + // dtor: + ~My_Evaluator ( void ) { delete [] _px; delete [] _fx; } + + // eval_x: + bool eval_x ( Eval_Point & x , + const NOMAD::Double & h_max , + bool & cnt_eval ) const; +}; + +// eval_x: +bool My_Evaluator::eval_x ( Eval_Point & x , + const NOMAD::Double & h_max , + bool & cnt_eval ) const { + int i; + for ( i = 0 ; i < _n ; ++i ) + _px[i] = x[i].value(); + eval_x_dll ( _px , _fx , &cnt_eval ); + for ( i = 0 ; i < _m ; ++i ) + x.set_bb_output ( i , _fx[i] ); + return true; +} + +/*------------------------------------------*/ +/* NOMAD main function */ +/*------------------------------------------*/ +int main ( int argc , char ** argv ) { + + // use: + if ( argc != 2 ) { + cerr << "\nuse: nomad_for_DLL.exe param.txt\n\n"; + return 1; + } + + // NOMAD initializations: + begin ( argc , argv ); + + // display: + NOMAD::Display out ( std::cout ); + out.precision ( NOMAD::DISPLAY_PRECISION_STD ); + + // random seed: + unsigned seed = 0; + srand(seed); + + // define DLL functions: + // get handle to dll: + HINSTANCE hdll = LoadLibrary ( TEXT("bb.dll") ); + if ( !hdll ) { + cerr << "ERROR: unable to open bb.dll" << endl; + FreeLibrary ( hdll ); + return 1; + } + + // get function pointers: + get_n_dll = (GET_NM)GetProcAddress(hdll, "GET_N"); + if ( !get_n_dll ) { + cerr << "ERROR: unable to find GET_N function in dll" << endl; + FreeLibrary ( hdll ); + return 1; + } + + get_m_dll = (GET_NM)GetProcAddress(hdll, "GET_M"); + if ( !get_m_dll ) { + cerr << "ERROR: unable to find GET_M function in dll" << endl; + FreeLibrary ( hdll ); + return 1; + } + + eval_x_dll = (EVAL_X)GetProcAddress(hdll, "EVAL_X"); + if ( !eval_x_dll ) { + cerr << "ERROR: unable to find EVAL_X function in dll" << endl; + FreeLibrary ( hdll ); + return 1; + } + + /* init_dll = (INIT)GetProcAddress(hdll, "INIT"); + if ( !init_dll ) { + cerr << "ERROR: unable to find INIT function in dll" << endl; + FreeLibrary ( hdll ); + return 1; + } + + clear_dll = (INIT)GetProcAddress(hdll, "CLEAR"); + if ( !clear_dll ) { + cerr << "ERROR: unable to find CLEAR function in dll" << endl; + FreeLibrary ( hdll ); + return 1; + }*/ + + // MADS: + try { + + /* init_dll(); */ + + int n = get_n_dll(); + int m = get_m_dll(); + + // parameters creation: + // -------------------- + Parameters p ( out ); + + // dimension: + p.set_DIMENSION ( n ); + + // definition of output types: + vector<bb_output_type> bbot (m); + bbot[0] = bbot[1] = OBJ; + for ( int i = 2 ; i < m ; ++i ) + bbot[i] = PB; + p.set_BB_OUTPUT_TYPE ( bbot ); + + // read parameters file: + p.read ( argv[1] ); + + // parameters check: + p.check(); + + // display parameters: + // out << p << endl; + + // custom evaluator creation: + My_Evaluator ev ( p , n , m ); + + // algorithm creation and execution: + Mads mads ( p , &ev ); + mads.multi_run(); + + // algorithm display: + // out << mads << endl; + + /* clear_dll(); */ + } + catch ( exception & e ) { + cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; + } + + // Release the Dll: + FreeLibrary ( hdll ); + + NOMAD::Slave::stop_slaves ( out ); + NOMAD::end(); + + return EXIT_SUCCESS; +} diff --git a/examples/interfaces/DLL/bi_obj/parameters.txt b/examples/interfaces/DLL/bi_obj/param.txt similarity index 91% rename from examples/interfaces/DLL/bi_obj/parameters.txt rename to examples/interfaces/DLL/bi_obj/param.txt index 7b6d6bb..fea33ef 100755 --- a/examples/interfaces/DLL/bi_obj/parameters.txt +++ b/examples/interfaces/DLL/bi_obj/param.txt @@ -1,28 +1,28 @@ -#seed 100 - -initial_mesh_size r0.1 - -direction_type ortho 2n - - -multi_overall_bb_eval 1000 - -lower_bound * -10.0 - -upper_bound * 10.0 - - -x0 ( 2 3 4 5 6 ) - -display_degree 3 - - -add_seed_to_file_names no - -#stats_file toto.txt bbe obj -#solution_file "sol.txt" - -#LH_SEARCH 100 0 - -#OPPORTUNISTIC_LH no - +#seed 100 + +initial_mesh_size r0.1 + +direction_type ortho 2n + + +multi_overall_bb_eval 1000 + +lower_bound * -10.0 + +upper_bound * 10.0 + + +x0 ( 2 3 4 5 6 ) + +display_degree 3 + + +add_seed_to_file_names no + +#stats_file toto.txt bbe obj +#solution_file "sol.txt" + +#LH_SEARCH 100 0 + +#OPPORTUNISTIC_LH no + diff --git a/examples/interfaces/DLL/bi_obj/readme.txt b/examples/interfaces/DLL/bi_obj/readme.txt index a37fa9c..8889d3d 100755 --- a/examples/interfaces/DLL/bi_obj/readme.txt +++ b/examples/interfaces/DLL/bi_obj/readme.txt @@ -1,54 +1,54 @@ - -This example illustrates how to use NOMAD with a black-box -problem that is coded inside a DLL file. - -The problem has two objective values to minimize. - -The example runs on windows with visual C++ and minGW. - - -DLL characteristics: - -/*----------*/ - -/* bb.dll */ - -/*----------*/ - - - -// init/clear: - -// ----------- - -void init_dll ( void ); - -void clear_dll ( void ); - -// problem characteristics: - -// ------------------------ - - -int get_n_dll ( void ); // number of variables - -int get_m _dll( void ); // number of outputs: output #0 and #1: objective values to minimize - - // output #2..m-1: PB constraints with format g(x) <= 0 - - - -// evaluation: f(x): - -// ----------------- - - -void eval_x_dll ( double * x , double * fx , bool & count_eval ); - - - -// x: input , double array of size n - -// fx: output, double array of size m - -// count_eval: output, set to true if the evaluation has to be counted, false else + +This example illustrates how to use NOMAD with a black-box +problem that is coded inside a DLL file. + +The problem has two objective values to minimize. + +The example runs on windows with visual C++ and minGW. + + +DLL characteristics: + +/*----------*/ + +/* bb.dll */ + +/*----------*/ + + + +// init/clear: + +// ----------- + +void init_dll ( void ); + +void clear_dll ( void ); + +// problem characteristics: + +// ------------------------ + + +int get_n_dll ( void ); // number of variables + +int get_m _dll( void ); // number of outputs: output #0 and #1: objective values to minimize + + // output #2..m-1: PB constraints with format g(x) <= 0 + + + +// evaluation: f(x): + +// ----------------- + + +void eval_x_dll ( double * x , double * fx , bool & count_eval ); + + + +// x: input , double array of size n + +// fx: output, double array of size m + +// count_eval: output, set to true if the evaluation has to be counted, false else diff --git a/examples/interfaces/DLL/single_obj/nomad_for_DLL.cpp b/examples/interfaces/DLL/single_obj/nomad_for_DLL.cpp index 968a4d7..43f4dcf 100755 --- a/examples/interfaces/DLL/single_obj/nomad_for_DLL.cpp +++ b/examples/interfaces/DLL/single_obj/nomad_for_DLL.cpp @@ -1,212 +1,212 @@ -/*---------------------------------------------------------------*/ -/* NOMAD for a DLL-black-box */ -/*---------------------------------------------------------------*/ -#include "nomad.hpp" -#include <windows.h> -using namespace std; -using namespace NOMAD; - -// black-box outputs (m): -// ---------------------- -// . the first one is the objective function -// . all the others (1 to m-1) are PB constraints with format g(x) <= 0 - - -/*------------------------------------------*/ -/* DLL functions */ -/*------------------------------------------*/ -typedef int (_stdcall *GET_NM)( void ); -typedef void (_stdcall *EVAL_X)( double * , double * , bool * ); -typedef void (_stdcall *INIT )( void ); - -GET_NM get_n_dll; -GET_NM get_m_dll; -EVAL_X eval_x_dll; -//INIT init_dll; -//INIT clear_dll; - -// simulate the DLL functions (for tests): -/* -void init ( void ) {} -void clear ( void ) {} -int get_n_dll ( void ) { return 5; } -int get_m_dll ( void ) { return 3; } -void eval_x_dll ( double * x , double * fx , bool & cnt_eval ) { - double c1 = 0.0 , c2 = 0.0; - for ( int i = 0 ; i < 5 ; ++i ) { - c1 += pow ( x[i]-1 , 2 ); - c2 += pow ( x[i]+1 , 2 ); - } - fx[0] = x[4]; - fx[1] = c1 - 25; - fx[2] = 25 - c2; - cnt_eval = true; -} -*/ - -/*--------------------------------------*/ -/* custom evaluator */ -/*--------------------------------------*/ -class My_Evaluator : public Evaluator { - -private: - - int _n; - int _m; - double * _px; - double * _fx; - -public: - - // ctor: - My_Evaluator ( const Parameters & p , int n , int m ) - : Evaluator ( p ) , - _n ( n ) , - _m ( m ) , - _px ( new double [_n] ) , - _fx ( new double [_m] ) {} - - // dtor: - ~My_Evaluator ( void ) { delete [] _px; delete [] _fx; } - - // eval_x: - bool eval_x ( Eval_Point & x , - const Double & h_max , - bool & cnt_eval ) const; -}; - -// eval_x: -bool My_Evaluator::eval_x ( Eval_Point & x , - const Double & h_max , - bool & cnt_eval ) const { - int i; - for ( i = 0 ; i < _n ; ++i ) - _px[i] = x[i].value(); - eval_x_dll ( _px , _fx , &cnt_eval ); - for ( i = 0 ; i < _m ; ++i ) - x.set_bb_output ( i , _fx[i] ); - return true; -} - -/*------------------------------------------*/ -/* NOMAD main function */ -/*------------------------------------------*/ -int main ( int argc , char ** argv ) { - - // use: - if ( argc != 2 ) { - cerr << "\nuse: nomad_for_DLL.exe param.txt\n\n"; - return 1; - } - - // NOMAD initializations: - begin ( argc , argv ); - - // display: - NOMAD::Display out ( std::cout ); - out.precision ( NOMAD::DISPLAY_PRECISION_STD ); - - // random seed: - unsigned seed = 0; - srand(seed); - - // define DLL functions: - // get handle to dll: - HINSTANCE hdll = LoadLibrary ( TEXT("bb.dll") ); - if ( !hdll ) { - cerr << "ERROR: unable to open bb.dll" << endl; - FreeLibrary ( hdll ); - return 1; - } - - // get function pointers: - get_n_dll = (GET_NM)GetProcAddress(hdll, "GET_N"); - if ( !get_n_dll ) { - cerr << "ERROR: unable to find GET_N function in dll" << endl; - FreeLibrary ( hdll ); - return 1; - } - - get_m_dll = (GET_NM)GetProcAddress(hdll, "GET_M"); - if ( !get_m_dll ) { - cerr << "ERROR: unable to find GET_M function in dll" << endl; - FreeLibrary ( hdll ); - return 1; - } - - eval_x_dll = (EVAL_X)GetProcAddress(hdll, "EVAL_X"); - if ( !eval_x_dll ) { - cerr << "ERROR: unable to find EVAL_X function in dll" << endl; - FreeLibrary ( hdll ); - return 1; - } - - /* init_dll = (INIT)GetProcAddress(hdll, "INIT"); - if ( !init_dll ) { - cerr << "ERROR: unable to find INIT function in dll" << endl; - FreeLibrary ( hdll ); - return 1; - } - - clear_dll = (INIT)GetProcAddress(hdll, "CLEAR"); - if ( !clear_dll ) { - cerr << "ERROR: unable to find CLEAR function in dll" << endl; - FreeLibrary ( hdll ); - return 1; - }*/ - - // MADS: - try { - - /* init_dll(); */ - - int n = get_n_dll(); - int m = get_m_dll(); - - // parameters creation: - // -------------------- - Parameters p ( out ); - - // dimension: - p.set_DIMENSION ( n ); - - // definition of output types: - vector<bb_output_type> bbot (m); - bbot[0] = OBJ; - for ( int i = 1 ; i < m ; ++i ) - bbot[i] = PB; - p.set_BB_OUTPUT_TYPE ( bbot ); - - // read parameters file: - p.read ( argv[1] ); - - // parameters check: - p.check(); - - // display parameters: - // out << p << endl; - - // custom evaluator creation: - My_Evaluator ev ( p , n , m ); - - // algorithm creation and execution: - Mads mads ( p , &ev ); - mads.run(); - - // algorithm display: - // out << mads << endl; - - /* clear_dll(); */ - } - catch ( exception & e ) { - cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; - } - - // Release the Dll: - FreeLibrary ( hdll ); - - NOMAD::Slave::stop_slaves ( out ); - NOMAD::end(); - - return EXIT_SUCCESS; -} +/*---------------------------------------------------------------*/ +/* NOMAD for a DLL-black-box */ +/*---------------------------------------------------------------*/ +#include "nomad.hpp" +#include <windows.h> +using namespace std; +using namespace NOMAD; + +// black-box outputs (m): +// ---------------------- +// . the first one is the objective function +// . all the others (1 to m-1) are PB constraints with format g(x) <= 0 + + +/*------------------------------------------*/ +/* DLL functions */ +/*------------------------------------------*/ +typedef int (_stdcall *GET_NM)( void ); +typedef void (_stdcall *EVAL_X)( double * , double * , bool * ); +typedef void (_stdcall *INIT )( void ); + +GET_NM get_n_dll; +GET_NM get_m_dll; +EVAL_X eval_x_dll; +//INIT init_dll; +//INIT clear_dll; + +// simulate the DLL functions (for tests): +/* +void init ( void ) {} +void clear ( void ) {} +int get_n_dll ( void ) { return 5; } +int get_m_dll ( void ) { return 3; } +void eval_x_dll ( double * x , double * fx , bool & cnt_eval ) { + double c1 = 0.0 , c2 = 0.0; + for ( int i = 0 ; i < 5 ; ++i ) { + c1 += pow ( x[i]-1 , 2 ); + c2 += pow ( x[i]+1 , 2 ); + } + fx[0] = x[4]; + fx[1] = c1 - 25; + fx[2] = 25 - c2; + cnt_eval = true; +} +*/ + +/*--------------------------------------*/ +/* custom evaluator */ +/*--------------------------------------*/ +class My_Evaluator : public Evaluator { + +private: + + int _n; + int _m; + double * _px; + double * _fx; + +public: + + // ctor: + My_Evaluator ( const Parameters & p , int n , int m ) + : Evaluator ( p ) , + _n ( n ) , + _m ( m ) , + _px ( new double [_n] ) , + _fx ( new double [_m] ) {} + + // dtor: + ~My_Evaluator ( void ) { delete [] _px; delete [] _fx; } + + // eval_x: + bool eval_x ( Eval_Point & x , + const Double & h_max , + bool & cnt_eval ) const; +}; + +// eval_x: +bool My_Evaluator::eval_x ( Eval_Point & x , + const Double & h_max , + bool & cnt_eval ) const { + int i; + for ( i = 0 ; i < _n ; ++i ) + _px[i] = x[i].value(); + eval_x_dll ( _px , _fx , &cnt_eval ); + for ( i = 0 ; i < _m ; ++i ) + x.set_bb_output ( i , _fx[i] ); + return true; +} + +/*------------------------------------------*/ +/* NOMAD main function */ +/*------------------------------------------*/ +int main ( int argc , char ** argv ) { + + // use: + if ( argc != 2 ) { + cerr << "\nuse: nomad_for_DLL.exe param.txt\n\n"; + return 1; + } + + // NOMAD initializations: + begin ( argc , argv ); + + // display: + NOMAD::Display out ( std::cout ); + out.precision ( NOMAD::DISPLAY_PRECISION_STD ); + + // random seed: + unsigned seed = 0; + srand(seed); + + // define DLL functions: + // get handle to dll: + HINSTANCE hdll = LoadLibrary ( TEXT("bb.dll") ); + if ( !hdll ) { + cerr << "ERROR: unable to open bb.dll" << endl; + FreeLibrary ( hdll ); + return 1; + } + + // get function pointers: + get_n_dll = (GET_NM)GetProcAddress(hdll, "GET_N"); + if ( !get_n_dll ) { + cerr << "ERROR: unable to find GET_N function in dll" << endl; + FreeLibrary ( hdll ); + return 1; + } + + get_m_dll = (GET_NM)GetProcAddress(hdll, "GET_M"); + if ( !get_m_dll ) { + cerr << "ERROR: unable to find GET_M function in dll" << endl; + FreeLibrary ( hdll ); + return 1; + } + + eval_x_dll = (EVAL_X)GetProcAddress(hdll, "EVAL_X"); + if ( !eval_x_dll ) { + cerr << "ERROR: unable to find EVAL_X function in dll" << endl; + FreeLibrary ( hdll ); + return 1; + } + + /* init_dll = (INIT)GetProcAddress(hdll, "INIT"); + if ( !init_dll ) { + cerr << "ERROR: unable to find INIT function in dll" << endl; + FreeLibrary ( hdll ); + return 1; + } + + clear_dll = (INIT)GetProcAddress(hdll, "CLEAR"); + if ( !clear_dll ) { + cerr << "ERROR: unable to find CLEAR function in dll" << endl; + FreeLibrary ( hdll ); + return 1; + }*/ + + // MADS: + try { + + /* init_dll(); */ + + int n = get_n_dll(); + int m = get_m_dll(); + + // parameters creation: + // -------------------- + Parameters p ( out ); + + // dimension: + p.set_DIMENSION ( n ); + + // definition of output types: + vector<bb_output_type> bbot (m); + bbot[0] = OBJ; + for ( int i = 1 ; i < m ; ++i ) + bbot[i] = PB; + p.set_BB_OUTPUT_TYPE ( bbot ); + + // read parameters file: + p.read ( argv[1] ); + + // parameters check: + p.check(); + + // display parameters: + // out << p << endl; + + // custom evaluator creation: + My_Evaluator ev ( p , n , m ); + + // algorithm creation and execution: + Mads mads ( p , &ev ); + mads.run(); + + // algorithm display: + // out << mads << endl; + + /* clear_dll(); */ + } + catch ( exception & e ) { + cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; + } + + // Release the Dll: + FreeLibrary ( hdll ); + + NOMAD::Slave::stop_slaves ( out ); + NOMAD::end(); + + return EXIT_SUCCESS; +} diff --git a/examples/interfaces/DLL/single_obj/parameters.txt b/examples/interfaces/DLL/single_obj/param.txt similarity index 92% rename from examples/interfaces/DLL/single_obj/parameters.txt rename to examples/interfaces/DLL/single_obj/param.txt index 42f7a6f..ddbb511 100755 --- a/examples/interfaces/DLL/single_obj/parameters.txt +++ b/examples/interfaces/DLL/single_obj/param.txt @@ -1,27 +1,27 @@ -#seed 100 - -initial_mesh_size r0.1 - -direction_type ortho 2n - -max_bb_eval 1000 - -lower_bound * -10.0 - -upper_bound * 10.0 - - -x0 ( 2 3 4 5 6 ) - -display_degree 1 - -display_stats bbe ( sol ) obj - -add_seed_to_file_names no - -#stats_file toto.txt bbe obj -#solution_file "sol.txt" - -#LH_SEARCH 100 0 - -#OPPORTUNISTIC_LH no +#seed 100 + +initial_mesh_size r0.1 + +direction_type ortho 2n + +max_bb_eval 1000 + +lower_bound * -10.0 + +upper_bound * 10.0 + + +x0 ( 2 3 4 5 6 ) + +display_degree 1 + +display_stats bbe ( sol ) obj + +add_seed_to_file_names no + +#stats_file toto.txt bbe obj +#solution_file "sol.txt" + +#LH_SEARCH 100 0 + +#OPPORTUNISTIC_LH no diff --git a/examples/interfaces/DLL/single_obj/readme.txt b/examples/interfaces/DLL/single_obj/readme.txt index 7c139cb..970c9be 100755 --- a/examples/interfaces/DLL/single_obj/readme.txt +++ b/examples/interfaces/DLL/single_obj/readme.txt @@ -1,52 +1,52 @@ - -This example illustrates how to use NOMAD with a black-box -problem that is coded inside a DLL file. - -The example runs on windows with visual C++ and minGW. - - -DLL characteristics: - -/*----------*/ - -/* bb.dll */ - -/*----------*/ - - - -// init/clear: - -// ----------- - -void init_dll ( void ); - -void clear_dll ( void ); - -// problem characteristics: - -// ------------------------ - - -int get_n_dll ( void ); // number of variables - -int get_m _dll( void ); // number of outputs: output #0 : objective value to minimize - - // output #1..m-1: PB constraints with format g(x) <= 0 - - - -// evaluation: f(x): - -// ----------------- - - -void eval_x_dll ( double * x , double * fx , bool & count_eval ); - - - -// x: input , double array of size n - -// fx: output, double array of size m - -// count_eval: output, set to true if the evaluation has to be counted, false else + +This example illustrates how to use NOMAD with a black-box +problem that is coded inside a DLL file. + +The example runs on windows with visual C++ and minGW. + + +DLL characteristics: + +/*----------*/ + +/* bb.dll */ + +/*----------*/ + + + +// init/clear: + +// ----------- + +void init_dll ( void ); + +void clear_dll ( void ); + +// problem characteristics: + +// ------------------------ + + +int get_n_dll ( void ); // number of variables + +int get_m _dll( void ); // number of outputs: output #0 : objective value to minimize + + // output #1..m-1: PB constraints with format g(x) <= 0 + + + +// evaluation: f(x): + +// ----------------- + + +void eval_x_dll ( double * x , double * fx , bool & count_eval ); + + + +// x: input , double array of size n + +// fx: output, double array of size m + +// count_eval: output, set to true if the evaluation has to be counted, false else diff --git a/examples/interfaces/GAMS/bb.gms b/examples/interfaces/GAMS/bb.gms index a68edb8..7659730 100644 --- a/examples/interfaces/GAMS/bb.gms +++ b/examples/interfaces/GAMS/bb.gms @@ -1,321 +1,321 @@ - -Set t time periods -/ -2005, 2015, 2025, 2035, 2045, 2055, 2065, 2075, 2085, 2095, -2105, 2115, 2125, 2135, 2145, 2155, 2165, 2175, 2185, 2195, -2205, 2215, 2225, 2235, 2245, 2255, 2265, 2275, 2285, 2295, -2305, 2315, 2325, 2335, 2345, 2355, 2365, 2375, 2385, 2395, -2405 -/ - -subtGDP(t) indice sommation GDP -/ -2005, 2015, 2025, 2035, 2045, 2055, 2065, 2075, 2085, 2095 -/ - -subtem(t) indice sommation emissions -/ -2005, 2015, 2025, 2035, 2045, 2055, 2065, 2075, 2085 -/ -; - -Set ts(t) time periods -/ -2005, 2015, 2025, 2035, 2045, 2055, 2065, 2075, 2085, 2095, -2105, 2115, 2125, 2135, 2145, 2155, 2165, 2175, 2185, 2195, -2205, 2215, 2225, 2235, 2245, 2255, 2265, 2275, 2285, 2295, -2305, 2315, 2325, 2335, 2345, 2355, 2365, 2375, 2385, 2395, -2405 -/; - -Set tfirst(t) first time period; -tfirst(t) = YES$(ord(t) eq 1); - -Set tlast(t) last time period; -tlast(t) = YES$(ord(t) eq card(t)); - -Parameter nbp(t) number of periods since 2005 -/ - 2005 0, 2015 1, 2025 2, 2035 3, 2045 4, 2055 5, 2065 6, 2075 7, 2085 8, - 2095 9, 2105 10, 2115 11, 2125 12, 2135 13, 2145 14, 2155 15, 2165 16, - 2175 17, 2185 18, 2195 19, 2205 20, 2215 21, 2225 22, 2235 23, 2245 24, - 2255 25, 2265 26, 2275 27, 2285 28, 2295 29, 2305 30, 2315 31, 2325 32, - 2335 33, 2345 34, 2355 35, 2365 36, 2375 37, 2385 38, 2395 39, 2405 40 -/; - -Parameter nby(t) number of years since 2005 -/ - 2005 0, 2015 10, 2025 20, 2035 30, 2045 40, 2055 50, 2065 60, 2075 70, 2085 80, - 2095 90, 2105 100, 2115 110, 2125 120, 2135 130, 2145 140, 2155 150, 2165 160, - 2175 170, 2185 180, 2195 190, 2205 200, 2215 210, 2225 220, 2235 230, 2245 240, - 2255 250, 2265 260, 2275 270, 2285 280, 2295 290, 2305 300, 2315 310, 2325 320, - 2335 330, 2345 340, 2355 350, 2365 360, 2375 370, 2385 380, 2395 390, 2405 400 -/; - -Parameter xi(t) indicator for the clean economy -/ - 2005 1, 2015 1, 2025 1, 2035 1, 2045 1, 2055 1, 2065 1, 2075 1, 2085 1, - 2095 1, 2105 1, 2115 1, 2125 1, 2135 1, 2145 1, 2155 1, 2165 1, 2175 1, - 2185 1, 2195 1, 2205 1, 2215 1, 2225 1, 2235 1, 2245 1, 2255 1, 2265 1, - 2275 1, 2285 1, 2295 1, 2305 1, 2315 1, 2325 1, 2335 1, 2345 1, 2355 1, - 2365 1, 2375 1, 2385 1, 2395 1, 2405 1 -/; -$ontext -/ - 2005 0, 2015 0, 2025 0, 2035 0, 2045 0, 2055 0, 2065 0, 2075 0, 2085 0, - 2095 0, 2105 0, 2115 0, 2125 0, 2135 0, 2145 0, 2155 0, 2165 0, 2175 0, - 2185 0, 2195 0, 2205 0, 2215 0, 2225 0, 2235 0, 2245 0, 2255 0, 2265 0, - 2275 0, 2285 0, 2295 0, 2305 0, 2315 0, 2325 0, 2335 0, 2345 0, 2355 0, - 2365 0, 2375 0, 2385 0, 2395 0, 2405 0 -/; -$offtext - -Parameter GDP(t) GDP donne par le scenario B2MESSAGE par moyenne simple -/ - 2005 49.84, 2015 66.53, 2025 86.94, 2035 112.9, 2045 145.3, 2055 182.0, 2065 220.7, 2075 259.1, 2085 295.5, - 2095 331.7, 2105 0, 2115 0, 2125 0, 2135 0, 2145 0, 2155 0, 2165 0, 2175 0, - 2185 0, 2195 0, 2205 0, 2215 0, 2225 0, 2235 0, 2245 0, 2255 0, 2265 0, - 2275 0, 2285 0, 2295 0, 2305 0, 2315 0, 2325 0, 2335 0, 2345 0, 2355 0, - 2365 0, 2375 0, 2385 0, 2395 0, 2405 0 -/; - -Parameter emissionB2(t) emission CO2 par decennie donne par le scenario B2MESSAGE par moyenne simple -/ - 2005 8.65, 2015 9.19, 2025 9.88, 2035 10.57, 2045 11.05, 2055 11.40, 2065 11.72, 2075 12.18, 2085 12.76, - 2095 0, 2105 0, 2115 0, 2125 0, 2135 0, 2145 0, 2155 0, 2165 0, 2175 0, - 2185 0, 2195 0, 2205 0, 2215 0, 2225 0, 2235 0, 2245 0, 2255 0, 2265 0, - 2275 0, 2285 0, 2295 0, 2305 0, 2315 0, 2325 0, 2335 0, 2345 0, 2355 0, - 2365 0, 2375 0, 2385 0, 2395 0, 2405 0 -/; - -Scalars - borneinf borne inferieure de DICE /0.9/ - bornesup borne superieure de DICE /1.1/ - deltaalpha ecart entre modeles DICE et GERAD /0/ - deltaGDP ecart DICE GERAD pour le GDP /0/ - deltaem idem /0/ - moyenneGDP moyenne GDP B2-message /175.05/ - moyenneem idem /10.82/ - - vb slope w.r.t K2(t) of the probability rate of discovery /0.0019/ - wb initial probability rate of discovery /0.05/ - beta marginal atmospheric retention rate /0.64/ - catM catastrophic carbon concentration /2059.0/ - delta_M carbon removal rate per decade /0.036/ -* mtargM target for carbon concentration /1025.00/ - mtargM target for carbon concentration /5000.00/ - piE1 initial energy price in dirty economy /0.35/ - piE2 initial energy price in clean economy /0.60/ - rhop discount rate /0.025/ - - prstp initial rate of social time preference per year /0.015/ - dr decline rate of social time preference per year /0.000001/ - rho discount rate /0.03/ - - L0 2005 world population (millions) /6409/ - gL0 initial value for growth rate of population /0.08/ - dgL rate of decrease for growth rate of population /0.3/ - - scale1 scaling coefficient in objective function /300/ - scale2 scaling coefficient in objective function /1.00E+07/ - -*Scalaires calibres -$include "input.txt"; - -; - -*Initialisation des parametres -Parameter L(t) labor - world population (millions); -L(t) = L0 * exp( (gl0/dgL)*(1-exp( -dgL*nbp(t) )) ); - -Parameter r(t) instantaeous rate of social time preference; -r(t)=prstp*EXP(-dr*10*(ord(t)-1)); - -Parameter rr(t) average utility social discount rate; -rr(tfirst)=1; -loop(t, rr(t+1) = rr(t) / ((1+r(t))**10) ); - -Parameter A(t) total factor productivity; -A(tfirst) = 1.38734*A0; -*loop(t, A(t+1) = A(t) / (1-gA0*exp(-dgA*10*nbp(t))) ); -A(t) = 1.38734*A0 * exp( (gA0/dgA)*(1-exp( -dgA*nbp(t) )) ); - -Parameter phid(t) energy efficiency in the dirty economy; -phid(t) = (phid0 * exp( (-gphid0/dgphid)*exp(-dgphid*(nbp(t)+1)) ) ) / - exp(-gphid0/dgphid); - -Parameter phic(t) energy efficiency in the clean economy; -phic(t) = (phic0 * exp( (-gphic0/dgphic)*exp(-dgphic*(nbp(t)+1)) ) ) / - exp(-gphic0/dgphic); - -Parameter thetad(t) dirty energy elasticity in production function; -thetad(t) = (thetad0 * exp( (gthetad0/dgthetad)*exp(-dgthetad*(nbp(t)+1)) ) ) / - exp(gthetad0/dgthetad); - -Parameter thetac(t) clean energy elasticity in production function; -thetac(t) = (thetac0 * exp( (gthetac0/dgthetac)*exp(-dgthetac*(nbp(t)+1)) ) ) / - exp(gthetac0/dgthetac); - -Parameter EM(t) total emissions (over 10 years); -EM(t) = 0; - -Parameter TK(t) total capital; -TK(t) = 0; - -Parameter deltaalphaGDP(t) ecart courant entre GDP de DICE et GERAD; -deltaalphaGDP(t) = 0; - -*Definition du modele -Positive variables - C(t) total consumption (trillion dollars) - ELF(t) economic loss factor (%) - E1(t) carbon emissions from the dirty economy (GtC) - E2(t) carbon emissions from the clean economy (GtC) - I1(t) investment in dirty capital K1 (trillion dollars) - I2(t) investment in clean capital K2 (trillion dollars) - K1(t) physical stock of dirty capital (trillion dollars) - K2(t) physical stock of clean capital (trillion dollars) - L1(t) labor for the dirty economy (millions) - L2(t) labor for the clean economy (millions) - M(t) atmospheric carbon concentration - Y(t) economic output (trillion dollars); - -Variables - PW(t) welfare of current period - W2 total discounted welfare after the last jump (V_2-1-l); - -Equations - ALOCLABOR(t) compute allocation of total labor - CARBDYNAM(t) compute evolution of carbon concentrations - E1FIRST(t) initial value for carbon emissions from dirty capital - E2FIRST(t) initial value for carbon emissions from clean capital - ELFCOMP(t) compute economic loss factor - I2MAX(t) bound for investment on clean capital - K1ACCUMUL(t) compute dirty capital accumulation - K1FIRST(t) initial value for dirty capital - K1LAST(t) final value for dirty capital - K2ACCUMUL(t) compute clean capital accumulation - K2FIRST(t) initial value for clean capital - K2LAST(t) final value for clean capital - MFIRST(t) initial value for carbon concentration - TARGETM(t) impose cap on atmospheric carbon concentrations - TOTALCONS(t) compute total consumption - TOTALPROD(t) compute total production - PWEQ(t) compute welfare of current period - WELFARE2 compute total welfare after the last jump; - -ALOCLABOR(t).. - L1(t) + L2(t) =l= L(t); - -CARBDYNAM(t+1).. - M(t+1) =e= beta*10*(E1(t)+E2(t)) + M(t)*(1-delta_M) + delta_M*590; - -MFIRST(tfirst).. -* 2005 value around 385 ppmv = 808.8 GtC - M(tfirst) =e= 808.8; - -ELFCOMP(t).. - ELF(t) =e= 1; - -E1FIRST(tfirst).. -* DICE-2007 value - E1(tfirst) =e= 6.7; - -E2FIRST(tfirst).. -* 0.0001 of DICE-2007 value - E2(tfirst) =e= 0.00067; - -I2MAX(t).. - I2(t) =l= 0.97*Y(t); - -K1FIRST(tfirst).. - K1(tfirst) =e= 137.0; - -K1ACCUMUL(t).. - K1(t+1) =l= K1(t)*(1-dk)**10 + 10*I1(t); - -K1LAST(tlast).. - 0.02*K1(tlast) =l= I1(tlast); - -K2FIRST(tfirst).. - K2(tfirst) =e= 0.0137; - -K2ACCUMUL(t).. - K2(t+1) =l= K2(t)*(1-dk)**10 + 10*I2(t); - -K2LAST(tlast).. - 0.02*K2(tlast) =l= I2(tlast); - -TARGETM(t).. -* Constraint is always active - M(t) =l= mtargM; - -TOTALPROD(t).. - Y(t) =e= A(t) * ( - K1(t)**alphad * (phid(t)*E1(t))**thetad(t) * L1(t)**(1-alphad-thetad(t)) + - xi(t)*K2(t)**alphac * (phic(t)*E2(t))**thetac(t) * L2(t)**(1-alphac-thetac(t)) - ); - -TOTALCONS(t).. - C(t) =e= Y(t) - I1(t) - I2(t) - piE1*phid(t)*E1(t) - piE2*phic(t)*E2(t); - -PWEQ(t).. - PW(t) =e= ( (ELF(t)*C(t)/L(t))**(1-elasmu) -1) / (1-elasmu); - -WELFARE2.. - W2 =e= sum(t, 10*exp(-rho*nby(t))*L(t)*(PW(t))/scale1) + scale2 ; - -Model ECM /all/ ; -ECM.OPTFILE =1; - -C.lo(t) = 1; -C.up(t) = 1000; -E1.lo(t) = 0.0000001; -E1.up(t) = 500; -E2.lo(t) = 0.0000001; -E2.up(t) = 100; -ELF.lo(t) = 0.5; -ELF.up(t) = 1.0; -I1.lo(t) = 0.000000001; -I1.up(t) = 1000; -I2.lo(t) = 0.000000001; -I2.up(t) = 1000; -K1.lo(t) = 0.01; -K1.up(t) = 3000; -K2.lo(t) = 0.000000001; -K2.up(t) = 3000; -L1.lo(t) = 0.1; -L1.up(t) = 10000; -L2.lo(t) = 0.000000001; -L2.up(t) = 10000; -M.lo(t) = 300; -M.up(t) = 4000; -Y.lo(t) = 50; -Y.up(t) = 1000; - -option iterlim = 99900; -option reslim = 99999; -option solprint = off; -option limrow = 0; -option limcol = 0; - -Solve ECM using nlp maximising W2; - -EM(t) = E1.L(t)+E2.L(t); -TK(t) = K1.L(t)+K2.L(t); - -deltaalphaGDP(t) = Y.L(t)-GDP(t); -deltaGDP = sum ( subtGDP(t) , sqr(deltaalphaGDP(t)) ); -deltaem = sum ( subtem(t) , sqr(EM(t)-emissionB2(t)) ); -deltaalpha = deltaGDP / moyenneGDP + deltaem / moyenneem ; - -file FOUT / output.txt /; -put FOUT; -put deltaalpha:13:6; -putclose; - - - - - - + +Set t time periods +/ +2005, 2015, 2025, 2035, 2045, 2055, 2065, 2075, 2085, 2095, +2105, 2115, 2125, 2135, 2145, 2155, 2165, 2175, 2185, 2195, +2205, 2215, 2225, 2235, 2245, 2255, 2265, 2275, 2285, 2295, +2305, 2315, 2325, 2335, 2345, 2355, 2365, 2375, 2385, 2395, +2405 +/ + +subtGDP(t) indice sommation GDP +/ +2005, 2015, 2025, 2035, 2045, 2055, 2065, 2075, 2085, 2095 +/ + +subtem(t) indice sommation emissions +/ +2005, 2015, 2025, 2035, 2045, 2055, 2065, 2075, 2085 +/ +; + +Set ts(t) time periods +/ +2005, 2015, 2025, 2035, 2045, 2055, 2065, 2075, 2085, 2095, +2105, 2115, 2125, 2135, 2145, 2155, 2165, 2175, 2185, 2195, +2205, 2215, 2225, 2235, 2245, 2255, 2265, 2275, 2285, 2295, +2305, 2315, 2325, 2335, 2345, 2355, 2365, 2375, 2385, 2395, +2405 +/; + +Set tfirst(t) first time period; +tfirst(t) = YES$(ord(t) eq 1); + +Set tlast(t) last time period; +tlast(t) = YES$(ord(t) eq card(t)); + +Parameter nbp(t) number of periods since 2005 +/ + 2005 0, 2015 1, 2025 2, 2035 3, 2045 4, 2055 5, 2065 6, 2075 7, 2085 8, + 2095 9, 2105 10, 2115 11, 2125 12, 2135 13, 2145 14, 2155 15, 2165 16, + 2175 17, 2185 18, 2195 19, 2205 20, 2215 21, 2225 22, 2235 23, 2245 24, + 2255 25, 2265 26, 2275 27, 2285 28, 2295 29, 2305 30, 2315 31, 2325 32, + 2335 33, 2345 34, 2355 35, 2365 36, 2375 37, 2385 38, 2395 39, 2405 40 +/; + +Parameter nby(t) number of years since 2005 +/ + 2005 0, 2015 10, 2025 20, 2035 30, 2045 40, 2055 50, 2065 60, 2075 70, 2085 80, + 2095 90, 2105 100, 2115 110, 2125 120, 2135 130, 2145 140, 2155 150, 2165 160, + 2175 170, 2185 180, 2195 190, 2205 200, 2215 210, 2225 220, 2235 230, 2245 240, + 2255 250, 2265 260, 2275 270, 2285 280, 2295 290, 2305 300, 2315 310, 2325 320, + 2335 330, 2345 340, 2355 350, 2365 360, 2375 370, 2385 380, 2395 390, 2405 400 +/; + +Parameter xi(t) indicator for the clean economy +/ + 2005 1, 2015 1, 2025 1, 2035 1, 2045 1, 2055 1, 2065 1, 2075 1, 2085 1, + 2095 1, 2105 1, 2115 1, 2125 1, 2135 1, 2145 1, 2155 1, 2165 1, 2175 1, + 2185 1, 2195 1, 2205 1, 2215 1, 2225 1, 2235 1, 2245 1, 2255 1, 2265 1, + 2275 1, 2285 1, 2295 1, 2305 1, 2315 1, 2325 1, 2335 1, 2345 1, 2355 1, + 2365 1, 2375 1, 2385 1, 2395 1, 2405 1 +/; +$ontext +/ + 2005 0, 2015 0, 2025 0, 2035 0, 2045 0, 2055 0, 2065 0, 2075 0, 2085 0, + 2095 0, 2105 0, 2115 0, 2125 0, 2135 0, 2145 0, 2155 0, 2165 0, 2175 0, + 2185 0, 2195 0, 2205 0, 2215 0, 2225 0, 2235 0, 2245 0, 2255 0, 2265 0, + 2275 0, 2285 0, 2295 0, 2305 0, 2315 0, 2325 0, 2335 0, 2345 0, 2355 0, + 2365 0, 2375 0, 2385 0, 2395 0, 2405 0 +/; +$offtext + +Parameter GDP(t) GDP donne par le scenario B2MESSAGE par moyenne simple +/ + 2005 49.84, 2015 66.53, 2025 86.94, 2035 112.9, 2045 145.3, 2055 182.0, 2065 220.7, 2075 259.1, 2085 295.5, + 2095 331.7, 2105 0, 2115 0, 2125 0, 2135 0, 2145 0, 2155 0, 2165 0, 2175 0, + 2185 0, 2195 0, 2205 0, 2215 0, 2225 0, 2235 0, 2245 0, 2255 0, 2265 0, + 2275 0, 2285 0, 2295 0, 2305 0, 2315 0, 2325 0, 2335 0, 2345 0, 2355 0, + 2365 0, 2375 0, 2385 0, 2395 0, 2405 0 +/; + +Parameter emissionB2(t) emission CO2 par decennie donne par le scenario B2MESSAGE par moyenne simple +/ + 2005 8.65, 2015 9.19, 2025 9.88, 2035 10.57, 2045 11.05, 2055 11.40, 2065 11.72, 2075 12.18, 2085 12.76, + 2095 0, 2105 0, 2115 0, 2125 0, 2135 0, 2145 0, 2155 0, 2165 0, 2175 0, + 2185 0, 2195 0, 2205 0, 2215 0, 2225 0, 2235 0, 2245 0, 2255 0, 2265 0, + 2275 0, 2285 0, 2295 0, 2305 0, 2315 0, 2325 0, 2335 0, 2345 0, 2355 0, + 2365 0, 2375 0, 2385 0, 2395 0, 2405 0 +/; + +Scalars + borneinf borne inferieure de DICE /0.9/ + bornesup borne superieure de DICE /1.1/ + deltaalpha ecart entre modeles DICE et GERAD /0/ + deltaGDP ecart DICE GERAD pour le GDP /0/ + deltaem idem /0/ + moyenneGDP moyenne GDP B2-message /175.05/ + moyenneem idem /10.82/ + + vb slope w.r.t K2(t) of the probability rate of discovery /0.0019/ + wb initial probability rate of discovery /0.05/ + beta marginal atmospheric retention rate /0.64/ + catM catastrophic carbon concentration /2059.0/ + delta_M carbon removal rate per decade /0.036/ +* mtargM target for carbon concentration /1025.00/ + mtargM target for carbon concentration /5000.00/ + piE1 initial energy price in dirty economy /0.35/ + piE2 initial energy price in clean economy /0.60/ + rhop discount rate /0.025/ + + prstp initial rate of social time preference per year /0.015/ + dr decline rate of social time preference per year /0.000001/ + rho discount rate /0.03/ + + L0 2005 world population (millions) /6409/ + gL0 initial value for growth rate of population /0.08/ + dgL rate of decrease for growth rate of population /0.3/ + + scale1 scaling coefficient in objective function /300/ + scale2 scaling coefficient in objective function /1.00E+07/ + +*Scalaires calibres +$include "input.txt"; + +; + +*Initialisation des parametres +Parameter L(t) labor - world population (millions); +L(t) = L0 * exp( (gl0/dgL)*(1-exp( -dgL*nbp(t) )) ); + +Parameter r(t) instantaeous rate of social time preference; +r(t)=prstp*EXP(-dr*10*(ord(t)-1)); + +Parameter rr(t) average utility social discount rate; +rr(tfirst)=1; +loop(t, rr(t+1) = rr(t) / ((1+r(t))**10) ); + +Parameter A(t) total factor productivity; +A(tfirst) = 1.38734*A0; +*loop(t, A(t+1) = A(t) / (1-gA0*exp(-dgA*10*nbp(t))) ); +A(t) = 1.38734*A0 * exp( (gA0/dgA)*(1-exp( -dgA*nbp(t) )) ); + +Parameter phid(t) energy efficiency in the dirty economy; +phid(t) = (phid0 * exp( (-gphid0/dgphid)*exp(-dgphid*(nbp(t)+1)) ) ) / + exp(-gphid0/dgphid); + +Parameter phic(t) energy efficiency in the clean economy; +phic(t) = (phic0 * exp( (-gphic0/dgphic)*exp(-dgphic*(nbp(t)+1)) ) ) / + exp(-gphic0/dgphic); + +Parameter thetad(t) dirty energy elasticity in production function; +thetad(t) = (thetad0 * exp( (gthetad0/dgthetad)*exp(-dgthetad*(nbp(t)+1)) ) ) / + exp(gthetad0/dgthetad); + +Parameter thetac(t) clean energy elasticity in production function; +thetac(t) = (thetac0 * exp( (gthetac0/dgthetac)*exp(-dgthetac*(nbp(t)+1)) ) ) / + exp(gthetac0/dgthetac); + +Parameter EM(t) total emissions (over 10 years); +EM(t) = 0; + +Parameter TK(t) total capital; +TK(t) = 0; + +Parameter deltaalphaGDP(t) ecart courant entre GDP de DICE et GERAD; +deltaalphaGDP(t) = 0; + +*Definition du modele +Positive variables + C(t) total consumption (trillion dollars) + ELF(t) economic loss factor (%) + E1(t) carbon emissions from the dirty economy (GtC) + E2(t) carbon emissions from the clean economy (GtC) + I1(t) investment in dirty capital K1 (trillion dollars) + I2(t) investment in clean capital K2 (trillion dollars) + K1(t) physical stock of dirty capital (trillion dollars) + K2(t) physical stock of clean capital (trillion dollars) + L1(t) labor for the dirty economy (millions) + L2(t) labor for the clean economy (millions) + M(t) atmospheric carbon concentration + Y(t) economic output (trillion dollars); + +Variables + PW(t) welfare of current period + W2 total discounted welfare after the last jump (V_2-1-l); + +Equations + ALOCLABOR(t) compute allocation of total labor + CARBDYNAM(t) compute evolution of carbon concentrations + E1FIRST(t) initial value for carbon emissions from dirty capital + E2FIRST(t) initial value for carbon emissions from clean capital + ELFCOMP(t) compute economic loss factor + I2MAX(t) bound for investment on clean capital + K1ACCUMUL(t) compute dirty capital accumulation + K1FIRST(t) initial value for dirty capital + K1LAST(t) final value for dirty capital + K2ACCUMUL(t) compute clean capital accumulation + K2FIRST(t) initial value for clean capital + K2LAST(t) final value for clean capital + MFIRST(t) initial value for carbon concentration + TARGETM(t) impose cap on atmospheric carbon concentrations + TOTALCONS(t) compute total consumption + TOTALPROD(t) compute total production + PWEQ(t) compute welfare of current period + WELFARE2 compute total welfare after the last jump; + +ALOCLABOR(t).. + L1(t) + L2(t) =l= L(t); + +CARBDYNAM(t+1).. + M(t+1) =e= beta*10*(E1(t)+E2(t)) + M(t)*(1-delta_M) + delta_M*590; + +MFIRST(tfirst).. +* 2005 value around 385 ppmv = 808.8 GtC + M(tfirst) =e= 808.8; + +ELFCOMP(t).. + ELF(t) =e= 1; + +E1FIRST(tfirst).. +* DICE-2007 value + E1(tfirst) =e= 6.7; + +E2FIRST(tfirst).. +* 0.0001 of DICE-2007 value + E2(tfirst) =e= 0.00067; + +I2MAX(t).. + I2(t) =l= 0.97*Y(t); + +K1FIRST(tfirst).. + K1(tfirst) =e= 137.0; + +K1ACCUMUL(t).. + K1(t+1) =l= K1(t)*(1-dk)**10 + 10*I1(t); + +K1LAST(tlast).. + 0.02*K1(tlast) =l= I1(tlast); + +K2FIRST(tfirst).. + K2(tfirst) =e= 0.0137; + +K2ACCUMUL(t).. + K2(t+1) =l= K2(t)*(1-dk)**10 + 10*I2(t); + +K2LAST(tlast).. + 0.02*K2(tlast) =l= I2(tlast); + +TARGETM(t).. +* Constraint is always active + M(t) =l= mtargM; + +TOTALPROD(t).. + Y(t) =e= A(t) * ( + K1(t)**alphad * (phid(t)*E1(t))**thetad(t) * L1(t)**(1-alphad-thetad(t)) + + xi(t)*K2(t)**alphac * (phic(t)*E2(t))**thetac(t) * L2(t)**(1-alphac-thetac(t)) + ); + +TOTALCONS(t).. + C(t) =e= Y(t) - I1(t) - I2(t) - piE1*phid(t)*E1(t) - piE2*phic(t)*E2(t); + +PWEQ(t).. + PW(t) =e= ( (ELF(t)*C(t)/L(t))**(1-elasmu) -1) / (1-elasmu); + +WELFARE2.. + W2 =e= sum(t, 10*exp(-rho*nby(t))*L(t)*(PW(t))/scale1) + scale2 ; + +Model ECM /all/ ; +ECM.OPTFILE =1; + +C.lo(t) = 1; +C.up(t) = 1000; +E1.lo(t) = 0.0000001; +E1.up(t) = 500; +E2.lo(t) = 0.0000001; +E2.up(t) = 100; +ELF.lo(t) = 0.5; +ELF.up(t) = 1.0; +I1.lo(t) = 0.000000001; +I1.up(t) = 1000; +I2.lo(t) = 0.000000001; +I2.up(t) = 1000; +K1.lo(t) = 0.01; +K1.up(t) = 3000; +K2.lo(t) = 0.000000001; +K2.up(t) = 3000; +L1.lo(t) = 0.1; +L1.up(t) = 10000; +L2.lo(t) = 0.000000001; +L2.up(t) = 10000; +M.lo(t) = 300; +M.up(t) = 4000; +Y.lo(t) = 50; +Y.up(t) = 1000; + +option iterlim = 99900; +option reslim = 99999; +option solprint = off; +option limrow = 0; +option limcol = 0; + +Solve ECM using nlp maximising W2; + +EM(t) = E1.L(t)+E2.L(t); +TK(t) = K1.L(t)+K2.L(t); + +deltaalphaGDP(t) = Y.L(t)-GDP(t); +deltaGDP = sum ( subtGDP(t) , sqr(deltaalphaGDP(t)) ); +deltaem = sum ( subtem(t) , sqr(EM(t)-emissionB2(t)) ); +deltaalpha = deltaGDP / moyenneGDP + deltaem / moyenneem ; + +file FOUT / output.txt /; +put FOUT; +put deltaalpha:13:6; +putclose; + + + + + + diff --git a/examples/interfaces/GAMS/ed.hup b/examples/interfaces/GAMS/ed.hup index 85bca40..4cce1c4 100644 --- a/examples/interfaces/GAMS/ed.hup +++ b/examples/interfaces/GAMS/ed.hup @@ -1,13 +1,13 @@ - -This example illustrates how to use NOMAD with a GAMS black-box problem. - -The example runs on windows. - -The GAMS program is located in file bb.gms. - -The source code is in bb.cpp: it is a C++ wrapper that calls GAMS. -It can be compiled with visual C++ or minGW. - -The wrapper can be tested with the command 'bb.exe .\points\x0.txt'. - + +This example illustrates how to use NOMAD with a GAMS black-box problem. + +The example runs on windows. + +The GAMS program is located in file bb.gms. + +The source code is in bb.cpp: it is a C++ wrapper that calls GAMS. +It can be compiled with visual C++ or minGW. + +The wrapper can be tested with the command 'bb.exe .\points\x0.txt'. + Once the wrapper is compiled, use nomad with the parameters file parameters.txt. diff --git a/examples/interfaces/GAMS/lb.txt b/examples/interfaces/GAMS/lb.txt index a45ca61..542b27d 100644 --- a/examples/interfaces/GAMS/lb.txt +++ b/examples/interfaces/GAMS/lb.txt @@ -1,19 +1,19 @@ -2.25 -0.027 -0.09 -0.18 -0.27 -0.27 -0.09 -0.9 -0.13 -0.27 -4.5 -0.13 -0.27 -0.045 -0 -0.007 -0.045 -0 +2.25 +0.027 +0.09 +0.18 +0.27 +0.27 +0.09 +0.9 +0.13 +0.27 +4.5 +0.13 +0.27 +0.045 +0 +0.007 +0.045 +0 0.007 \ No newline at end of file diff --git a/examples/interfaces/GAMS/parameters.txt b/examples/interfaces/GAMS/param.txt similarity index 94% rename from examples/interfaces/GAMS/parameters.txt rename to examples/interfaces/GAMS/param.txt index 62b7279..0c41dfa 100644 --- a/examples/interfaces/GAMS/parameters.txt +++ b/examples/interfaces/GAMS/param.txt @@ -1,31 +1,31 @@ ##### # NOMAD PARAMETERS # -#### +#### - -SEED NONE - -DIMENSION 19 -DISPLAY_DEGREE 1 -DISPLAY_STATS BBE OBJ -BB_EXE bb.exe +SEED NONE -BB_OUTPUT_TYPE OBJ +DIMENSION 19 +DISPLAY_DEGREE 1 +DISPLAY_STATS BBE OBJ -BB_INPUT_INCLUDE_SEED yes +BB_EXE bb.exe -BB_INPUT_INCLUDE_TAG yes +BB_OUTPUT_TYPE OBJ - +BB_INPUT_INCLUDE_SEED yes +BB_INPUT_INCLUDE_TAG yes -x0 x0.txt -lower_bound lb.txt -upper_bound ub.txt - + + +x0 x0.txt +lower_bound lb.txt + +upper_bound ub.txt + diff --git a/examples/interfaces/GAMS/points/x0.txt b/examples/interfaces/GAMS/points/x0.txt index d7b79a8..d99f74e 100644 --- a/examples/interfaces/GAMS/points/x0.txt +++ b/examples/interfaces/GAMS/points/x0.txt @@ -1,22 +1,22 @@ -0 0 +0 0 2.5 - + 0.0302 - -0.1 -0.2 -0.3 -0.3 -0.1 -1.0 -0.15 -0.3 -5.0 -0.15 -0.3 -0.05 -0 -0.008 -0.05 -0 + +0.1 +0.2 +0.3 +0.3 +0.1 +1.0 +0.15 +0.3 +5.0 +0.15 +0.3 +0.05 +0 +0.008 +0.05 +0 0.008 \ No newline at end of file diff --git a/examples/interfaces/GAMS/points/x1.txt b/examples/interfaces/GAMS/points/x1.txt index d1a6bea..1e6f158 100644 --- a/examples/interfaces/GAMS/points/x1.txt +++ b/examples/interfaces/GAMS/points/x1.txt @@ -1,20 +1,20 @@ -0 0 -2.25 -0.027 -0.09 -0.18 -0.27 -0.27 -0.09 -0.9 -0.13 -0.27 -4.5 -0.13 -0.27 -0.045 -0 -0.007 -0.045 -0 +0 0 +2.25 +0.027 +0.09 +0.18 +0.27 +0.27 +0.09 +0.9 +0.13 +0.27 +4.5 +0.13 +0.27 +0.045 +0 +0.007 +0.045 +0 0.007 \ No newline at end of file diff --git a/examples/interfaces/GAMS/points/x2.txt b/examples/interfaces/GAMS/points/x2.txt index bdf4951..3242adc 100644 --- a/examples/interfaces/GAMS/points/x2.txt +++ b/examples/interfaces/GAMS/points/x2.txt @@ -1,25 +1,25 @@ -0 0 +0 0 2.75 - -0.033 + +0.033 0.11 - + 0.22 - + 0.33 - + 0.33 - -0.11 -1.1 -0.17 -0.33 -5.5 -0.17 -0.33 -0.055 -0.5 -0.009 -0.055 -0.5 + +0.11 +1.1 +0.17 +0.33 +5.5 +0.17 +0.33 +0.055 +0.5 +0.009 +0.055 +0.5 0.009 \ No newline at end of file diff --git a/examples/interfaces/GAMS/readme.txt b/examples/interfaces/GAMS/readme.txt index 390c172..4cce1c4 100644 --- a/examples/interfaces/GAMS/readme.txt +++ b/examples/interfaces/GAMS/readme.txt @@ -1,13 +1,13 @@ - -This example illustrates how to use NOMAD with a GAMS black-box problem. - -The example runs on windows. - -The GAMS program is located in file bb.gms. - -The source code is in bb.cpp: it is a C++ wrapper that calls GAMS. -It can be compiled with visual C++ or minGW. - -The wrapper can be tested with the command 'bb.exe .\points\x0.txt'. - -Once the wrapper is compiled, use nomad with the parameters file parameters.txt. + +This example illustrates how to use NOMAD with a GAMS black-box problem. + +The example runs on windows. + +The GAMS program is located in file bb.gms. + +The source code is in bb.cpp: it is a C++ wrapper that calls GAMS. +It can be compiled with visual C++ or minGW. + +The wrapper can be tested with the command 'bb.exe .\points\x0.txt'. + +Once the wrapper is compiled, use nomad with the parameters file parameters.txt. diff --git a/examples/interfaces/GAMS/ub.txt b/examples/interfaces/GAMS/ub.txt index b543382..025836a 100644 --- a/examples/interfaces/GAMS/ub.txt +++ b/examples/interfaces/GAMS/ub.txt @@ -1,24 +1,24 @@ 2.75 - -0.033 + +0.033 0.11 - + 0.22 - + 0.33 - + 0.33 - -0.11 -1.1 -0.17 -0.33 -5.5 -0.17 -0.33 -0.055 -0.5 -0.009 -0.055 -0.5 + +0.11 +1.1 +0.17 +0.33 +5.5 +0.17 +0.33 +0.055 +0.5 +0.009 +0.055 +0.5 0.009 \ No newline at end of file diff --git a/examples/interfaces/GAMS/x0.txt b/examples/interfaces/GAMS/x0.txt index b6b3974..e82d42d 100644 --- a/examples/interfaces/GAMS/x0.txt +++ b/examples/interfaces/GAMS/x0.txt @@ -1,21 +1,21 @@ 2.5 - + 0.0302 - -0.1 -0.2 -0.3 -0.3 -0.1 -1.0 -0.15 -0.3 -5.0 -0.15 -0.3 -0.05 -0 -0.008 -0.05 -0 + +0.1 +0.2 +0.3 +0.3 +0.1 +1.0 +0.15 +0.3 +5.0 +0.15 +0.3 +0.05 +0 +0.008 +0.05 +0 0.008 \ No newline at end of file diff --git a/examples/interfaces/Matlab_MEX/GERAD_NOMAD_build.m b/examples/interfaces/Matlab_MEX/GERAD_NOMAD_build.m new file mode 100644 index 0000000..36eee6c --- /dev/null +++ b/examples/interfaces/Matlab_MEX/GERAD_NOMAD_build.m @@ -0,0 +1,79 @@ +%% GERAD NOMAD Build for Matlab + +% This file will help you compile NOMAD for use with MATLAB. + +% To recompile you will need to get / do the following: + +% 1) Get NOMAD +% NOMAD is available from http://www.gerad.ca/NOMAD/PHP_Forms/Download.php. +% Complete the download form then download the latest version. Define the +% $NOMAD_HOME environment variable. + +% 2) NOMAD MEX Interface +% The NOMAD MEX Interface is a simple MEX interface written to use NOMAD. + +% 3) Compile the MEX File +% The code below will build the NOMAD MEX file. Once you have completed all the +% above steps, simply run this file to compile NOMAD! You MUST BE in the +% base directory of OPTI! + +clear nomad + +switch(computer) +case 'PCWIN' +libdir = ' -Lwin32\'; +case 'PCWIN64' +libdir = ' -Lwin64\'; +case 'GLNX86' +libdir = 'glnx86/'; +case 'GLNXA64' +libdir = 'glnxa64/'; +case 'MACI64' +libdir = 'maci64/'; +end + +clear nomad_home nomad_src; + + +fprintf('\n------------------------------------------------\n'); +fprintf('NOMAD MEX FILE BUILD --- GERAD VERSION \n\n'); + +nomad_home = getenv('NOMAD_HOME'); +if (length(nomad_home)<1) + error('opti:nomad','Please set NOMAD_HOME variables properly with the command setenv(''NOMAD_HOME'',ARG1)!'); +end +nomad_src=[nomad_home filesep 'src' filesep]; + + +%Get NOMAD Libraries +post = [' -I. -I' nomad_src ' -lm -lut -output nomad']; + +%CD to Source Directory +cdir = cd; +cd 'Source'; + +%Compile & Move +pre = ['mex -v -g -largeArrayDims nomadmex.cpp ' nomad_src 'Parameters.cpp ' nomad_src 'Barrier.cpp ' nomad_src 'Cache.cpp '... +nomad_src 'Cache_File_Point.cpp ' nomad_src 'Cache_Point.cpp ' nomad_src 'Cache_Search.cpp ' nomad_src 'Clock.cpp '... +nomad_src 'Direction.cpp ' nomad_src 'Directions.cpp ' nomad_src 'Display.cpp '... +nomad_src 'Double.cpp ' nomad_src 'Eval_Point.cpp ' nomad_src 'Evaluator.cpp ' nomad_src 'Evaluator_Control.cpp ' nomad_src 'Exception.cpp '... +nomad_src 'Extended_Poll.cpp ' nomad_src 'L_Curve.cpp ' nomad_src 'LH_Search.cpp ' nomad_src 'OrthogonalMesh.cpp ' nomad_src 'Mads.cpp ' nomad_src 'Model_Sorted_Point.cpp '... +nomad_src 'Model_Stats.cpp ' nomad_src 'Multi_Obj_Evaluator.cpp ' nomad_src 'Parameter_Entries.cpp '... +nomad_src 'Parameter_Entry.cpp ' nomad_src 'Pareto_Front.cpp ' nomad_src 'Pareto_Point.cpp ' nomad_src 'Phase_One_Evaluator.cpp '... +nomad_src 'Phase_One_Search.cpp ' nomad_src 'Point.cpp ' nomad_src 'Priority_Eval_Point.cpp ' nomad_src 'Quad_Model.cpp '... +nomad_src 'Quad_Model_Evaluator.cpp ' nomad_src 'Quad_Model_Search.cpp ' nomad_src 'Random_Pickup.cpp ' nomad_src 'RNG.cpp '... +nomad_src 'Signature.cpp ' nomad_src 'Slave.cpp ' nomad_src 'SMesh.cpp ' nomad_src 'Speculative_Search.cpp ' nomad_src 'Stats.cpp ' nomad_src 'utils.cpp '... +nomad_src 'Variable_Group.cpp ' nomad_src 'VNS_Search.cpp ' nomad_src 'XMesh.cpp']; + +try + eval([pre post]) + movefile(['nomad.' mexext],['..' filesep],'f') + cd(cdir); + clear nomad_home nomad_src cdir post pre libdir; + fprintf('Done!\n'); +catch ME + cd(cdir); + clear nomad_home nomad_src cdir post pre libdir; + error('opti:nomad','Error Compiling NOMAD!\n%s',ME.message); +end +fprintf('------------------------------------------------\n'); diff --git a/examples/interfaces/Matlab_MEX/Source/nomadmex.cpp b/examples/interfaces/Matlab_MEX/Source/nomadmex.cpp new file mode 100755 index 0000000..cd8f3ec --- /dev/null +++ b/examples/interfaces/Matlab_MEX/Source/nomadmex.cpp @@ -0,0 +1,1635 @@ +/*-------------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search MATLAB Interface */ +/* */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ +/* Charles Audet - Ecole Polytechnique, Montreal */ +/* Gilles Couture - Ecole Polytechnique, Montreal */ +/* John Dennis - Rice University, Houston */ +/* Sebastien Le Digabel - Ecole Polytechnique, Montreal */ +/* Christophe Tribes - Ecole Polytechnique, Montreal */ +/* */ +/* funded in part by AFOSR and Exxon Mobil */ +/* */ +/* MEX Interface Author: Jonathan Currie 2012 (I2C2) */ +/* */ +/* MEX Interface Contact information: */ +/* jocurrie@aut.ac.nz */ +/* */ +/* This program is free software: you can redistribute it and/or modify it under the */ +/* terms of the GNU Lesser General Public License as published by the Free Software */ +/* Foundation, either version 3 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 Lesser General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public License along */ +/* with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*-------------------------------------------------------------------------------------*/ + +#define NOMADMEX_VERSION "1.24_ct [feb 12, 2015]" +//NOTE from Version 1.15 on this MEX file contains a dual interface: + +// 1) The default (GERAD) interface is: +// [x,fval,exitflag,iter] = nomad(fun,x0,lb,ub,opts) + +// 2) Otherwise if OPTI_VERSION is defined it will compile the OPTI Toolbox interface: +// [x,fval,exitflag,iter] = nomad(fun,x0,lb,ub,nlcon,nlrhs,xtype,opts) + +// Both contain near identical functionality, except the GERAD version includes nonlinear +// constraints with the objective (blackbox) function. The OPTI version separates them, +// and allows a user specified rhs. The OPTI version also rounds x0 for integer constraints. + +#include "mex.h" +#include "nomad.hpp" +#include "defines.hpp" +#include <stdio.h> +#include <string.h> + +using namespace std; + + +//Function handle structure +#define FLEN 128 /* max length of user function name */ +#define MAXRHS 3 /* max nrhs for user function */ +typedef struct { + char f[FLEN]; + mxArray *plhs[1]; + mxArray *prhs[MAXRHS]; + int xrhs, nrhs; + double *nlrhs; +} usrFcn; + +typedef struct { + char f[FLEN]; + mxArray *plhs[1]; + mxArray *prhs[2]; + bool enabled; +} neighborsFcn; + + +//Iteration callback structure +typedef struct { + char f[FLEN]; + mxArray *plhs[1]; + mxArray *prhs[4]; + bool enabled; +} iter_fun_data; + +//Ctrl-C Detection +#ifdef __cplusplus +extern "C" bool utIsInterruptPending(); +extern "C" void utSetInterruptPending(bool); +#else +extern bool utIsInterruptPending(); +extern void utSetInterruptPending(bool); +#endif + +//Argument Enums (in expected order of arguments) +#ifdef OPTI_VERSION +enum {eFUN, eX0, eLB, eUB, eNLCON, eNLRHS, eXTYPE, eOPTS}; +#else //GERAD VERSION +enum {eFUN, eX0, eLB, eUB, eOPTS}; +enum {eNLCON, eNLRHS, eXTYPE}; //placeholders +#endif +//PRHS Defines +#define pFUN prhs[eFUN] +#define pX0 prhs[eX0] +#define pLB prhs[eLB] +#define pUB prhs[eUB] +#define pNLCON prhs[eNLCON] +#define pNLRHS prhs[eNLRHS] +#define pXTYPE prhs[eXTYPE] +#define pOPTS prhs[eOPTS] + +//Function Prototypes +void printSolverInfo(); +int checkInputs(const mxArray *prhs[], int nrhs, mxArray *plhs[], int nlhs); +vector<NOMAD::bb_input_type> detInTypes(char *xtype, size_t n); +vector<NOMAD::bb_output_type> detRetTypes(usrFcn *fun, mxArray *out_types, int *nobj, usrFcn *con, int *ncon, double *x0, size_t n); +void setNOMADopts(NOMAD::Parameters &p, const mxArray *opts); +bool isNMDOption(const char *field); +NOMAD::bb_output_type getOutEnum(char *str); +void lower(char *str); +double getStatus(int stat); + + +// Matlab Extended_Poll Class +/*--------------------------------------------------*/ +/* Class to define categorical neighborhoods */ +/*--------------------------------------------------*/ +class Matlab_Extended_Poll : public NOMAD::Extended_Poll +{ + +private: + + // signatures for 1 asset: + NOMAD::Signature * _s1; + + neighborsFcn * _neighbors; + + +public: + + Matlab_Extended_Poll ( NOMAD::Parameters & p , neighborsFcn * neighbors ); + + virtual ~Matlab_Extended_Poll ( void ){} + + // construct the extended poll points: + virtual void construct_extended_points ( const NOMAD::Eval_Point & ); + +}; + +/*-----------------------------------------*/ +/* constructor: creates the signature */ +/*-----------------------------------------*/ +Matlab_Extended_Poll::Matlab_Extended_Poll ( NOMAD::Parameters & p , neighborsFcn * neighbors) +: Extended_Poll ( p ) , +_s1 ( NULL ), +_neighbors ( neighbors ) +{ + _s1 = p.get_signature(); + +} + +/*--------------------------------------*/ +/* construct the extended poll points */ +/* (categorical neighborhoods) */ +/*--------------------------------------*/ +void Matlab_Extended_Poll::construct_extended_points ( const NOMAD::Eval_Point & x ) +{ + double *xm; + char errstr[1024]; + + if ( !x.is_complete() ) + { + mexWarnMsgTxt("construct_extended_points: bad extended poll center\n%sExiting NOMAD...\n\n"); + //Force exit + raise(SIGINT); + } + + + xm = mxGetPr(_neighbors->prhs[1]); + int n=_s1->get_n(); + + for(int i=0;i<n;i++) + xm[i] = x[i].value(); + + //Call MATLAB neighbors + try + { + mexCallMATLAB(1, _neighbors->plhs, 2, _neighbors->prhs, _neighbors->f); + } + //Note if these errors occur it is due to errors in MATLAB code, no way to recover? + catch(exception &e) + { + sprintf(errstr,"Unrecoverable Error from neighbors callback:\n%sExiting NOMAD...\n\n",e.what()); + mexWarnMsgTxt(errstr); + //Force exit + raise(SIGINT); + } + catch(...) + { + mexWarnMsgTxt("Unrecoverable Error from neighbors callback, Exiting NOMAD...\n\n"); + //Force exit + raise(SIGINT); + } + + + size_t nbNPoints=mxGetNumberOfElements(_neighbors->plhs[0])/n; + double *xr=mxGetPr(_neighbors->plhs[0]); + + for(int i=0;i<nbNPoints;i++) + { + NOMAD::Point nPoint(n); + + for(int j=0;j<n;j++) + nPoint[j]=xr[i+j*nbNPoints]; + + add_extended_poll_point(nPoint , *_s1 ); + } + +} + + +//MATLAB Evaluator Class +class matlabEval : public NOMAD::Evaluator { +private: + usrFcn *fun; + bool hasSur; + int nobj; + usrFcn *con; + int ncon; + iter_fun_data *iterF; + int citer; + +public: + //Constructor + matlabEval(const NOMAD::Parameters &p, usrFcn *_obj, int _nobj, usrFcn *_con, int _ncon, iter_fun_data *_iterF) : NOMAD::Evaluator(p) + { + fun = _obj; + hasSur = p.has_sgte(); + nobj = _nobj; + con = _con; + ncon = _ncon; + iterF = _iterF; + citer = 0; + +#ifdef OPTI_VERSION + if(hasSur) + mexWarnMsgTxt("Optimization using surrogates is not available in OPTI version of NOMAD\n"); +#endif + } + //Destructor + ~matlabEval(void) {} + + + // evaluating a list of points + bool eval_x(std::list<NOMAD::Eval_Point *> &x, const NOMAD::Double &h_max, std::list<bool> & list_count_eval ) + { + +#ifdef OPTI_VERSION + mexPrintf("Optimization using block of points evaluation is not available in OPTI version of NOMAD\n"); + //Force exit + raise(SIGINT); + return false; +#endif + + + char errstr[1024]; + bool stop = false; + int i, j; + size_t m, n; + double *fvals; + mxLogical *sur; + + m=x.size(); + n=(*(x.begin()))->size(); + + if ( m !=list_count_eval.size()) + { + mexPrintf("NomadMex Evaluator: inconsistent size of list" ); + //Force exit + raise(SIGINT); + return false; + } + + + //Check for Ctrl-C + if (utIsInterruptPending()) + { + utSetInterruptPending(false); /* clear Ctrl-C status */ + mexPrintf("\nCtrl-C Detected. Exiting NOMAD...\n\n"); + list_count_eval.assign(m,false); + raise(SIGINT); + return false; + } + + + fun->prhs[fun->xrhs] = mxCreateDoubleMatrix(m, n, mxREAL); //x + double *List_x = mxGetPr(fun->prhs[fun->xrhs]); + std::list<NOMAD::Eval_Point *>::iterator it_x=x.begin(); + j=0; + for (it_x=x.begin();it_x!=x.end();++it_x,++j) + for(i=0;i<n;i++) + List_x[i*m+j] = (*(*it_x))[i].value(); + + + //Add Surrogate if present and requested + if(hasSur) + { + sur=mxGetLogicals(fun->prhs[fun->xrhs+1]); + (x.front()->get_eval_type()==NOMAD::SGTE)? *sur=true:*sur=false; // all evaluations in a list have the same eval_type + } + + + // Count eval for bbox + // The case where the evaluation is rejected by user (and should not be counted) is not managed in the matlab version + list_count_eval.assign(m,true); + + + //Call MATLAB Objective + try + { + mexCallMATLAB(1, fun->plhs, fun->nrhs, fun->prhs, fun->f); + } + + //Note if these errors occur it is due to errors in MATLAB code, no way to recover? + catch(exception &e) + { + sprintf(errstr,"Unrecoverable Error from Objective / Blackbox Callback:\n%sExiting NOMAD...\n\n",e.what()); + mexPrintf(errstr); + //Force exit + raise(SIGINT); + return false; + } + catch(...) + { + mexPrintf("Unrecoverable Error from Objective / Blackbox Callback, Exiting NOMAD...\n\n"); + //Force exit + raise(SIGINT); + return false; + } + + //Check we got the correct number of elements back + if(mxGetNumberOfElements(fun->plhs[0]) > (nobj+ncon)*m) + mexPrintf("Black box returns more elements than required. Please provide a BB_OUTPUT_TYPE consistent with your black box function or correct the black box function."); + else if(mxGetNumberOfElements(fun->plhs[0]) < (nobj+ncon)*m) + { + mexPrintf("Insufficient outputs provided by the black box function. Exiting NOMAD...\n\n"); + raise(SIGINT); + return false; + } + else if(mxGetM(fun->plhs[0]) != m ) + { + mexPrintf("Insufficient number of rows in the output of the black box function. The number of rows should be equal to the size of the block of evaluations. Exiting NOMAD...\n\n"); + raise(SIGINT); + return false; + } + else if(mxGetN(fun->plhs[0]) != (nobj+ncon) ) + { + mexPrintf("Insufficient number of columns in the output of the black box function. The number of columns should be the number of objectives plus the number of constraints. Exiting NOMAD...\n\n"); + raise(SIGINT); + return false; + } + + + + //Assign bb output + fvals = mxGetPr(fun->plhs[0]); + j=0; + for (it_x=x.begin();it_x!=x.end();++it_x,++j) + for(i=0;i<(nobj+ncon);i++) + (*it_x)->set_bb_output(i,fvals[m*i+j]); + + //Iteration Callback + if(iterF->enabled) + { + iterF->plhs[0] = NULL; + memcpy(mxGetData(iterF->prhs[1]), &citer, sizeof(int)); + memcpy(mxGetPr(iterF->prhs[2]), fvals, m*(nobj+ncon)*sizeof(double)); + memcpy(mxGetPr(iterF->prhs[3]), List_x, n * m * sizeof(double)); + try { + mexCallMATLAB(1, iterF->plhs, 4, iterF->prhs, iterF->f); + } + catch (...) + { + mexPrintf("Unrecoverable Error from Iteration Callback, Exiting NOMAD...\n\n"); + //Force exit + raise(SIGINT); + return false; + } + + //Collect return argument + stop = *(bool*)mxGetData(iterF->plhs[0]); + //Clean up Ptr + mxDestroyArray(iterF->plhs[0]); + + } + + //Add Function Eval Counter + citer++; + + // Clean up LHS Fun Ptr + mxDestroyArray(fun->plhs[0]); + + //Check for iterfun stop + if(stop) + { + mexPrintf("\nIterFun Called Stop. Exiting NOMAD...\n\n"); + raise(SIGINT); + return false; + } + else + return true; + } + + + + //Function + Constraint Evaluation + bool eval_x(NOMAD::Eval_Point &x, const NOMAD::Double &h_max, bool &count_eval) + { + char errstr[1024]; + bool stop = false; + int i, n = x.size(); + double *xm, *fvals; + mxLogical *sur; + count_eval = true; //mexErrMsgTxt will kill MEX + + //Check for Ctrl-C + if (utIsInterruptPending()) { + utSetInterruptPending(false); /* clear Ctrl-C status */ + mexPrintf("\nCtrl-C Detected. Exiting NOMAD...\n\n"); + count_eval = false; + raise(SIGINT); + return false; + } + + //Blackbox / Objective Evaluation + xm = mxGetPr(fun->prhs[fun->xrhs]); + for(i=0;i<n;i++) + xm[i] = x[i].value(); + //Add Surrogate if present and requested + if(hasSur) { + sur=mxGetLogicals(fun->prhs[fun->xrhs+1]); + (x.get_eval_type()==NOMAD::SGTE)? *sur=true:*sur=false; + } + //Call MATLAB Objective + try { + mexCallMATLAB(1, fun->plhs, fun->nrhs, fun->prhs, fun->f); + } + //Note if these errors occur it is due to errors in MATLAB code, no way to recover? + catch(exception &e) { + sprintf(errstr,"Unrecoverable Error from Objective / Blackbox Callback:\n%sExiting NOMAD...\n\n",e.what()); + mexWarnMsgTxt(errstr); + //Force exit + raise(SIGINT); + return false; + } + catch(...) { + mexPrintf("Unrecoverable Error from Objective / Blackbox Callback, Exiting NOMAD...\n\n"); + //Force exit + raise(SIGINT); + return false; + } + +#ifdef OPTI_VERSION + //Check we got the correct number back + if(mxGetM(fun->plhs[0]) != nobj) + mexErrMsgTxt("Incorrect number of elements returned from the objective function"); + //Set Objective (Or multi-objective) + fvals = mxGetPr(fun->plhs[0]); + for(i=0;i<nobj;i++) + x.set_bb_output(i,fvals[i]); + + //Constraint Evaluation + if(ncon) { + con->plhs[0] = NULL; + xm = mxGetPr(con->prhs[con->xrhs]); + for(i=0;i<n;i++) + xm[i] = x[i].value(); + //Call MATLAB Constraint + try { + mexCallMATLAB(1, con->plhs, con->nrhs, con->prhs, con->f); + } + catch(...) + { + mexWarnMsgTxt("Unrecoverable Error from Constraint Callback, Exiting NOMAD...\n\n"); + //Force exit + raise(SIGINT); + return false; + } + //Check we got the correct number back + if(mxGetM(con->plhs[0]) != ncon) + mexErrMsgTxt("Incorrect number of elements returned from nonlinear constraint function"); + //Set Constraints + double *cons = mxGetPr(con->plhs[0]); + for(i=0,j=nobj;i<ncon;i++,j++) + x.set_bb_output(j,cons[i] - con->nlrhs[i]); //subtract nlrhs + // Clean up LHS Ptr + mxDestroyArray(con->plhs[0]); + } +#else //GERAD VERSION + //Check we got the correct number of elements back + if(mxGetNumberOfElements(fun->plhs[0]) > nobj+ncon) + mexWarnMsgTxt("Black box returns more elements than required. Please provide a BB_OUTPUT_TYPE consistent with your black box function"); + else if(mxGetNumberOfElements(fun->plhs[0]) < nobj+ncon) + { + mexPrintf("Insufficient outputs provided by the black box function. Exiting NOMAD...\n\n"); + raise(SIGINT); + return false; + } + //Assign bb output + fvals = mxGetPr(fun->plhs[0]); + for(i=0;i<(nobj+ncon);i++) + x.set_bb_output(i,fvals[i]); + +#endif + + //Iteration Callback + if(iterF->enabled) + { + iterF->plhs[0] = NULL; + memcpy(mxGetData(iterF->prhs[1]), &citer, sizeof(int)); + memcpy(mxGetPr(iterF->prhs[2]), fvals, sizeof(double)); + memcpy(mxGetPr(iterF->prhs[3]), xm, n * sizeof(double)); + try { + mexCallMATLAB(1, iterF->plhs, 4, iterF->prhs, iterF->f); + } + catch (...) + { + mexPrintf("Unrecoverable Error from Iteration Callback, Exiting NOMAD...\n\n"); + //Force exit + raise(SIGINT); + return false; + } + + //Collect return argument + stop = *(bool*)mxGetData(iterF->plhs[0]); + //Clean up Ptr + mxDestroyArray(iterF->plhs[0]); + } + + //Add Function Eval Counter + citer++; + + // Clean up LHS Fun Ptr + mxDestroyArray(fun->plhs[0]); + + //Check for iterfun stop + if(stop) + { + mexPrintf("\nIterFun Called Stop. Exiting NOMAD...\n\n"); + count_eval = false; + raise(SIGINT); + return false; + } + else + return true; + } +}; + +//MATLAB MultiObj Evaluator Class +class matlabMEval : public NOMAD::Multi_Obj_Evaluator { +private: + matlabEval *mEval; +public: + //Constructor + matlabMEval(const NOMAD::Parameters &p, usrFcn *_obj, int _nobj, usrFcn *_con, int _ncon, iter_fun_data *_iterF) : NOMAD::Multi_Obj_Evaluator(p) + { + mEval = new matlabEval(p,_obj,_nobj,_con,_ncon,_iterF); + } + //Destructor + ~matlabMEval(void) + { + delete mEval; + } + //Function + Constraint Information + bool eval_x(NOMAD::Eval_Point &x, const NOMAD::Double &h_max, bool &count_eval) + { + return mEval->eval_x(x,h_max,count_eval); + } + + //Function + Constraint Information + bool eval_x(std::list<NOMAD::Eval_Point *> &x, const NOMAD::Double &h_max, std::list<bool> & list_count_eval ) + { + return mEval->eval_x(x,h_max,list_count_eval); + } + +}; + +//cout Redirection +struct printfbuf : std::streambuf { +public: + //Constructor + printfbuf() + { + setp(m_buffer, m_buffer + s_size - 2); + } +private: + enum { s_size = 1024 }; //not sure on this size + char m_buffer[s_size]; + int_type overflow(int_type c) + { + if (!traits_type::eq_int_type(c, traits_type::eof())) { + *pptr() = traits_type::to_char_type(c); + pbump(1); + } + return sync() != -1 ? traits_type::not_eof(c) : traits_type::eof(); + } + + int sync() { + *pptr() = 0; + mexPrintf(pbase()); + mexEvalString("drawnow;"); + setp(m_buffer, m_buffer + s_size - 2); + return 0; + } +}; + +// make the buffer static to have a single buffer when nested nomad optimizations +static printfbuf buf; + +// Main Entry Function +// ----------------------------------------------------------------- +void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + //Input Args + usrFcn fun, con; + double *x0, *lb = NULL, *ub = NULL; + char *xtype = NULL; + + //Outputs Args + double *exitflag, *iter, *nfval; + + //Internal Vars + size_t ndec; + int i, nobj = 1, ncon = 0; + char errstr[1024]; //used for returning error info + iter_fun_data iterF; + neighborsFcn neighborsF; + + //Check user inputs + if(!checkInputs(prhs,nrhs,plhs,nlhs)) + return; + + //Redirect cout + std::cout.rdbuf(&buf); //redirect buffer + + //NOMAD Vars + NOMAD::Mads *mads; + NOMAD::Display out(std::cout); + NOMAD::Parameters p(out); + NOMAD::Point px0; + NOMAD::Double *nx0; + NOMAD::stop_type stopflag; + //Evaluator Vars + matlabEval *mSEval = NULL; + matlabMEval *mBEval = NULL; + // Extended Poll Vars + Matlab_Extended_Poll *mEP = NULL; + + //Set Option Defaults + int printLevel = 0; + char *paramfile = NULL; + mxArray *bb_out_type = NULL; + iterF.enabled = false; + neighborsF.enabled=false; + + //Get Size + ndec = mxGetNumberOfElements(pX0); + + //Get Blackbox / Objective Function Handle + if (mxIsChar(pFUN)) + { + if(mxGetString(pFUN, fun.f, FLEN) != 0) + mexErrMsgTxt("error reading objective name string"); + fun.nrhs = 1; + fun.xrhs = 0; + } else + { + fun.prhs[0] = (mxArray*)pFUN; + strcpy(fun.f, "feval"); + fun.nrhs = 2; + fun.xrhs = 1; + } + fun.prhs[fun.xrhs] = mxCreateDoubleMatrix(ndec, 1, mxREAL); //x + + //Get x0 + x0 = mxGetPr(pX0); + + //Get xtype + if(nrhs > eXTYPE && !mxIsEmpty(pXTYPE)) + xtype = mxArrayToString(pXTYPE); + + //Get MEX Options if specified + if(nrhs > eOPTS && !mxIsEmpty(pOPTS)) { + if(mxGetField(pOPTS,0,"display_degree") && !mxIsEmpty(mxGetField(pOPTS,0,"display_degree"))) + printLevel = (int)*mxGetPr(mxGetField(pOPTS,0,"display_degree")); + if(mxGetField(pOPTS,0,"param_file") && !mxIsEmpty(mxGetField(pOPTS,0,"param_file"))) + paramfile = mxArrayToString(mxGetField(pOPTS,0,"param_file")); + if(mxGetField(pOPTS,0,"bb_output_type") && !mxIsEmpty(mxGetField(pOPTS,0,"bb_output_type"))) + bb_out_type = mxGetField(pOPTS,0,"bb_output_type"); + if(mxGetField(pOPTS,0,"iterfun") && !mxIsEmpty(mxGetField(pOPTS,0,"iterfun"))) + { + iterF.prhs[0] = (mxArray*)mxGetField(pOPTS,0,"iterfun"); + strcpy(iterF.f, "feval"); + iterF.enabled = true; + iterF.prhs[1] = mxCreateNumericMatrix(1,1,mxINT32_CLASS,mxREAL); + iterF.prhs[2] = mxCreateDoubleMatrix(1,1,mxREAL); + iterF.prhs[3] = mxCreateDoubleMatrix(ndec,1,mxREAL); + } + // This is for categorical variables + if(mxGetField(pOPTS,0,"neighbors_mat") && !mxIsEmpty(mxGetField(pOPTS,0,"neighbors_mat"))) + { + strcpy(neighborsF.f, "feval"); + neighborsF.enabled = true; + neighborsF.prhs[0] = (mxArray*)mxGetField(pOPTS,0,"neighbors_mat"); + neighborsF.prhs[1] = mxCreateDoubleMatrix(ndec,1,mxREAL); + } + + } + + + //Setup ndec + p.set_DIMENSION((int)ndec); + //Warn if >1000 + if(ndec > 1000 && printLevel) { + sprintf(errstr,"Warning: NOMAD is designed for problems with less than 1000 variables. Your model has %d.\nWhile unlikely, it is possible that NOMAD may not perform as intended on this problem.",static_cast<int>(ndec)); + mexWarnMsgTxt(errstr); + } + + //Setup Lower Bounds + if(nrhs > eLB && !mxIsEmpty(pLB)) { + NOMAD::Point ptLB; + NOMAD::Double *dLB = new NOMAD::Double[ndec]; + lb = mxGetPr(pLB); + for(i=0;i<ndec;i++) { + if(!mxIsInf(lb[i])) //if not initialized will not be used + dLB[i] = lb[i]; + } + ptLB.set((int)ndec,dLB); + p.set_LOWER_BOUND(ptLB); + delete [] dLB; + } + //Setup Upper Bounds + if(nrhs > eUB && !mxIsEmpty(pUB)) + { + NOMAD::Point ptUB; + NOMAD::Double *dUB = new NOMAD::Double[ndec]; + ub = mxGetPr(pUB); + for(i=0;i<ndec;i++) { + if(!mxIsInf(ub[i])) //if not initialized will not be used + dUB[i] = ub[i]; + } + ptUB.set((int)ndec,dUB); + p.set_UPPER_BOUND(ptUB); + delete [] dUB; + } + + //Setup x0 + nx0 = new NOMAD::Double[ndec]; +#ifdef OPTI_VERSION + double xl, xu; + //If integer variables declared, need to ensure x0[i] is an integer + if(xtype) + { + for(i=0;i<ndec;i++) + { + switch(tolower(xtype[i])) + { + case 'c': + //Ensure within bounds + if(lb && x0[i] < lb[i]) + nx0[i] = lb[i]; + else if(ub && x0[i] > ub[i]) + nx0[i] = ub[i]; + else + nx0[i] = x0[i]; //no rounding + break; + case 'i': + case 'b': + xl = floor(x0[i]); //First round is a floor + //If lower bounds exist + if(lb) { + //if lower bound broken + if(xl < lb[i]) { + xu = ceil(x0[i]); + //If upper bounds exist, check bound directions + if(ub && xu > ub[i]) { //if broken, no integer x0 exists + sprintf(errstr,"x0[%d] cannot be rounded to an integer value between lb: %g, ub %g",i,lb[i],ub[i]); + mexErrMsgTxt(errstr); + } + if(xu != x0[i]) { //If we changed something, warn user + sprintf(errstr,"x0[%d] was rounded up to %g to suit NOMAD interface",i,xu); + mexWarnMsgTxt(errstr); + } + //Save ceil value + nx0[i] = xu; + } + //Floor value did not break lower bounds, value OK + else { + if(xl != x0[i]) { //If we changed something, warn user + sprintf(errstr,"x0[%d] was rounded down to %g to suit NOMAD interface",i,xl); + mexWarnMsgTxt(errstr); + } + //Save floor value + nx0[i] = xl; + } + } + //No lower bounds, floor value assumed OK + else { + if(xl != x0[i]) { //If we changed something, warn user + sprintf(errstr,"x0[%d] was rounded down to %g to suit NOMAD interface",i,xl); + mexWarnMsgTxt(errstr); + } + //Save floor value + nx0[i] = xl; + } + break; + case 'r': + mexErrMsgTxt("Please specify continuous (real) variables using 'c' (as opposed to 'r') when using the OPTI version"); + break; + default: + sprintf(errstr,"Unknown xtype[%d] character: %c\n\nValid options are 'C', 'I', or 'B'\n",i,xtype[i]); + mexErrMsgTxt(errstr); + } + } + } + //Else user start position within bounds + else { + for(i=0;i<ndec;i++) { + if(lb && x0[i] < lb[i]) + nx0[i] = lb[i]; + else if(ub && x0[i] > ub[i]) + nx0[i] = ub[i]; + else + nx0[i] = x0[i]; + } + } + +#else //GERAD VERSION - no x0 checking + for(i=0;i<ndec;i++) + nx0[i] = x0[i]; +#endif + px0.set((int)ndec,nx0); + p.set_X0(px0); + delete [] nx0; + +#ifdef OPTI_VERSION + //Setup Nonlinear Constraints + if(nrhs > eNLCON && !mxIsEmpty(pNLCON)) { + if (mxIsChar(pNLCON)) { + if(mxGetString(pNLCON, con.f, FLEN) != 0) + mexErrMsgTxt("error reading constraint name string"); + con.nrhs = 1; + con.xrhs = 0; + } else { + con.prhs[0] = (mxArray*)pNLCON; + strcpy(con.f, "feval"); + con.nrhs = 2; + con.xrhs = 1; + } + con.prhs[con.xrhs] = mxCreateDoubleMatrix(ndec, 1, mxREAL); //x + if(nrhs < eNLRHS+1 || mxIsEmpty(pNLRHS)) {//we will default to <= 0 + ncon = -1; + con.nlrhs = NULL; + } + else { + ncon = (int)mxGetNumberOfElements(pNLRHS); + con.nlrhs = mxGetPr(pNLRHS); + } + } + //Setup Input Variable Types + if(xtype) + p.set_BB_INPUT_TYPE(detInTypes(xtype,ndec)); + + //Setup Evaluation Return Types + #'s of Obj + Con + p.set_BB_OUTPUT_TYPE(detRetTypes(&fun,bb_out_type,&nobj,&con,&ncon,x0,ndec)); + + //Set All Normal NOMAD Options + p.set_DISPLAY_DEGREE(0); //default + +#endif //GERAD Version does not have a separate constraint handler and handles input and output types using options + + // evaluation tags and numbers are reset + NOMAD::Eval_Point::reset_tags_and_bbes(); + + // Reset the random number generator for each mads run. + // The seed will always be to its default value + NOMAD::RNG::reset_seed_to_default(); + + //Set User Options + if(nrhs > eOPTS && !mxIsEmpty(pOPTS)) + setNOMADopts(p,pOPTS); + else + setNOMADopts(p,NULL); + + //If the user has specified a parameter file to read, see if it exists, and if so, read and parse it. + if(paramfile) + { + FILE *pFile = fopen(paramfile,"r"); + if(pFile==NULL) { + sprintf(errstr,"Cannot open parameter file: %s\n\nEnsure it exists!",paramfile); + mexErrMsgTxt(errstr); + } + else{ + fclose(pFile); //close file pointer (we don't need it) + try + { + p.read(paramfile); + } + catch(exception &e) + { + sprintf(errstr,"NOMAD Parameter File Read Error:\n\n%s",e.what()); + mexErrMsgTxt(errstr); + } + } + } + + //Check NOMAD parameters + try + { + p.check(); + } + catch(exception &e) { + sprintf(errstr,"NOMAD Parameter Error:\n\n%s",e.what()); + mexErrMsgTxt(errstr); + } + + //If GERAD version, obtain number of objectives and constraints from parameters +#ifndef OPTI_VERSION + nobj=p.get_nb_obj(); + ncon=(int)p.get_bb_output_type().size()-nobj; + if (p.has_sgte()) { + fun.prhs[fun.xrhs+1] = mxCreateLogicalMatrix(1,1); //extra logical indicating surrogate or not + fun.nrhs++; + } +#endif + + //Print Header + if(printLevel) { + mexPrintf("\n------------------------------------------------------------------\n"); + mexPrintf(" This is NOMAD v%s\n",NOMAD::VERSION.c_str()); + mexPrintf(" Authors: M. Abramson, C. Audet, G. Couture, J. Dennis, S. Le Digabel, C. Tribes\n"); +#ifdef OPTI_VERSION + mexPrintf(" MEX Interface (OPTI) J. Currie 2012\n\n"); +#else + mexPrintf(" MEX Interface (GERAD) J. Currie 2012 and C.Tribes 2015 \n\n"); +#endif + mexPrintf(" Problem Properties:\n"); + mexPrintf(" # Decision Variables: %4d\n",ndec); + mexPrintf(" # Number of Objectives: %4d\n",nobj); + mexPrintf(" # Number of Nonlinear Constraints: %4d\n",ncon); + + mexPrintf("------------------------------------------------------------------\n"); + mexEvalString("drawnow;"); //flush draw buffer + } + + //Create evaluator and run mads based on number of objectives + try + { + if(nobj > 1) + { + mBEval = new matlabMEval(p,&fun,nobj,&con,ncon,&iterF); //Bi-Objective Evaluator + + if ( p.get_signature()->has_categorical() ) + { + mEP = new Matlab_Extended_Poll ( p , &neighborsF); + mads = new NOMAD::Mads(p, mBEval , mEP , NULL , NULL); //Run NOMAD + + } + else + mads = new NOMAD::Mads(p, mBEval); //Run NOM + + stopflag = mads->multi_run(); + } + else + { + mSEval = new matlabEval(p,&fun,nobj,&con,ncon,&iterF); //Single Objective Evaluator + + if ( p.get_signature()->has_categorical() ) + { + mEP = new Matlab_Extended_Poll ( p, &neighborsF); + mads = new NOMAD::Mads(p, mSEval , mEP , NULL , NULL); //Run NOMAD + + } + else + mads = new NOMAD::Mads(p, mSEval); //Run NOMAD + + stopflag = mads->run(); + + } + } + catch(exception &e) + { + + //Free Memory + if(mSEval) + delete mSEval; + mSEval = NULL; + if(mBEval) + delete mBEval; + mBEval = NULL; + delete mads; + if(xtype) + mxFree(xtype); + xtype = NULL; + + delete mads; + + sprintf(errstr,"NOMAD Run Error:\n\n%s",e.what()); + mexErrMsgTxt(errstr); + } + + if(printLevel) + mexPrintf("------------------------------------------------------------------\n"); + + //Obtain Solution + + + //Create Outputs + plhs[2] = mxCreateDoubleMatrix(1,1, mxREAL); + plhs[3] = mxCreateDoubleMatrix(1,1, mxREAL); + plhs[4] = mxCreateDoubleMatrix(1,1, mxREAL); + exitflag = mxGetPr(plhs[2]); + iter = mxGetPr(plhs[3]); + nfval = mxGetPr(plhs[4]); + if (nobj>1) + { + + NOMAD::Pareto_Front * pareto_front=mads->get_pareto_front(); + + if ( pareto_front ) + { + + int nb_pareto_pts = pareto_front->size(); + plhs[0] = mxCreateDoubleMatrix(ndec,nb_pareto_pts, mxREAL); + plhs[1] = mxCreateDoubleMatrix(nobj,nb_pareto_pts, mxREAL); + double *x = mxGetPr(plhs[0]); + double *fval = mxGetPr(plhs[1]); + + const NOMAD::Eval_Point * cur = pareto_front->begin(); + int i=0; + while ( cur ) + { + + if ( cur->is_eval_ok() && cur->is_feasible ( p.get_h_min() ) ) + { + const std::list<int> & index_obj = p.get_index_obj(); + std::list<int>::const_iterator it , end = index_obj.end(); + const NOMAD::Point & bbo = cur->get_bb_outputs(); + int j = 0; + NOMAD::Point multi_obj ( static_cast<int>(index_obj.size()) ); + + for ( it = index_obj.begin() ; it != end ; ++it,j++ ) + fval[nobj*i+j] = bbo[*it].value(); + + for(j=0;j<ndec;j++) + x[ndec*i+j] = (*cur)[j].value(); + } + cur = pareto_front->next(); + i++; + } + *exitflag = getStatus(stopflag); + + } + else + { + stopflag = (NOMAD::stop_type)10; + *exitflag = -1; //No solution + } + //Save Status & Iterations + + *iter = mads->get_stats().get_iterations(); + *nfval = mads->get_stats().get_bb_eval(); + + } + else + { + + plhs[0] = mxCreateDoubleMatrix(ndec,1, mxREAL); + plhs[1] = mxCreateDoubleMatrix(1,1, mxREAL); //even bi-objectives return 1 fval + double *x = mxGetPr(plhs[0]); + double *fval = mxGetPr(plhs[1]); + + const NOMAD::Eval_Point *bestSol = mads->get_best_feasible(); + if(bestSol == NULL) + { + bestSol = mads->get_best_infeasible(); + //manually set as infeasible (no infeasible stop flag) + stopflag = (NOMAD::stop_type)10; + } + if(bestSol == NULL) + *exitflag = -1; //No solution + + //If we have a solution, save it + if(*exitflag != -1) { + //Save x + NOMAD::Point pt(*bestSol); + for(i=0;i<ndec;i++) + x[i] = pt[i].value(); + //Save fval + *fval = bestSol->get_f().value(); + + //Save Status & Iterations + *exitflag = getStatus(stopflag); + *iter = mads->get_stats().get_iterations(); + *nfval = mads->get_stats().get_bb_eval(); + } + } + + //Return error control to default + mexSetTrapFlag(0); + + + //Free Memory + if(mSEval) + delete mSEval; + mSEval = NULL; + if(mBEval) + delete mBEval; + mBEval = NULL; + + // Clean up of fun + mxDestroyArray(fun.prhs[fun.xrhs]); + + delete mads; + + if(xtype) + mxFree(xtype); + xtype = NULL; +} + +//Determine Variable Return Types + # Objectives + #NL Constraints (only OPTI Version) +vector<NOMAD::bb_output_type> detRetTypes(usrFcn *fun, mxArray *out_types, int *nobj, usrFcn *con, int *ncon, double *x0, size_t n) +{ + int i, j, stat; + + //Test Blackbox / Objective Evaluation + fun->plhs[0] = NULL; + memcpy(mxGetPr(fun->prhs[fun->xrhs]), x0, n * sizeof(double)); + //Call MATLAB Objective + stat = mexCallMATLAB(1, fun->plhs, fun->nrhs, fun->prhs, fun->f); + if(stat) + mexErrMsgTxt("Error calling Objective Function!"); + //Ensure we have a real column + if(mxGetN(fun->plhs[0]) > mxGetM(fun->plhs[0])) + mexErrMsgTxt("The objective function must return a scalar or column vector"); + if(mxIsSparse(fun->plhs[0]) || mxIsComplex(fun->plhs[0])) + mexErrMsgTxt("The objective function must return a real, dense, vector"); + + //Ensure 1 or 2 rows (max of bi-objective) + *nobj = (int)mxGetNumberOfElements(fun->plhs[0]); + if(*nobj < 1 || *nobj > 2) + mexErrMsgTxt("The objective function must return a scalar or 2x1 vector (bi-objective)"); + // Clean up LHS Ptr + mxDestroyArray(fun->plhs[0]); + + //Test Constraint Evaluation + if(*ncon) { + con->plhs[0] = NULL; + memcpy(mxGetPr(con->prhs[con->xrhs]), x0, n * sizeof(double)); + //Call MATLAB Objective + stat = mexCallMATLAB(1, con->plhs, con->nrhs, con->prhs, con->f); + if(stat) + mexErrMsgTxt("Error calling Constraint Function!"); + //Ensure we have a real column + if(mxGetN(con->plhs[0]) > mxGetM(con->plhs[0])) + mexErrMsgTxt("The constraint function must return a scalar or column vector"); + if(mxIsSparse(con->plhs[0]) || mxIsComplex(con->plhs[0])) + mexErrMsgTxt("The constraint function must return a real, dense, vector"); + + //If we have nlrhs, check against returned vector + if(*ncon > 0) { + if(mxGetM(con->plhs[0]) != *ncon) + mexErrMsgTxt("The vector returned from nlcon is not the same length as nlrhs!"); + } + else { + *ncon = (int)mxGetM(con->plhs[0]); + con->nlrhs = mxGetPr(mxCreateDoubleMatrix(*ncon,1, mxREAL)); //create dummy rhs + } + // Clean up LHS Ptr + mxDestroyArray(con->plhs[0]); + } + + //Create Return Vector + vector<NOMAD::bb_output_type> varType(*nobj+*ncon); + //Fill Objective Information + for(i=0;i<*nobj;i++) + varType[i] = NOMAD::OBJ; + //If the user has set bb_output_type use it to set constraint types + if(out_types) { + if(!mxIsCell(out_types)) + mexErrMsgTxt("Parameter bb_output_type must be a cell array of strings."); + if(mxGetNumberOfElements(out_types) != *ncon) + mexErrMsgTxt("You must specify a bb_output_type for each element returned by the constraint function (not objective)."); + //Process each element in the array + for(i=0,j=*nobj;i<*ncon;i++,j++){ + mxArray *ctype = mxGetCell(out_types,i); + if(!mxIsChar(ctype)) + mexErrMsgTxt("An element in the bb_output_type paramter is not a string"); + //Get the string + char *str = mxArrayToString(ctype); + //Set varType based on string + varType[j] = getOutEnum(str); + //Free local memory at each iteration + mxFree(str); + } + } + //Or Fill Constraint Information as Default all PB + else { + for(i=0,j=*nobj;i<*ncon;i++,j++) + varType[j] = NOMAD::PB; + } + + return varType; +} + +//Convert user string to NOMAD bb_output_type enum +NOMAD::bb_output_type getOutEnum(char *str) +{ + char errstr[1024]; + lower(str); //convert to lowercase + + if(!strcmp(str,"obj")) +#ifdef OPTI_VERSION + mexErrMsgTxt("The OPTI Version of NOMAD uses bb_output_type to describe CONSTRAINTS ONLY. Please remove any OBJ terms from the cell array."); +#else + return NOMAD::OBJ; +#endif + else if(!strcmp(str,"pb")) + return NOMAD::PB; + else if(!strcmp(str,"eb")) + return NOMAD::EB; + else if(!strcmp(str,"peb")) + return NOMAD::PEB_P; + else if(!strcmp(str,"f")) + return NOMAD::FILTER; + else if(!strcmp(str,"nothing") || !strcmp(str,"-")) + return NOMAD::UNDEFINED_BBO; + else { + sprintf(errstr,"Unknown BB_OUTPUT_TYPE %s",str); + mexErrMsgTxt(errstr); + } + //Default + return NOMAD::UNDEFINED_BBO; +} + +//Convert input string to lowercase +void lower(char *str) +{ + int i = 0; + while(str[i]) { + str[i] = tolower(str[i]); + i++; + } +} + +//Determine input variable types (only OPTI version) +vector<NOMAD::bb_input_type> detInTypes(char *xtype, size_t n) +{ + int i; + char msgbuf[1024]; + vector<NOMAD::bb_input_type> varType(n); + for(i=0;i<n;i++) { + switch(tolower(xtype[i])) + { + case 'c': + varType[i] = NOMAD::CATEGORICAL; break; + case 'r': + varType[i] = NOMAD::CONTINUOUS; break; + mexErrMsgTxt("Please specify continuous (real) variables using 'c' when using the OPTI version"); + case 'i': + varType[i] = NOMAD::INTEGER; break; + case 'b': + varType[i] = NOMAD::BINARY; break; + default: + sprintf(msgbuf,"Unknown xtype[%d] character: %c\n\nValid options are 'C', 'I', or 'B'\n",i,xtype[i]); + mexErrMsgTxt(msgbuf); + } + } + return varType; +} + +//User Input Checking + Version / Info / Help +int checkInputs(const mxArray *prhs[], int nrhs, mxArray *plhs[], int nlhs) +{ + size_t ndec; + char *str = NULL; + + //MEX Display Version (OPTI compatibility) + if (nrhs < 1) { + if(nlhs < 1) + printSolverInfo(); + else + plhs[0] = mxCreateString(NOMAD::VERSION.c_str()); + return 0; + } + + //Redirect cout + std::streambuf *cout_sbuf = std::cout.rdbuf(); //keep existing buffer + std::cout.rdbuf(&buf); //redirect buffer + + //NOMAD Display + NOMAD::Display out (std::cout); + + //Check for display on options passed as structure + if(nrhs == 1 && mxIsStruct(prhs[0])) { + int i, no = mxGetNumberOfFields(prhs[0]); + const char *field; + std::list<std::string> ls; + //For all fields, display nomad help + for(i=0;i<no;i++) { + field = mxGetFieldNameByNumber(prhs[0],i); + string st(field); + ls.push_back ( st ); + } + if(no>0) { + //NOMAD Display + NOMAD::Parameters p ( out ); + p.help(ls); + } + std::cout.rdbuf(cout_sbuf); //Return cout to initial buffer + return 0; + } + + //Check for Version / Information / Help Request + if(nrhs == 1 && mxIsChar(prhs[0])) { + str = mxArrayToString(prhs[0]); + //Check for Info Request + if(!strcmp(str,"-I") || !strcmp(str,"-INFO") || !strcmp(str,"-i") || !strcmp(str,"-info")) { + //Information to Print + mexPrintf("\nNOMAD Blackbox Optimization Software, v%s\n\n",NOMAD::VERSION.c_str()); + mexPrintf("Copyright (C) 2001-2015\n"); + mexPrintf("Mark A. Abramson - The Boeing Company\n"); + mexPrintf("Charles Audet - Ecole Polytechnique de Montreal\n"); + mexPrintf("Gilles Couture - Ecole Polytechnique de Montreal\n"); + mexPrintf("John E. Dennis, Jr. - Rice University\n"); + mexPrintf("Sebastien Le Digabel - Ecole Polytechnique de Montreal\n"); + mexPrintf("Christophe Tribes - Ecole Polytechnique de Montreal\n\n"); + mexPrintf("Funded in part by AFOSR and Exxon Mobil.\n\n"); + mexPrintf("License : \'%s\'\n",NOMAD::LGPL_FILE.c_str()); + mexPrintf("User guide: \'%s\'\n",NOMAD::USER_GUIDE_FILE.c_str()); + mexPrintf("Examples : \'%s\'\n",NOMAD::EXAMPLES_DIR.c_str()); + mexPrintf("Tools : \'%s\'\n\n",NOMAD::TOOLS_DIR.c_str()); + mexPrintf("Please report NOMAD bugs to nomad@gerad.ca and MEX Interface bugs to jocurrie@aut.ac.nz\n\n"); + + std::cout.rdbuf(cout_sbuf); //Return cout to initial buffer + return 0; + } + //Check for Ver Request + if(!strcmp(str,"-V") || !strcmp(str,"-v") || !strcmp(str,"-version")) + { + mexPrintf("NOMAD - version %s - www.gerad.ca/nomad\n\n",NOMAD::VERSION.c_str()); +#ifdef OPTI_VERSION + mexPrintf("MEX Interface (OPTI) v%s\n",NOMADMEX_VERSION); +#else + mexPrintf("MEX Interface (GERAD) v%s\n",NOMADMEX_VERSION); +#endif + + std::cout.rdbuf(cout_sbuf); //Return cout to initial buffer + return 0; + } + //Check for Help Request + if (strcmp(str,"-H")<0 || strcmp(str,"-HELP")<0 || strcmp(str,"-h")<0 || strcmp(str,"-help")<0 ) + { + NOMAD::Parameters p ( out ); + std::list<std::string> helpS; + const char * toks=" "; + char *w = strtok(str,toks) ; + for ( w = strtok(NULL,toks) ; w != NULL ; w = strtok(NULL,toks) ) + { + helpS.push_back(w); + } + p.help (helpS ); + + std::cout.rdbuf(cout_sbuf); //Return cout to initial buffer + return 0; + } + } + + //Otherwise assume we have a normal problem + if(nrhs < 2) + mexErrMsgTxt("You must supply at least 2 arguments to nomad!\n\nnomad(fun,x0)\n"); + + //Check Types + if(!mxIsFunctionHandle(pFUN) && !mxIsChar(pFUN)) + mexErrMsgTxt("fun must be a function handle or function name!"); + + if(!mxIsDouble(pX0) || mxIsComplex(pX0) || mxIsEmpty(pX0)) + mexErrMsgTxt("x0 must be a real double column vector!"); + + //Get ndec + ndec = mxGetNumberOfElements(prhs[1]); + + //Check Bounds + if(nrhs > 2) { + if(!mxIsDouble(pLB) || mxIsComplex(pLB)) + mexErrMsgTxt("lb must be a real double column vector!"); + if(nrhs > 3 && (!mxIsDouble(pUB) || mxIsComplex(pUB))) + mexErrMsgTxt("ub must be a real double column vector!"); + //Check Sizes + if(!mxIsEmpty(pLB) && (ndec != mxGetNumberOfElements(pLB))) + mexErrMsgTxt("lb is not the same length as x0! Ensure they are both Column Vectors"); + if(nrhs > 3 && !mxIsEmpty(pUB) && (ndec != mxGetNumberOfElements(pUB))) + mexErrMsgTxt("ub is not the same length as x0! Ensure they are both Column Vectors"); + } + +#ifdef OPTI_VERSION + //Version check + if(nrhs > eNLRHS && mxIsStruct(pNLRHS)) + mexErrMsgTxt("It appears you may be calling NOMAD using the GERAD NOMAD Syntax - nomad(bb,x0,lb,ub,opts). This is the OPTI NOMAD version and requires nomad(fun,x0,lb,ub,nlcon,nlrhs,xtype,opts)."); + + //Check Nonlinear Constraint Handle + if(nrhs > eNLCON && !mxIsEmpty(pNLCON)) { + if(!mxIsFunctionHandle(pNLCON) && !mxIsChar(pNLCON)) + mexErrMsgTxt("nlcon must be a function handle or function name!"); + if(nrhs > eNLRHS && (!mxIsDouble(pNLRHS) || mxIsComplex(pNLRHS))) + mexErrMsgTxt("nlrhs must be a real double column vector!"); + } + //Check for xtype + if(nrhs > eXTYPE && !mxIsEmpty(pXTYPE)) { + if(!mxIsChar(pXTYPE)) + mexErrMsgTxt("The xtype vector must be a char array!"); + if(ndec != mxGetNumberOfElements(pXTYPE)) + mexErrMsgTxt("xtype is not same length as x0! Ensure they are both Column Vectors"); + } +#else + //Version check + if(nrhs > 6) + mexErrMsgTxt("It appears you may be calling NOMAD using the OPTI NOMAD Syntax - nomad(fun,x0,lb,ub,nlcon,nlrhs,xtype,opts). This is the GERAD NOMAD version and requires nomad(bb,x0,lb,ub,opts)."); +#endif + + //Check Options + if(nrhs > eOPTS && !mxIsEmpty(pOPTS)) { + //Version check + if(mxIsDouble(pOPTS)) + mexErrMsgTxt("It appears you may be calling NOMAD using the OPTI NOMAD Syntax - nomad(fun,x0,lb,ub,nlcon,nlrhs,xtype,opts). This is the GERAD NOMAD version and requires nomad(bb,x0,lb,ub,opts)."); + + if(!mxIsStruct(pOPTS)) + mexErrMsgTxt("The specified options must be a structure!"); + } + + //Return Continue + return 1; + +} + +void setNOMADopts(NOMAD::Parameters &p, const mxArray *opts) +{ + char strbuf[1024]; + int i, no = 0; + NOMAD::Parameter_Entries entries; + const char *field; + mxArray *value; + bool doAdd = false; + size_t m; + double val; + bool has_BB_OUTPUT_TYPE = false; + bool has_categorical =false; + + if(opts) + no = mxGetNumberOfFields(opts); + + //For each field, check if it's empty, if not, set it within NOMAD + for(i=0;i<no;i++) { + field = mxGetFieldNameByNumber(opts,i); + value = mxGetFieldByNumber(opts,0,i); + //Check we don't have an empty or MEX option + if(!mxIsEmpty(value) && isNMDOption(field)) { + //Switch on data type + switch(mxGetClassID(value)) + { + + case mxDOUBLE_CLASS: + m = mxGetNumberOfElements(value); + //This interface doesn't write vectors as options + if(m > 1) { + sprintf(strbuf,"This interface does not support vector options for parameter %s. Please provide it as a string",field); + mexErrMsgTxt(strbuf); + } + val = *mxGetPr(value); + //Check if we have an integer parameter (I assume this check is ok!) + if(floor(val) == val) { + sprintf(strbuf,"%s %.0f",field,val); doAdd = true; //write with no decimal points and no exponent + } + else {//write as double (exponent ok) + sprintf(strbuf,"%s %g",field,val); doAdd = true; + } + break; + case mxFUNCTION_CLASS: + if ( strcmp(field,"NEIGHBORS_MAT") == 0 || strcmp(field,"neighbors_mat") == 0 ) + { + // sprintf(strbuf,"%s %s",field,mxArrayToString(value)); + has_categorical = true; + } + break; + case mxCHAR_CLASS: + sprintf(strbuf,"%s %s",field,mxArrayToString(value)); + doAdd = true; + //GERAD check for BB_OUTPUT_TYPE + if ( strcmp(field,"BB_OUTPUT_TYPE") == 0 || strcmp(field,"bb_output_type") == 0 ) + has_BB_OUTPUT_TYPE = true; + break; + + case mxCELL_CLASS: +#ifdef OPTI_VERSION + //Add each string for the specified field + m = mxGetNumberOfElements(value); + for(j=0;j<m;j++) { + mxArray *cellopt = mxGetCell(value,j); + if(!mxIsChar(cellopt)) { + sprintf(strbuf,"Element %d in the cell array of paramter %s is not a string",j+1,field); + mexErrMsgTxt(strbuf); + } + //Get the string and create the required option string + char *str = mxArrayToString(cellopt); + sprintf(strbuf,"%s %s",field,str); + //Add to our set of parameter entries + NOMAD::Parameter_Entry *pe = new NOMAD::Parameter_Entry(strbuf); // pe will be deleted by ~Parameter_Entries() + if(pe->is_ok()) + entries.insert(pe); + else { + sprintf(strbuf,"Parameter %s has an error",field); + mexErrMsgTxt(strbuf); + } + //Free local memory at each iteration + mxFree(str); + } +#else + sprintf(strbuf,"Parameter %s NOT SET!\nThe GERAD version of the NOMAD interface does not support cell arrays. Please specify them as strings, with spaces between arguments.",field); + mexWarnMsgTxt(strbuf); +#endif + break; + + default: + sprintf(strbuf,"Parameter %s NOT SET, CLASSID = %d which is not supported",field,mxGetClassID(value)); + mexWarnMsgTxt(strbuf); + } + + //If we have a valid parameter, add it to our set of entries + if(doAdd) { + //mexPrintf("NOMAD Option set as: %s\n",strbuf); //enable for debug + NOMAD::Parameter_Entry *pe = new NOMAD::Parameter_Entry(strbuf); + if(pe->is_ok()) + entries.insert(pe); // pe will be deleted by ~Parameter_Entries() + else + { + sprintf(strbuf,"Parameter %s has an error",field); + mexErrMsgTxt(strbuf); + } + + doAdd = false; + } + } + } + //GERAD default bb_output_type if not specified +#ifndef OPTI_VERSION + if(!has_BB_OUTPUT_TYPE) { + NOMAD::Parameter_Entry *pe = new NOMAD::Parameter_Entry("BB_OUTPUT_TYPE OBJ"); + entries.insert(pe); // pe will be deleted by ~Parameter_Entries() + } +#endif + + try + { + p.read(entries); + } + catch(exception &e) + { + sprintf(strbuf,"NOMAD Parameter Read Error:\n\n%s",e.what()); + mexErrMsgTxt(strbuf); + } +} + +//Separates MEX interface options from NOMAD ones +bool isNMDOption(const char *field) +{ + if(!strcmp(field,"param_file")) + return false; + else if(!strcmp(field,"iterfun")) + return false; +#ifdef OPTI_VERSION + else if(!strcmp(field,"bb_output_type")) + return false; +#endif + else + return true; +} + +double getStatus(int stat) +{ + switch((int)stat) + { + case 5: //mesh minimum + case 8: //min mesh size + case 9: //min poll size + case 20: //ftarget reached + case 19: //feas reached + return 1; + break; + case 12: //max time + case 13: //max bb eval + case 14: //max sur eval + case 15: //max evals + case 16: //max sim bb evals + case 17: //max iter + case 23: //max multi bb evals + case 24: //max mads runs + return 0; + break; + case 10: //max mesh index + case 11: //mesh index limits + case 18: //max consec fails + case 25: //stagnation + case 26: //no pareto + case 27: //max cache memory + return -1; + case 6: //x0 fail + case 7: //p1_fail + return -2; + case 2: //Unknown stop reason + return -3; + case 3: //Ctrl-C + case 4: //User-stopped + return -5; + default: //Not assigned flag + return -3; + } +} + +//Print Solver Information +void printSolverInfo() +{ + mexPrintf("\n-----------------------------------------------------------\n"); + mexPrintf(" NOMAD: Nonlinear Optimization using the MADS Algorithm [v%s]\n",NOMAD::VERSION.c_str()); + mexPrintf(" - Released under the GNU Lesser General Public License: http://www.gnu.org/copyleft/lesser.html\n"); + mexPrintf(" - Source available from: http://www.gerad.ca/NOMAD/Project/Home.html\n"); + + mexPrintf("\n MEX Interface J.Currie 2013 (www.i2c2.aut.ac.nz) and C.Tribes 2015 \n"); + mexPrintf("-----------------------------------------------------------\n"); +} diff --git a/examples/interfaces/Matlab_MEX/example_block_eval/fun.m b/examples/interfaces/Matlab_MEX/example_block_eval/fun.m new file mode 100644 index 0000000..1c9c899 --- /dev/null +++ b/examples/interfaces/Matlab_MEX/example_block_eval/fun.m @@ -0,0 +1,26 @@ +function [ fout ] = fun( X ) + +% CRESCENT 5 --- Block evals version + +nb_points=size(X,1); +n=size(X,2); + +if ( n ~= 5) + error('Black box function must be provided with points of dimension 5 (=number of columns)'); +end + +% objective +obj=X(:,5); +% constraints +parfor m=1:nb_points + c1(m)=sum((X(m,:)-1).^2)-25; + c2(m)=25-sum((X(m,:)+1).^2); +end + +% Unlike in the standard nomad version, a point cannot be +% rejected in the matlab version. +% If some points cannot be evaluated, objective and constraints must be set +% to Inf, otherwise the nomad evaluator for block of evaluations cannot +% continue. +fout=[obj , c1' , c2']; + diff --git a/examples/interfaces/Matlab_MEX/example_block_eval/run_nomad.m b/examples/interfaces/Matlab_MEX/example_block_eval/run_nomad.m new file mode 100644 index 0000000..4177fee --- /dev/null +++ b/examples/interfaces/Matlab_MEX/example_block_eval/run_nomad.m @@ -0,0 +1,12 @@ +% CRESCENT 5 + + +% parpool(4); + +x0 = [0 0 0 0 0 ]'; +lb = [-6 -6 -6 -6 -6 ]'; +ub = [6 6 6 6 6]'; +opts = nomadset('display_degree',2,'max_bb_eval',500,'direction_type','ortho 2n','bb_output_type','OBJ PB PB','bb_max_block_size',4); + +% Start optimization +[x,fval] = nomad(@fun,x0,lb,ub,opts); diff --git a/examples/interfaces/Matlab_MEX/example_categorical/fun.m b/examples/interfaces/Matlab_MEX/example_categorical/fun.m new file mode 100644 index 0000000..7fa3a28 --- /dev/null +++ b/examples/interfaces/Matlab_MEX/example_categorical/fun.m @@ -0,0 +1,60 @@ +function [ out ] = fun( X ) + +t0=X(1); +v0=X(2); +t1=X(3); +v1=X(4); + +v=zeros(3,1); +vmin = 10000; + +if ( t0 < 0 || t1 < 0 ) + out(1)=Inf; + out(2)=Inf; + out(3)=Inf; + return; +end + +v(t0+1) = v0; +v(t1+1) = v1; + +if ( v0 < vmin ) + vmin = v0; +end +if ( v1 < vmin ) + vmin = v1; +end + +% constraints (budget and each asset is considered with at least 1$): +vt = v(1) + v(2) + v(3); +h = vt - 10000; +g1 = h; +g2 = 1-vmin; + +if ( h <= 0 && vmin >= 1 ) +%% compute the risk and revenue: + vt2 = vt*vt; + rev = v(1) * 0.0891 + v(2) * 0.2137 + v(3) * 0.2346; + risk = 0.01 * (v(1)/vt)*(v(1)/vt) + ... + 0.05 * (v(2)/vt)*(v(2)/vt) + ... + 0.09 * (v(3)/vt)*(v(3)/vt) + ... + 0.02 * (v(1)*v(2)/vt2) + ... + 0.02 * (v(1)*v(3)/vt2) + ... + 0.10 * (v(2)*v(3)/vt2); + + % the objective is taken as a scaled distance + % between (risk,revenue) and (risk_best,rev_best): + a = ( risk - 0.01 ) * 100 / 0.08; + b = ( rev - 891 ) * 100 / 1455; + + f = (a*a + (100-b)*(100-b))^0.5; +else + f = 145; +end + + out(1)=g1; + out(2)=g2; + out(3)=f; + +end + diff --git a/examples/interfaces/Matlab_MEX/example_categorical/neighbors.m b/examples/interfaces/Matlab_MEX/example_categorical/neighbors.m new file mode 100644 index 0000000..a057d1e --- /dev/null +++ b/examples/interfaces/Matlab_MEX/example_categorical/neighbors.m @@ -0,0 +1,14 @@ +function [ Xout ] = neighbors ( X ) + +t0 = X(1); +v0 = X(2); +t1 = X(3); +v1 = X(4); + +t2 = ( 3 - t0 - t1 ); + +% neighbor #1: +Xout(1,:)=[ t2 ; v0 ; t1 ; v1 ]; + +% neighbor #2: +Xout(2,:)=[ t0 ; v0 ; t2 ; v1 ]; diff --git a/examples/interfaces/Matlab_MEX/example_categorical/run_nomad.m b/examples/interfaces/Matlab_MEX/example_categorical/run_nomad.m new file mode 100644 index 0000000..c4d169f --- /dev/null +++ b/examples/interfaces/Matlab_MEX/example_categorical/run_nomad.m @@ -0,0 +1,7 @@ +x0 = [0 100 1 100 ]'; +lb = [-100 0.0 0 0.0 ]'; +ub = [100 10000.0 100 10000]'; +opts = nomadset('display_degree',2,'max_bb_eval',200,'bb_output_type','EB EB OBJ','bb_input_type','[C R C R]','neighbors_mat',@neighbors); + +% Start optimization +[x,fval] = nomad(@fun,x0,lb,ub,opts); diff --git a/examples/interfaces/Matlab_MEX/example_surrogate/bbsur.m b/examples/interfaces/Matlab_MEX/example_surrogate/bbsur.m new file mode 100644 index 0000000..a14643e --- /dev/null +++ b/examples/interfaces/Matlab_MEX/example_surrogate/bbsur.m @@ -0,0 +1,11 @@ +function eval = bbsur(x,sur) + +if (nargin==1) + sur=false; +end + +if (sur) + eval=[9.9*(x(2)-x(1)^2); 1 - x(1)]; +else + eval=[10*(x(2)-x(1)^2); 1 - x(1)]; +end diff --git a/examples/interfaces/Matlab_MEX/example_surrogate/run_nomad.m b/examples/interfaces/Matlab_MEX/example_surrogate/run_nomad.m new file mode 100644 index 0000000..b7e58c9 --- /dev/null +++ b/examples/interfaces/Matlab_MEX/example_surrogate/run_nomad.m @@ -0,0 +1,5 @@ +%% TEST SURROGATE +clc +x0 = [1;1]; +opts = nomadset('display_degree',2,'bb_output_type','OBJ EB','has_sgte',1) +[x,fval] = nomad(@bbsur,x0,[-10;-10],[10;10],opts) diff --git a/examples/interfaces/Matlab_MEX/nomad.m b/examples/interfaces/Matlab_MEX/nomad.m new file mode 100644 index 0000000..b273d1c --- /dev/null +++ b/examples/interfaces/Matlab_MEX/nomad.m @@ -0,0 +1,38 @@ +% NOMAD Solve a Global MINLP/NLP using NOMAD, a Blackbox Optimization Library +% +% min f(x) subject to: nlcon(x) <= 0 +% x lb <= x <= ub +% xi in Z +% xj in {0,1} +% +%%%%%%%%%%%%% GERAD VERSION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [x,fval,exitflag,iter,nfval] = nomad(fun,x0,lb,ub,opts) +% +% Input arguments: +% fun - nonlinear function handle (f and nlcon) +% x0 - initial solution guess +% lb - decision variable lower bounds +% ub - decision variable upper bounds +% opts - solver options (see nomadset) +% +% Return arguments: +% x - solution vector +% fval - objective value at the solution +% exitflag - exit status (see below) +% iter - number of iterations taken by the solver +% nfval - number of function evaluations taken by the solver +% +% Return Status: +% 1 - converged / target reached +% 0 - maximum iterations / function evaluations exceeded +% -1 - infeasible / mesh limit reached +% -2 - initialization error +% -3 - nomad error +% -5 - user exit +% +% +% NOMAD is released under the Lesser GNU Public License (LGPL). +% Type nomad('-info') to see license and author details. +% +% MEX Interface Copyright (C) 2012 Jonathan Currie (I2C2) +% Modified for GERAD version by C.Tribes \ No newline at end of file diff --git a/examples/interfaces/Matlab_MEX/nomadset.m b/examples/interfaces/Matlab_MEX/nomadset.m new file mode 100755 index 0000000..19b7aa0 --- /dev/null +++ b/examples/interfaces/Matlab_MEX/nomadset.m @@ -0,0 +1,343 @@ +function options = nomadset(varargin) +%NOMADSET Create or alter the options for Optimization with NOMAD +% +% options = nomadset('param1',value1,'param2',value2,...) creates an +% NOMAD options structure with the parameters 'param' set to their +% corresponding values in 'value'. Parameters not specified will be set to +% the NOMAD default. +% +% options = nomadset(oldopts,'param1',value1,...) creates a copy of the old +% options 'oldopts' and then fills in (or writes over) the parameters +% specified by 'param' and 'value'. +% +% options = nomadset() creates an options structure with all fields set to +% NOMADSET defaults. +% +% nomadset() prints a list of all possible fields and their function. + +% Copyright (C) 2012 Jonathan Currie (I2C2) +% modif CT june 12, 2014 --->�version 1.22_ct +%Valid direction types +global dirtypes +dirtypes = {'ortho 1','ortho 2','ortho n+1','ortho n+1 quad','ortho n+1 neg','ortho','ortho 2n','lt 1','lt 2','lt 2n','lt n+1','gps binary','gps 2n static',... + 'gps 2n rand','gps n+1 static uniform','gps n+1 static','gps n+1 rand uniform','gps n+1 rand'}; + +% Print out possible values of properties. +if (nargin == 0) && (nargout == 0) + printfields(); + return +end + +%Names and Defaults +Names = {'bb_input_type','bb_output_type','direction_type','f_target','initial_mesh_size','lh_search','max_bb_eval','bb_max_block_size',... + 'max_time','model_eval_sort','model_search','multi_nb_mads_runs','multi_overall_bb_eval','opportunistic_eval','opportunistic_lh','seed','vns_search',... + 'cache_search','h_max_0','h_min','h_norm','initial_mesh_index','l_curve_target','max_cache_memory','max_consecutive_failed_iterations',... + 'max_eval','max_iterations','max_mesh_index','max_sim_bb_eval','mesh_coarsening_exponent','mesh_refining_exponent','mesh_update_basis',... + 'min_mesh_size','min_poll_size','model_eval_sort_cautious','model_search_max_trial_pts','model_search_optimistic','model_search_proj_to_mesh',... + 'model_quad_max_y_size','model_quad_min_y_size','model_quad_radius_factor','model_quad_use_wp','multi_f_bounds','multi_formulation','multi_use_delta_crit',... + 'neighbors_mat','opportunistic_cache_search','opportunistic_lucky_eval','opportunistic_min_eval','opportunistic_min_f_imprvmt','opportunistic_min_nb_success','rho','scaling','sec_poll_dir_type',... + 'snap_to_bounds','speculative_search','stat_sum_target','stop_if_feasible','add_seed_to_file_names','cache_file','cache_save_period','display_degree','display_all_eval',... + 'history_file','solution_file','stats_file','param_file','iterfun','disable','epsilon','opt_only_sgte','sgte_cost','sgte_eval_sort','has_sgte',... + 'sgte_cache_file','max_sgte_eval','anisotropic_mesh','fixed_variable'}'; +Defaults = {[],[],[],[],[],[],[],1,...%bb_max_block_size + [],1,1,[],[],1,1,[],0,... %vns_search + 0,1e20,[],'L2',[],[],2000,[],...%max_consecutive_failed_iterations + [],[],[],[],1,-1,4,... %mesh_update_basis + [],[],1,4,1,1,... %model_search_proj_to_mesh + [],500,2,0,[],'product',0,...%multi_use_delta_crit + [],0,0,[],[],[],0.1,[],[],...%sec_poll_dir_type + 1,1,[],0,1,[],25,0,0,... %display_all_eval + [],[],[],[],[],[],1e-13,0,[],1,0,...%has_sgte + [],[],1,''}'; + +%Collect Sizes and lowercase matches +m = size(Names,1); numberargs = nargin; +%Create structure with all names and default values +st = [Names,Defaults]'; options = struct(st{:}); + +% Check we have char or structure input. If structure, insert arguments +i = 1; +while i <= numberargs + arg = varargin{i}; + if ischar(arg) + break; + end + if ~isempty(arg) + if ~isa(arg,'struct') + error('An argument was supplied that wasn''t a string or struct!'); + end + for j = 1:m + if any(strcmp(fieldnames(arg),Names{j,:})) + val = arg.(Names{j,:}); + else + val = []; + end + if(~isempty(val)) + checkfield(Names{j,:},val); + options.(Names{j,:}) = val; + end + end + end + i = i + 1; +end + +%Check we have even number of args left +if rem(numberargs-i+1,2) ~= 0 + error('You do not have a value specified for each field!'); +end + +%Go through each argument pair and assign to correct field +expectval = 0; %first arg is a name +while i <= numberargs + arg = varargin{i}; + + switch(expectval) + case 0 %field + if ~ischar(arg) + error('Expected field name to be a string! - Argument %d',i); + end + j = find(strcmp(arg,Names) == 1); + if isempty(j) % if no matches + error('Unrecognised parameter %s',arg); + elseif(length(j) > 1) + error('Ambiguous parameter %s',arg); + end + expectval = 1; %next arg is a value + case 1 + if(~isempty(arg)) + if(iscell(arg)) + checkfield(Names{j,:},arg); + options.(Names{j,:}) = arg; + else + if(ischar(arg)), arg = lower(arg); end + checkfield(Names{j,:},arg); + options.(Names{j,:}) = arg; + end + end + expectval = 0; + end + i = i + 1; +end + +if expectval %fallen off end somehow + error('Missing value for %s',arg); +end +%Ensure we have absolute path +if(~isempty(options.param_file)) + options = checkParamFile(options); +end + + +function checkfield(field,value) +%Check a field contains correct data type +global dirtypes +err = []; + +switch lower(field) + %Scalar double + case {'f_target','max_bb_eval','bb_max_block_size','max_time','model_eval_sort',... + 'model_search','multi_nb_mads_runs','multi_overall_bb_eval','opportunistic_eval','opportunistic_lh','seed','vns_search',... + 'cache_search','h_max_0','h_min','initial_mesh_index','l_curve_target','max_cache_memory','max_consecutive_failed_iterations',... + 'max_eval','max_iterations','max_mesh_index','max_sim_bb_eval','mesh_coarsening_exponent','mesh_refining_exponent','mesh_update_basis',... + 'model_eval_sort_cautious','model_search_max_trial_pts','model_search_optimistic','model_search_proj_to_mesh',... + 'model_quad_max_y_size','model_quad_min_y_size','model_quad_radius_factor','model_quad_use_wp','multi_use_delta_crit',... + 'opportunistic_cache_search','opportunistic_lucky_eval','opportunistic_min_f_imprvmnt','opportunistic_min_nb_success','rho',... + 'snap_to_bounds','speculative_search','stat_sum_target','stop_if_feasible','add_seed_to_file_names','cache_save_period','display_degree',... + 'display_all_eval','has_sgte','sgte_cost','sgte_eval_sort','opt_only_sgte','epsilon','max_sgte_eval','anisotropic_mesh'} + if(~isscalar(value) || ~isnumeric(value) || ~isreal(value) || ~isa(value,'double')) + err = MException('NOMAD:SetFieldError','Parameter ''%s'' should be a real scalar double',field); + end + + %Direction Type + case {'direction_type','sec_poll_dir_type'} + if(~ischar(value) || ~any(strcmp(value,dirtypes))) + err = MException('NOMAD:SetFieldError','Parameter ''%s'' should match one of those displayed by nomadset()',field); + end + + %Disable + case 'disable' + if(~ischar(value) || ~any(strcmp(value,{'models'}))) + err = MException('NOMAD:SetFieldError','Parameter ''%s'' should be one of {''models''}',field); + end + + %String + case {'cache_file','history_file','solution_file','stats_file','param_file','multi_formulation','h_norm',... + 'lh_search','multi_f_bounds','sgte_cache_file'} + if(~ischar(value)) + err = MException('NOMAD:SetFieldError','Parameter ''%s'' should be a char array (string)',field); + end + + %string or cell of strings + case {'bb_output_type','bb_input_type','initial_mesh_size','min_mesh_size','min_poll_size','scaling','fixed_variable'} + if(~ischar(value) && ~iscell(value)) + err = MException('NOMAD:SetFieldError','Parameter ''%s'' should be a string or cell array of strings',field); + elseif(iscell(value)) + for i = 1:numel(value) + if(~ischar(value{i})) + err = MException('NOMAD:SetFieldError','Parameter ''%s'' cell(%d) should be a string',field,i); + break; + end + end + end + + %function_handle + case {'iterfun','neighbors_mat'} + if(~isa(value,'function_handle')) % C.Tribes june 12, 2014 ~isa instead of isa + err = MException('NOMAD:SetFieldError','Parameter ''%s'' should be a function handle',field); + end + + otherwise + err = MException('OPTI:SetFieldError','Unrecognized parameter name ''%s''.', field); +end +if(~isempty(err)), throw(err); end + + +function opts = checkParamFile(opts) +%Check parameter file exists and collect absolute path +filename = opts.param_file; +%See if we got an absolute path +switch(computer) + case {'PCWIN','PCWIN64'} + if(~isempty(strfind(filename,':'))) + p = filename; + %Check it exists + if(exist(filename,'file') ~= 2) + error('Cannot locate absolute file %s!',filename); + end + else + p = which(filename); + %Check it exists + if(isempty(p)) + error('Cannot locate file %s!',filename); + end + end + otherwise %Linux / Mac + if(filename(1) == '/') %absolute path (I think) + p = filename; + %Check it exists + if(exist(filename,'file') ~= 2) + error('Cannot locate absolute file %s!',filename); + end + else + p = which(filename); + %Check it exists + if(isempty(p)) + error('Cannot locate file %s!',filename); + end + end +end +%Save full path +opts.param_file = p; + + +function printfields() +%Print out fields with defaults + +global dirtypes + +fprintf('\nBASIC PROBLEM PARAMETERS:\n'); +fprintf(' bb_input_type: [ Blackbox input types, specified as a cell array of strings, overwrites xtype {[]} ] \n'); +fprintf(' bb_output_type: [ Blackbox output types, specified as a cell array of strings (see below) ] \n'); + +fprintf('\nBASIC ALGORITHMIC PARAMETERS:\n'); +fprintf(' direction_type: [ Type of directions for the poll (see below) {''ortho n+1 quad''} ] \n'); +fprintf(' f_target: [ Stop if f(x) < ftarget {[]} ] \n'); +fprintf(' initial_mesh_size: [ Initial Mesh Size (del_0^m) {[]} ]\n'); +fprintf(' lh_search: [ Latin-Hypercube Search (po and pi) {[]} ]\n'); +fprintf(' max_bb_eval: [ Maximum number of blackbox evaluations {[]} ] \n'); +fprintf(' max_time: [ Maximum execution time {[]} ] \n'); + +fprintf('\nADVANCED ALGORITHMIC PARAMETERS:\n'); +fprintf(' anisotropic_mesh: [ Use anisotropic mesh: No (0), Yes (1) = Default ] \n'); +fprintf(' bb_max_block_size: [ Maximum size of a block of evaluations given to the blackbox function {1} \n'); +fprintf(' cache_search: [ Use Cache search: Off {0}, On (1) ] \n'); +fprintf(' disable: [ Forcefully disable NOMAD features {[]} ] \n'); +fprintf(' fixed_variable: [ Fixed variable provided as ( 0.0 - 0.0 ) -> variables 0 and 2 are fixed; or as 1-10 0.0 -> variable 1 to 10 are fixed to 0.0 {[]} \n'); +fprintf(' h_max_0: [ Initial value of hmax {1e20} ] \n'); +fprintf(' h_min: [ x is feasible if h(x) >= v {0.0} ] \n'); +fprintf(' h_norm: [ Norm used to compute h: ''L1'', {''L2''}, ''Linf'' ] \n'); +fprintf(' has_sgte: [ Indicates if the problem has a surrogate function: No {0}, Yes {1} ] \n'); +fprintf(' initial_mesh_index: [ Initial Mesh Index {0} ] \n'); +fprintf(' l_curve_target: [ NOMAD terminates if objective may not reach this value {[]} ] \n'); +fprintf(' max_cache_memory: [ Maximum cache memory {2000} MB ] \n'); +fprintf(' max_consecutive_failed_iterations: [ Maximum number of failed MADS iterations {[]} ] \n'); +fprintf(' max_eval: [ Maximum number of evaluations (includes cache and bb) {[]} ] \n'); +fprintf(' max_iterations: [ Maximum number of iterations {[]} ] \n'); +fprintf(' max_mesh_index: [ Maximum Mesh Index {[]} ] \n'); +fprintf(' max_sgte_eval: [ Maximum Number of Surrogate Evaluations {[]} ] \n'); +fprintf(' max_sim_bb_eval: [ Maximum Simulated BB evaluations {[]} ] \n'); +fprintf(' mesh_coarsening_exponent: [ Mesh Coarsening Exponent {1} ] \n'); +fprintf(' mesh_refining_exponent: [ Mesh Refining Exponent {-1} ] \n'); +fprintf(' mesh_update_basis: [ Mesh Update Basis {4} ] \n'); +fprintf(' min_mesh_size: [ Minimum Mesh Size (del_min^m) {[]} ] \n'); +fprintf(' min_poll_size: [ Minimum Poll Size (del_min^p) {[]} ] \n'); +fprintf(' model_eval_sort: [ Use Quadratic Model to order points: Off (0), On {1} ] \n'); +fprintf(' model_search: [ Use Quadratic Model searches: Off (0), On {1} ] \n'); +fprintf(' model_search_optimistic: [ If the model search is optimistic : No (0), Yes {1} ] \n'); +fprintf(' multi_f_bounds: [ Vector of [f1min, f1max, f2min, f2max] for biobjective surf calculation {[]} ] \n'); +fprintf(' multi_nb_mads_runs: [ Number of MADS runs in Biobjective Optimization {[]} ] \n'); +fprintf(' multi_overall_bb_eval: [ Maximum number of BB evals for all MADS runs {[]} ] \n'); +fprintf(' neighbors_mat: [ Matlab function handle to obtain the neighboring points (use with categorical variables) {[]} ] \n'); +fprintf(' opportunistic_cache_search: [ Opportunistic cache search: Off {0}, On (1) ] \n'); +fprintf(' opportunistic_eval: [ Opportunistic strategy: Off (0), On {1} ] \n'); +fprintf(' opportunistic_lh: [ Opportunistic strategy for LH search: Off {0}, On (1)] \n'); +fprintf(' opportunistic_min_eval: [ Do not terminate below i evaluations {[]} ] \n'); +fprintf(' rho: [ Parameter of the progressive barrier {0.1} ] \n'); +fprintf(' scaling: [ Scaling on the variables (vector of scaling values for each variable) {[]} ] \n'); +fprintf(' seed: [ Random Seed: {[]} ] \n'); +fprintf(' sgte_cost: [ The cost of c surrogate evaluations is equivalent to one blackbox evaluation: {[]} ] \n'); +fprintf(' sgte_eval_sort: [ If surrogates are used to sort list of trial points: Off (0), On {1} ] \n'); +fprintf(' snap_to_bounds: [ Snap to boundary trial points that are generated outside of bounds: No (0), Yes {1} ] \n'); +fprintf(' speculative_search: [ MADS speculative search: No (0), Yes {1} ] \n'); +fprintf(' stat_sum_target: [ Terminates if stat_sum reaches this value {[]} ] \n'); +fprintf(' stop_if_feasible: [ Stop on first feasible solution: Off {0}, On (1) ] \n'); +fprintf(' vns_search: [ Variable Neighbourhood Search (Multiple Minima Problems): Off {0.0}, Max Searches (1.0) ] \n'); + + +fprintf('\nDEVELOPER PARAMETERS:\n'); +fprintf(' epsilon: [ Precision on real numbers {1e-13} ]\n'); +fprintf(' model_eval_sort_cautious: [ If the model ordering strategy is cautious: No (0), Yes {1} ] \n'); +fprintf(' model_search_max_trial_pts: [ Maximum trial points for one model search {4} ] \n'); +fprintf(' model_search_proj_to_mesh: [ If model search trial points are projected to mesh: No (0), Yes {1} ] \n'); +fprintf(' model_quad_max_y_size: [ Upper limit on the size of interpolation sets for quadratic models {500} ] \n'); +fprintf(' model_quad_min_y_size: [ Inf limit on the size of interpolation sets for quadratic models {[]} ] \n'); +fprintf(' model_quad_radius_factor: [ Quadratic Model search radius factor {2.0} ] \n'); +fprintf(' model_quad_use_wp: [ Enable strategy to maintain well-poised quadratic models: Off {0}, On (1) ] \n'); +fprintf(' multi_formulation: [ Single objective reformulation: ''normalized'', {''product''}, ''dist_l1'', ''dist_l2'', ''dist_linf'' ] \n'); +fprintf(' multi_use_delta_crit: [ Use stopping criterion based on the delta criterion: Off {0}, On (1) ] \n'); +fprintf(' opportunistic_lucky_eval: [ Perform an additional BB eval after an improvement: Off {0}, On (1) ] \n'); +fprintf(' opportunistic_min_f_imprvmt: [ Terminate only if f is reduced by r%% {[]} ] \n'); +fprintf('opportunistic_min_nb_success: [ Do not terminate before i successes {[]} ] \n'); +fprintf(' opt_only_sgte: [ Minimize only with surrogates: No {0}, Yes (1) ]\n'); +fprintf(' sec_poll_dir_type: [ Type of directions for the secondary poll (see below) {[]} ] \n'); + +fprintf('\nOUTPUT PARAMETERS:\n'); +fprintf(' add_seed_to_file_names: [ If the seed is added to the output file names: Off (0), On {1} ]\n'); +fprintf(' cache_file: [ Cache file: Off {[]}, On ''filename'' ]\n'); +fprintf(' cache_save_period: [ Cache files are saved every i iterations: {25} ]\n'); +fprintf(' display_degree: [ Display level: None {0}, Increasing (>0) ] \n'); +fprintf(' display_all_eval: [ Display all Points: Off {0}, On (1) ] \n'); +fprintf(' history_file: [ File containing all trial points: Off {[]}, On ''filename'' ]\n'); +fprintf(' solution_file: [ File to save the current best feasible point: Off {[]}, On ''filename'' ]\n'); +fprintf(' stats_file: [ File for screen dump: Off {[]}, On ''filename'' ]\n'); +fprintf(' sgte_cache_file: [ Surrogate cache file: Off {[]}, On ''filename'' ]\n'); + +fprintf('\nMEX INTERFACE PARAMETERS:\n'); +fprintf(' param_file: [ Read NOMAD options from a parameters file (overwrites these options): Off {[]}, On ''filename'' ]\n'); +fprintf(' iterfun: [ Callback function run every function evaluation: Off {[]}, On function_handle ]\n'); + + +fprintf('\n\nValid Direction Types (string):\n'); +for i = 1:length(dirtypes) + fprintf('''%s''\n',dirtypes{i}); +end +fprintf('\nValid BB_OUTPUT_TYPE types (cell array of strings):\n'); +fprintf('OBJ: Objective\n'); +fprintf(' PB: Progressive Barrier (default constraint type)\n'); +fprintf(' EB: Extreme Barrier\n'); +fprintf('PEB: Hybrid Constraint (PB/EB)\n'); +fprintf(' F: Filter\n'); + + + + diff --git a/examples/interfaces/Matlab_MEX/test_nomad_gerad.m b/examples/interfaces/Matlab_MEX/test_nomad_gerad.m new file mode 100755 index 0000000..810ca83 --- /dev/null +++ b/examples/interfaces/Matlab_MEX/test_nomad_gerad.m @@ -0,0 +1,152 @@ +% GERAD VERSION TESTING + + +%% PROBLEM 1 +fun = @(x) (1-x(1))^2 + 100 *(x(2)-x(1)^2)^2; +x0 = [-2 1]'; +lb = [-Inf;-1.5]; +ub = [100;100]; +opts = nomadset('display_degree',2,'min_mesh_size','1e-004','initial_mesh_size','10'); + +% Start optimization +[x,fval] = nomad(fun,x0,lb,ub,opts); + + +%%Uncomment the following problems for further testing +% +% +% %% PROBLEM 2 +% %clc +% % Blackbox Function +% bb = @(x) [29.4*x(1) + 18*x(2); +% -(x(1) - 0.2458*x(1)^2/x(2)) + 6]; +% % Bounds +% lb = [0;1e-5]; +% ub = [115.8;30]; +% % Starting Guess +% x0 = [0;1e-5]; +% % Options +% opts = nomadset('display_degree',2,'bb_output_type','OBJ EB','max_bb_eval',50); +% +% [x,fval,ef,iter] = nomad(bb,x0,lb,ub,opts); +% +% +% +% +% %% PROBLEM 3 +% %clc +% % Blackbox Function +% bb = @(x) (1-x(1))^2 + 100 *(x(2)-x(1)^2)^2; +% % Starting Guess +% x0 = [0 0]'; +% opts = []; %not no nomadset just to keep user options +% opts.display_degree = 2; +% opts.direction_type = 'ortho n+1'; +% opts.max_bb_eval = 2; +% % Solve +% [x,fval,ef,iter] = nomad(bb,x0,[],[],opts) +% +% %% PROBLEM 4 [fval = -2.5] +% %clc +% fun = @(x) [-x(1) - x(2) - x(3); +% (x(2) - 1./2.)*(x(2) - 1./2.) + (x(3) - 1./2.)*(x(3) - 1./2.) - 1/4; +% x(1) - x(2); +% x(1) + x(3) + x(4) - 2]; +% ub = [1;10;10;5]; +% lb = [0;0;0;0]; +% x0 = [0;0;0;0]; +% +% opts = []; %not no nomadset just to keep user options +% opts.display_degree = 2; +% opts.bb_output_type = 'OBJ PB PB PB'; +% opts.bb_input_type = '[B R R I]'; +% opts.model_search = 'false'; +% opts.model_eval_sort = 'false'; +% +% [xr,fval,ef,iter] = nomad(fun,x0,lb,ub,opts) +% +% +% %% REMAINDER OF PROBLEMS OK +% +% %% Rosenbrock [x = 1,1, fval = 0] +% %clc +% % Blackbox Function +% bb = @(x) (1-x(1))^2 + 100 *(x(2)-x(1)^2)^2; +% % Starting Guess +% x0 = [0 0]'; +% % Solve +% [x,fval,ef,iter] = nomad(bb,x0) +% +% %% St_e01 [x = 6,0.6667, fval = -6.6667] +% %clc +% % Blackbox Function +% bb = @(x) [-x(1) - x(2); +% x(1)*x(2) - 4]; +% % Bounds +% lb = [0;0]; +% ub = [6;4]; +% % Starting Guess +% x0 = [1,1]'; +% % Options +% opts = nomadset('display_degree',2,'bb_output_type','OBJ PB'); +% % Solve +% [x,fval,ef,iter] = nomad(bb,x0,lb,ub,opts) +% +% %% St_e08 [x = 0.1294, 0.4830, fval = 0.7418] +% %clc +% % Blackbox Function +% bb = @(x) [2*x(1)+x(2); +% -16*x(1)*x(2) + 1; +% (-4*x(1)^2) - 4*x(2)^2 + 1]; +% % Bounds +% lb = [0;0]; +% ub = [1;1]; +% % Starting Guess +% x0 = [0;0]; +% % Options +% opts = nomadset('display_degree',2,'bb_output_type','OBJ PB PB'); +% +% [x,fval,ef,iter] = nomad(bb,x0,lb,ub,opts) +% +% %% Wolfram problem (multiple global minima fval = 0) +% %clc +% % Fitting Function +% obj = @(x) [x(1) - sin(2*x(1) + 3*x(2)) - cos(3*x(1) - 5*x(2)); +% x(2) - sin(x(1) - 2*x(2)) + cos(x(1) + 3*x(2))]; +% % Blackbox Function +% bb = @(x) norm(obj(x)); +% +% % Bounds +% lb = [-4;-4]; +% ub = [4;4]; +% % Starting Guess +% x0 = [0;-3]; +% % Options +% opts = nomadset('display_degree',2,'vns_search',0.9,'f_target',1e-6); +% +% [x,fval,ef,iter] = nomad(bb,x0,lb,ub,opts) +% +% %% MINLP 1 [fval = -5] +% clc +% fun = @(x) [ (x(1) - 5)^2 + x(2)^2 - 25; +% x(1)^2 - x(2) + 0.5 ]; +% x0 = [0;0]; +% opts = nomadset('display_degree',2,'bb_input_type','[I I]','bb_output_type','OBJ PB'); +% [xr,fval,ef,iter] = nomad(fun,x0,[],[],opts) +% +% %% Bi-Objective (NOMAD Example) +% %clc +% % Blackbox Function +% bb = @(x) [x(5); +% sum((x-1).^2)-25; +% 25-sum((x+1).^2)]; +% % Bounds +% lb = [-6;-6;-6;-6;-6]; +% ub = [5;6;7;Inf;Inf]; +% % Starting Guess +% x0 = [0;0;0;0;0]; +% % Options +% % note the setting of bb_output_type in order to specify two objectives +% opts = nomadset('display_degree',2,'multi_overall_bb_eval',100,'bb_output_type','obj obj eb'); +% +% [xr,fval,ef,iter] = nomad(bb,x0,lb,ub,opts) diff --git a/install/install.sh b/install/install.sh index b359c46..a38c847 100755 --- a/install/install.sh +++ b/install/install.sh @@ -1,9 +1,9 @@ #!/bin/bash #-------------------------------------------------------------------------------------*/ -# NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search - version 3.5.1 */ +# NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search - version 3.7.2 */ # */ -# Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +# Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ # Charles Audet - Ecole Polytechnique, Montreal */ # Gilles Couture - Ecole Polytechnique, Montreal */ # John Dennis - Rice University, Houston */ @@ -38,7 +38,7 @@ # echo "*****************************************************" -echo " NOMAD 3.6.0 Installation Script " +echo " NOMAD 3.7.2 Installation Script " echo " usage: ./install.sh [nparallel] " echo " - nparallel : number of parallel process to make " echo "*****************************************************" @@ -56,16 +56,27 @@ echo "Testing gcc and mpi libraries" cd ${BASEDIR}/../src -VersionGCC=(`g++ -v 2>&1 | awk '$2 ~ /version/ {print $3}' | awk -F . '{print $1; print $2;print $3}'`) +VersionGCC=(`g++ -v 2>&1 | awk '$1 ~ /gcc/ && $2 ~ /version/ {print $3}' | awk -F . '{print $1; print $2;print $3}'`) if [ ${#VersionGCC[@]} -eq 0 ]; then - echo "======> gcc not installed. Failure of NOMAD installation " - exit 1; -fi - -if [ ${VersionGCC[0]} -gt 3 ]; then - echo "=======> gcc Version ${VersionGCC[0]}.${VersionGCC[1]}.${VersionGCC[2]} ---> ok" + echo "======> gcc not installed." + + VersionCLANG=(`g++ -v 2>&1 | awk '$1 ~ /Apple/ && $2 ~ /LLVM/ && $3 ~ /version/ {print $4}' | awk -F . '{print $1; print $2}'`) + if [ ${#VersionCLANG[@]} -eq 0 ]; then + echo "======> CLANG not installed. No supported compiler is available." + exit 1 + else + if [ ${VersionCLANG[0]} -gt 4 ]; then + echo "=======> CLANG Version ${VersionCLANG[0]}.${VersionCLANG[1]} ---> ok" + else + echo "=======> CLANG Version ${VersionCLANG[0]}.${VersionCLANG[1]} ---> Version of CLANG < 5 has not been tested for Nomad! Let us try to compile anyway." + fi + fi else - echo "=======> gcc Version ${VersionGCC[0]}.${VersionGCC[1]}.${VersionGCC[2]} ---> Version of gcc < 4 has not been tested for Nomad! Let us try to compile anyway." + if [ ${VersionGCC[0]} -gt 3 ]; then + echo "=======> gcc Version ${VersionGCC[0]}.${VersionGCC[1]}.${VersionGCC[2]} ---> ok" + else + echo "=======> gcc Version ${VersionGCC[0]}.${VersionGCC[1]}.${VersionGCC[2]} ---> Version of gcc < 4 has not been tested for Nomad! Let us try to compile anyway." + fi fi @@ -73,19 +84,32 @@ fi echo "Testing mpic++ " VersionMPICPP=(`mpic++ -v 2>&1 | awk '$2 ~ /version/ {print $3}' | awk -F . '{print $1; print $2;print $3}'`) if [ ${#VersionMPICPP[@]} -eq 0 ]; then - echo "======> mpic++ wrapper not available." - echo "Testing if MPI header available" - mpiHeaderAvailable=(`g++ -c nomad.cpp -DUSE_MPI 2>&1 | awk 'BEGIN{FS=":"} /mpi.h/ || /fatal error/ {Success=1;exit} END{print Success}' Success=0`) - if [ ${mpiHeaderAvailable} -eq 1 ]; then - echo "======> mpi.h not available. NOMAD Parallel version will not be compiled." - makeMPI=1 + echo "======> mpic++ (gcc) wrapper not available." + + VersionMPICLANG=(`mpic++ -v 2>&1 | awk '$1 ~ /Apple/ && $2 ~ /LLVM/ && $3 ~ /version/ {print $4}' | awk -F . '{print $1; print $2}'`) + if [ ${#VersionMPICLANG[@]} -eq 0 ]; then + echo "======> MPI wrapper for CLANG not installed." + echo "Testing if MPI header available" + mpiHeaderAvailable=(`g++ -c nomad.cpp -DUSE_MPI 2>&1 | awk 'BEGIN{FS=":"} /mpi.h/ || /fatal error/ {Success=1;exit} END{print Success}' Success=0`) + if [ ${mpiHeaderAvailable} -eq 1 ]; then + echo "======> mpi.h not available. NOMAD Parallel version will not be compiled." + makeMPI=1 + else + echo "======> mpi.h is present. Proper installation of MPI is supposed available and NOMAD parallel version will be compiled." + makeMPI=0 + COMPILATOR_MPI="g++" + fi else - echo "======> mpi.h is present. Proper installation of MPI is supposed available and NOMAD parallel version will be compiled." + if [ ${VersionMPICLANG[0]} -gt 4 ]; then + echo "=======> MPI wrapper for CLANG Version ${VersionCLANG[0]}.${VersionCLANG[1]} ---> ok" + else + echo "=======> MPI wrapper for CLANG Version ${VersionCLANG[0]}.${VersionCLANG[1]} ---> Version of CLANG < 5 has not been tested for Nomad! Let us try to compile anyway." + fi makeMPI=0 - COMPILATOR_MPI="g++" + COMPILATOR_MPI="mpic++" fi else - echo "=======> mpicc++ Version ${VersionMPICPP[0]}.${VersionMPICPP[1]}.${VersionMPICPP[2]} ---> ok" + echo "=======> mpicc++ wrapper for gcc version ${VersionMPICPP[0]}.${VersionMPICPP[1]}.${VersionMPICPP[2]} ---> ok" makeMPI=0 COMPILATOR_MPI="mpic++" fi diff --git a/nomad.spec b/nomad.spec index 6adc6ae..b324c31 100644 --- a/nomad.spec +++ b/nomad.spec @@ -1,7 +1,7 @@ %define _prefix /usr Name: nomad -Version: 3.6.1 +Version: 3.7.2 Release: 1 Summary: NOMAD (Nonsmooth Optimization by Mesh Adaptive Direct Search) License: LGPL diff --git a/readme.txt b/readme.txt index 96df2cf..4966d0c 100644 --- a/readme.txt +++ b/readme.txt @@ -1,115 +1,114 @@ -####################################################################################### -# # -# README # -# # -####################################################################################### -# # -# NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search # -# V 3.6.1 # -# 2013/05 # -# # -# Copyright (C) 2001-2013 # -# # -# Mark Abramson - the Boeing Company, Seattle # -# Charles Audet - Ecole Polytechnique, Montreal # -# Gilles Couture - Ecole Polytechnique, Montreal # -# John Dennis - Rice University, Houston # -# Sebastien Le Digabel - Ecole Polytechnique, Montreal # -# Christophe Tribes - Ecole Polytechnique, Montreal # -# # -#-------------------------------------------------------------------------------------# -# # -# Contact information: # -# Ecole Polytechnique de Montreal - GERAD # -# C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada # -# e-mail: nomad@gerad.ca # -# phone : 1-514-340-6053 #6928 # -# fax : 1-514-340-5665 # -# # -# This program is free software: you can redistribute it and/or modify it under the # -# terms of the GNU Lesser General Public License as published by the Free Software # -# Foundation, either version 3 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 Lesser General Public License for more details. # -# # -# -# You should have received a copy of the GNU Lesser General Public License along # -# with this program. If not, see <http://www.gnu.org/licenses/>. # -# # -# You can find information on the NOMAD software at www.gerad.ca/nomad # -####################################################################################### - - - AUTHORS : - -* Mark A. Abramson (Mark.A.Abramson@boeing.com), The Boeing Company. - -* Charles Audet (www.gerad.ca/Charles.Audet), GERAD and Departement de -mathematiques et de genie industriel, ecole Polytechnique de Montreal. - -* J.E. Dennis Jr. (www.caam.rice.edu/~dennis), Computational and Applied -Mathematics Department, Rice University. - -* Sebastien Le Digabel (www.gerad.ca/Sebastien.Le.Digabel), GERAD and Departement -de mathematiques et de genie industriel, ecole Polytechnique de Montreal. - -* Christophe Tribes, GERAD, Departement -de mathematiques et de genie industriel, Department of mechanical engineering, ecole Polytechnique de Montreal. - - DESCRIPTION : - -NOMAD is a C++ implementation of the Mesh Adaptive Direct Search (MADS) algorithm, -designed for constrained optimization of black-box functions. - -The project started in 2001, and was funded in part by AFOSR, CRIAQ, FQRNT, LANL, -NSERC, the Boeing Company, and ExxonMobil Upstream Research Company. - - - WEB PAGE : - -http://www.gerad.ca/nomad/ - - - FURTHER INSTRUCTIONS : - -Please visit the web page for futher instruction on the following: - - * Downloading, configuring, compiling, and installing NOMAD - * Using NOMAD and setting the parameters - * Reports on NOMAD - * How to report bugs and make enhancement requests - * And more... - - - BATCH OR LIBRARY MODE : - -NOMAD is designed to be used in two different modes : batch and library. -The batch mode is intended for a basic ans simple usage of the MADS method, -while the library mode allows more flexibility. -For example, in batch mode, users must define their separate black-box program, -that will be called with system calls by NOMAD. -In library mode, users can define their black-box function as C++ code -that will be directly called by NOMAD, without system calls and temporary files. - - - TYPES OF USE : - -There are two ways of using NOMAD, one can directly use an executable or compile -the source code. - -NOMAD batch mode executable is located in directory $NOMAD_HOME/bin or %NOMAD_HOME%\bin. -In order to avoid compiling the code, you can simply use this executable. - - - HOW TO EXECUTE NOMAD : - -For informations about the execution of NOMAD, please read the user guide : - - $NOMAD_HOME/doc/user_guide.pdf or %NOMAD_HOME%\doc\user_guide.pdf - -or - - http://www.gerad.ca/NOMAD/Downloads/user_guide.pdf +####################################################################################### +# # +# README # +# # +####################################################################################### +# # +# NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search # +# V 3.7.2 # +# # +# Copyright (C) 2001-2015 # +# # +# Mark Abramson - the Boeing Company, Seattle # +# Charles Audet - Ecole Polytechnique, Montreal # +# Gilles Couture - Ecole Polytechnique, Montreal # +# John Dennis - Rice University, Houston # +# Sebastien Le Digabel - Ecole Polytechnique, Montreal # +# Christophe Tribes - Ecole Polytechnique, Montreal # +# # +#-------------------------------------------------------------------------------------# +# # +# Contact information: # +# Ecole Polytechnique de Montreal - GERAD # +# C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada # +# e-mail: nomad@gerad.ca # +# phone : 1-514-340-6053 #6928 # +# fax : 1-514-340-5665 # +# # +# This program is free software: you can redistribute it and/or modify it under the # +# terms of the GNU Lesser General Public License as published by the Free Software # +# Foundation, either version 3 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 Lesser General Public License for more details. # +# # +# +# You should have received a copy of the GNU Lesser General Public License along # +# with this program. If not, see <http://www.gnu.org/licenses/>. # +# # +# You can find information on the NOMAD software at www.gerad.ca/nomad # +####################################################################################### + + + AUTHORS : + +* Mark A. Abramson (Mark.A.Abramson@boeing.com), The Boeing Company. + +* Charles Audet (www.gerad.ca/Charles.Audet), GERAD and Departement de +mathematiques et de genie industriel, ecole Polytechnique de Montreal. + +* J.E. Dennis Jr. (www.caam.rice.edu/~dennis), Computational and Applied +Mathematics Department, Rice University. + +* Sebastien Le Digabel (www.gerad.ca/Sebastien.Le.Digabel), GERAD and Departement +de mathematiques et de genie industriel, ecole Polytechnique de Montreal. + +* Christophe Tribes, GERAD, Departement +de mathematiques et de genie industriel, Department of mechanical engineering, ecole Polytechnique de Montreal. + + DESCRIPTION : + +NOMAD is a C++ implementation of the Mesh Adaptive Direct Search (MADS) algorithm, +designed for constrained optimization of black-box functions. + +The project started in 2001, and was funded in part by AFOSR, CRIAQ, FQRNT, LANL, +NSERC, the Boeing Company, and ExxonMobil Upstream Research Company. + + + WEB PAGE : + +http://www.gerad.ca/nomad/ + + + FURTHER INSTRUCTIONS : + +Please visit the web page for futher instruction on the following: + + * Downloading, configuring, compiling, and installing NOMAD + * Using NOMAD and setting the parameters + * Reports on NOMAD + * How to report bugs and make enhancement requests + * And more... + + + BATCH OR LIBRARY MODE : + +NOMAD is designed to be used in two different modes : batch and library. +The batch mode is intended for a basic ans simple usage of the MADS method, +while the library mode allows more flexibility. +For example, in batch mode, users must define their separate black-box program, +that will be called with system calls by NOMAD. +In library mode, users can define their black-box function as C++ code +that will be directly called by NOMAD, without system calls and temporary files. + + + TYPES OF USE : + +There are two ways of using NOMAD, one can directly use an executable or compile +the source code. + +NOMAD batch mode executable is located in directory $NOMAD_HOME/bin or %NOMAD_HOME%\bin. +In order to avoid compiling the code, you can simply use this executable. + + + HOW TO EXECUTE NOMAD : + +For informations about the execution of NOMAD, please read the user guide : + + $NOMAD_HOME/doc/user_guide.pdf or %NOMAD_HOME%\doc\user_guide.pdf + +or + + http://www.gerad.ca/NOMAD/Downloads/user_guide.pdf diff --git a/src/Barrier.cpp b/src/Barrier.cpp index ffbe2b8..ab768cd 100644 --- a/src/Barrier.cpp +++ b/src/Barrier.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Barrier.cpp - \brief Barrier for constraints handling (implementation) - \author Sebastien Le Digabel - \date 2010-04-12 - \see Barrier.hpp -*/ + \file Barrier.cpp + \brief Barrier for constraints handling (implementation) + \author Sebastien Le Digabel + \date 2010-04-12 + \see Barrier.hpp + */ #include "Barrier.hpp" /*---------------------------------------------------------*/ @@ -47,25 +47,25 @@ /*---------------------------------------------------------*/ void NOMAD::Barrier::reset ( void ) { - _prefilter.clear(); - _filter.clear(); - _h_max = _p.get_h_max_0(); - _best_feasible = NULL; - _ref = NULL; - _rho_leaps = 0; - _poll_center = NULL; - _sec_poll_center = NULL; - - if ( _peb_changes > 0 ) - _p.reset_PEB_changes(); - - _peb_changes = 0; - _peb_filter_reset = 0; - - _peb_lop.clear(); - _all_inserted.clear(); - - _one_eval_succ = _success = NOMAD::UNSUCCESSFUL; + _prefilter.clear(); + _filter.clear(); + _h_max = _p.get_h_max_0(); + _best_feasible = NULL; + _ref = NULL; + _rho_leaps = 0; + _poll_center = NULL; + _sec_poll_center = NULL; + + if ( _peb_changes > 0 ) + _p.reset_PEB_changes(); + + _peb_changes = 0; + _peb_filter_reset = 0; + + _peb_lop.clear(); + _all_inserted.clear(); + + _one_eval_succ = _success = NOMAD::UNSUCCESSFUL; } /*---------------------------------------------------------*/ @@ -73,49 +73,49 @@ void NOMAD::Barrier::reset ( void ) /*---------------------------------------------------------*/ void NOMAD::Barrier::display ( const Display & out ) const { - if ( _eval_type == NOMAD::SGTE ) - out << "surrogate barrier" << std::endl; - - if ( _p.get_barrier_type() == NOMAD::EB ) - out << "extreme barrier (EB)" << std::endl; - - else { - - out << "type : " - << ( (_p.get_barrier_type()==NOMAD::FILTER) ? "filter" : "progressive" ) - << std::endl - << "h_norm : " << _p.get_h_norm() << std::endl - << "h_min : " << _p.get_h_min() << std::endl - << "h_max : " << _h_max << std::endl; - if ( _p.get_barrier_type()==NOMAD::PB || _p.get_barrier_type()==NOMAD::PEB_P ) { - out << "poll center trigger rho : " << _p.get_rho() << std::endl - << "number of trigger leaps : " << _rho_leaps << std::endl; - if ( _p.get_barrier_type()==NOMAD::PEB_P ) - out << "number of PEB changes : " << _peb_changes << std::endl - << "number of PEB filter resets: " << _peb_filter_reset << std::endl; + if ( _eval_type == NOMAD::SGTE ) + out << "surrogate barrier" << std::endl; + + if ( _p.get_barrier_type() == NOMAD::EB ) + out << "extreme barrier (EB)" << std::endl; + + else { + + out << "type : " + << ( (_p.get_barrier_type()==NOMAD::FILTER) ? "filter" : "progressive" ) + << std::endl + << "h_norm : " << _p.get_h_norm() << std::endl + << "h_min : " << _p.get_h_min() << std::endl + << "h_max : " << _h_max << std::endl; + if ( _p.get_barrier_type()==NOMAD::PB || _p.get_barrier_type()==NOMAD::PEB_P ) { + out << "poll center trigger rho : " << _p.get_rho() << std::endl + << "number of trigger leaps : " << _rho_leaps << std::endl; + if ( _p.get_barrier_type()==NOMAD::PEB_P ) + out << "number of PEB changes : " << _peb_changes << std::endl + << "number of PEB filter resets: " << _peb_filter_reset << std::endl; + } + if ( out.get_gen_dd() == NOMAD::FULL_DISPLAY ) + out << "number of pre-filter points: " << static_cast<int>(_prefilter.size()) + << std::endl; + out << NOMAD::open_block ( "list of filter points (" + + NOMAD::itos ( _filter.size() ) + + ")" ) + << std::endl; + std::set<NOMAD::Filter_Point>::const_iterator end = _filter.end() , it; + for ( it = _filter.begin() ; it != end ; ++it ) + out << *it->get_point() << std::endl; + out.close_block(); } - if ( out.get_gen_dd() == NOMAD::FULL_DISPLAY ) - out << "number of pre-filter points: " << static_cast<int>(_prefilter.size()) - << std::endl; - out << NOMAD::open_block ( "list of filter points (" - + NOMAD::itos ( _filter.size() ) - + ")" ) - << std::endl; - std::set<NOMAD::Filter_Point>::const_iterator end = _filter.end() , it; - for ( it = _filter.begin() ; it != end ; ++it ) - out << *it->get_point() << std::endl; - out.close_block(); - } - + #ifdef DEBUG - out << NOMAD::open_block ( "list of inserted points (" - + NOMAD::itos ( _all_inserted.size() ) - + ")" ) - << std::endl; - std::list<const NOMAD::Eval_Point *>::const_iterator it2 , end2 = _all_inserted.end(); - for ( it2 = _all_inserted.begin() ; it2 != end2 ; ++it2 ) - out << **it2 << std::endl; - out.close_block(); + out << NOMAD::open_block ( "list of inserted points (" + + NOMAD::itos ( _all_inserted.size() ) + + ")" ) + << std::endl; + std::list<const NOMAD::Eval_Point *>::const_iterator it2 , end2 = _all_inserted.end(); + for ( it2 = _all_inserted.begin() ; it2 != end2 ; ++it2 ) + out << **it2 << std::endl; + out.close_block(); #endif } @@ -124,40 +124,40 @@ void NOMAD::Barrier::display ( const Display & out ) const /*------------------------------------------------------------*/ void NOMAD::Barrier::update_and_reset_success ( void ) { - if ( ( _p.get_barrier_type() == NOMAD::PB || _p.get_barrier_type() == NOMAD::PEB_P ) && - _success != NOMAD::UNSUCCESSFUL ) { - - if ( _success == NOMAD::PARTIAL_SUCCESS ) { - - if ( _filter.empty() ) - throw Barrier::Update_Error ( "Barrier.cpp" , __LINE__ , - "filter empty after a partial success" ); - - std::set<NOMAD::Filter_Point>::const_iterator it = _filter.end(); - --it; - - while ( true ) { - - if ( it->get_point()->get_h().value() < _h_max.value() ) { - set_h_max ( it->get_point()->get_h() ); - break; - } - - if ( it == _filter.begin() ) - throw Barrier::Update_Error ( "Barrier.cpp" , __LINE__ , - "could not find a filter point with h < h_max after a partial success" ); - - --it; - } + if ( ( _p.get_barrier_type() == NOMAD::PB || _p.get_barrier_type() == NOMAD::PEB_P ) && + _success != NOMAD::UNSUCCESSFUL ) { + + if ( _success == NOMAD::PARTIAL_SUCCESS ) { + + if ( _filter.empty() ) + throw Barrier::Update_Error ( "Barrier.cpp" , __LINE__ , + "filter empty after a partial success" ); + + std::set<NOMAD::Filter_Point>::const_iterator it = _filter.end(); + --it; + + while ( true ) { + + if ( it->get_point()->get_h().value() < _h_max.value() ) { + set_h_max ( it->get_point()->get_h() ); + break; + } + + if ( it == _filter.begin() ) + throw Barrier::Update_Error ( "Barrier.cpp" , __LINE__ , + "could not find a filter point with h < h_max after a partial success" ); + + --it; + } + } + + _ref = get_best_infeasible(); + if ( _ref ) + set_h_max ( _ref->get_h() ); } - - _ref = get_best_infeasible(); - if ( _ref ) - set_h_max ( _ref->get_h() ); - } - - // reset success types: - _one_eval_succ = _success = NOMAD::UNSUCCESSFUL; + + // reset success types: + _one_eval_succ = _success = NOMAD::UNSUCCESSFUL; } /*---------------------------------------------------------*/ @@ -165,45 +165,45 @@ void NOMAD::Barrier::update_and_reset_success ( void ) /*---------------------------------------------------------*/ void NOMAD::Barrier::insert ( const NOMAD::Eval_Point & x ) { - // we compare the eval types (_SGTE_ or _TRUTH_) of x and *this: - if ( x.get_eval_type() != _eval_type ) - throw Barrier::Insert_Error ( "Barrier.cpp" , __LINE__ , - "insertion of an Eval_Point into the bad Barrier object" ); - - // basic check: - if ( !x.is_eval_ok() ) { - _one_eval_succ = NOMAD::UNSUCCESSFUL; - return; - } - - // pre-filter: if tag(x) is already in the pre-filter, - // then return _UNSUCCESSFUL_: - size_t size_before = _prefilter.size(); - _prefilter.insert ( x.get_tag() ); - if ( _prefilter.size() == size_before ) { - _one_eval_succ = NOMAD::UNSUCCESSFUL; - return; - } - - // insertion in _all_inserted: - _all_inserted.push_back ( &x ); - - // other checks: - const NOMAD::Double & h = x.get_h(); - if ( !x.is_EB_ok () || - !x.get_f().is_defined () || - !h.is_defined () || - h.value() > _h_max.value() ) { - _one_eval_succ = NOMAD::UNSUCCESSFUL; - return; - } - - // insert_feasible or insert_infeasible: - _one_eval_succ = ( x.is_feasible ( _p.get_h_min() ) ) ? + // we compare the eval types (_SGTE_ or _TRUTH_) of x and *this: + if ( x.get_eval_type() != _eval_type ) + throw Barrier::Insert_Error ( "Barrier.cpp" , __LINE__ , + "insertion of an Eval_Point into the bad Barrier object" ); + + // basic check: + if ( !x.is_eval_ok() ) { + _one_eval_succ = NOMAD::UNSUCCESSFUL; + return; + } + + // pre-filter: if tag(x) is already in the pre-filter, + // then return _UNSUCCESSFUL_: + size_t size_before = _prefilter.size(); + _prefilter.insert ( x.get_tag() ); + if ( _prefilter.size() == size_before ) { + _one_eval_succ = NOMAD::UNSUCCESSFUL; + return; + } + + // insertion in _all_inserted: + _all_inserted.push_back ( &x ); + + // other checks: + const NOMAD::Double & h = x.get_h(); + if ( !x.is_EB_ok () || + !x.get_f().is_defined () || + !h.is_defined () || + h.value() > _h_max.value() ) { + _one_eval_succ = NOMAD::UNSUCCESSFUL; + return; + } + + // insert_feasible or insert_infeasible: + _one_eval_succ = ( x.is_feasible ( _p.get_h_min() ) ) ? insert_feasible ( x ) : insert_infeasible(x); - - if ( _one_eval_succ > _success ) - _success = _one_eval_succ; + + if ( _one_eval_succ > _success ) + _success = _one_eval_succ; } /*---------------------------------------------------------*/ @@ -212,26 +212,25 @@ void NOMAD::Barrier::insert ( const NOMAD::Eval_Point & x ) /*---------------------------------------------------------*/ void NOMAD::Barrier::insert ( const Barrier & b ) { - _one_eval_succ = _success = NOMAD::UNSUCCESSFUL; - - NOMAD::Eval_Point * modifiable_x; - - std::list<const NOMAD::Eval_Point *>::const_iterator it , end = b._all_inserted.end(); - for ( it = b._all_inserted.begin() ; it != end ; ++it ) { - - modifiable_x = &NOMAD::Cache::get_modifiable_point ( **it ); - - modifiable_x->set_direction ( NULL ); - modifiable_x->set_mesh_index ( NULL ); - modifiable_x->set_poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ); - modifiable_x->set_user_eval_priority ( NOMAD::Double() ); - modifiable_x->set_rand_eval_priority ( NOMAD::Double() ); - - insert ( **it ); - - if ( _one_eval_succ > _success ) - _success = _one_eval_succ; - } + _one_eval_succ = _success = NOMAD::UNSUCCESSFUL; + + NOMAD::Eval_Point * modifiable_x; + + std::list<const NOMAD::Eval_Point *>::const_iterator it , end = b._all_inserted.end(); + for ( it = b._all_inserted.begin() ; it != end ; ++it ) { + + modifiable_x = &NOMAD::Cache::get_modifiable_point ( **it ); + + modifiable_x->set_direction ( NULL ); + modifiable_x->set_poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ); + modifiable_x->set_user_eval_priority ( NOMAD::Double() ); + modifiable_x->set_rand_eval_priority ( NOMAD::Double() ); + + insert ( **it ); + + if ( _one_eval_succ > _success ) + _success = _one_eval_succ; + } } /*---------------------------------------------------------*/ @@ -239,11 +238,11 @@ void NOMAD::Barrier::insert ( const Barrier & b ) /*---------------------------------------------------------*/ NOMAD::success_type NOMAD::Barrier::insert_feasible ( const NOMAD::Eval_Point & x ) { - if ( !_best_feasible || ( x.get_f().value() < _best_feasible->get_f().value() ) ) { - _best_feasible = &x; - return NOMAD::FULL_SUCCESS; - } - return NOMAD::UNSUCCESSFUL; + if ( !_best_feasible || ( x.get_f().value() < _best_feasible->get_f().value() ) ) { + _best_feasible = &x; + return NOMAD::FULL_SUCCESS; + } + return NOMAD::UNSUCCESSFUL; } /*---------------------------------------------------------*/ @@ -251,38 +250,38 @@ NOMAD::success_type NOMAD::Barrier::insert_feasible ( const NOMAD::Eval_Point & /*---------------------------------------------------------*/ void NOMAD::Barrier::filter_insertion ( const NOMAD::Eval_Point & x , bool & insert ) { - if ( _filter.empty() ) { - _filter.insert (&x); - insert = true; - } - else { - - insert = false; - std::set<NOMAD::Filter_Point>::iterator it = _filter.begin(); - while ( it != _filter.end() ) { - if ( x < *(it->get_point()) ) { - _filter.erase(it++); - insert = true; - continue; - } - - ++it; + if ( _filter.empty() ) { + _filter.insert (&x); + insert = true; } - - if ( !insert ) { - insert = true; - std::set<NOMAD::Filter_Point>::iterator end = _filter.end(); - for ( it = _filter.begin() ; it != end ; ++it ) { - if ( *(it->get_point()) < x ) { - insert = false; - break; - } - } + else { + + insert = false; + std::set<NOMAD::Filter_Point>::iterator it = _filter.begin(); + while ( it != _filter.end() ) { + if ( x < *(it->get_point()) ) { + _filter.erase(it++); + insert = true; + continue; + } + + ++it; + } + + if ( !insert ) { + insert = true; + std::set<NOMAD::Filter_Point>::iterator end = _filter.end(); + for ( it = _filter.begin() ; it != end ; ++it ) { + if ( *(it->get_point()) < x ) { + insert = false; + break; + } + } + } + + if ( insert ) + _filter.insert (&x); } - - if ( insert ) - _filter.insert (&x); - } } /*---------------------------------------------------------*/ @@ -290,56 +289,56 @@ void NOMAD::Barrier::filter_insertion ( const NOMAD::Eval_Point & x , bool & ins /*---------------------------------------------------------*/ NOMAD::success_type NOMAD::Barrier::insert_infeasible ( const NOMAD::Eval_Point & x ) { - const NOMAD::Eval_Point * old_bi = get_best_infeasible(); - - // filter insertion: - // ----------------- - bool insert; - filter_insertion ( x , insert ); - - // filter: - // ------- - if ( _p.get_barrier_type() == NOMAD::FILTER ) { - const NOMAD::Eval_Point * bi = get_best_infeasible(); - if ( !bi ) - return NOMAD::UNSUCCESSFUL; - if ( old_bi ) { - if ( bi->get_h().value() < old_bi->get_h().value() ) - return NOMAD::FULL_SUCCESS; - if ( insert ) - return NOMAD::PARTIAL_SUCCESS; - return NOMAD::UNSUCCESSFUL; + const NOMAD::Eval_Point * old_bi = get_best_infeasible(); + + // filter insertion: + // ----------------- + bool insert; + filter_insertion ( x , insert ); + + // filter: + // ------- + if ( _p.get_barrier_type() == NOMAD::FILTER ) { + const NOMAD::Eval_Point * bi = get_best_infeasible(); + if ( !bi ) + return NOMAD::UNSUCCESSFUL; + if ( old_bi ) { + if ( bi->get_h().value() < old_bi->get_h().value() ) + return NOMAD::FULL_SUCCESS; + if ( insert ) + return NOMAD::PARTIAL_SUCCESS; + return NOMAD::UNSUCCESSFUL; + } + return NOMAD::FULL_SUCCESS; } + + // progressive barrier: + // -------------------- + + // with PEB constraints, we remember all points that we tried to insert: + if ( _p.get_barrier_type() == NOMAD::PEB_P ) + _peb_lop.push_back ( &x ); + + // first infeasible successes are considered as partial successes + // (improving iterations) + if ( !_ref ) + return NOMAD::PARTIAL_SUCCESS; + + double hx = x.get_h().value(); + double fx = x.get_f().value(); + double hr = _ref->get_h().value(); + double fr = _ref->get_f().value(); + + // failure: + if ( hx > hr || ( hx == hr && fx >= fr ) ) + return NOMAD::UNSUCCESSFUL; + + // partial success: + if ( fx > fr ) + return NOMAD::PARTIAL_SUCCESS; + + // full success: return NOMAD::FULL_SUCCESS; - } - - // progressive barrier: - // -------------------- - - // with PEB constraints, we remember all points that we tried to insert: - if ( _p.get_barrier_type() == NOMAD::PEB_P ) - _peb_lop.push_back ( &x ); - - // first infeasible successes are considered as partial successes - // (improving iterations) - if ( !_ref ) - return NOMAD::PARTIAL_SUCCESS; - - double hx = x.get_h().value(); - double fx = x.get_f().value(); - double hr = _ref->get_h().value(); - double fr = _ref->get_f().value(); - - // failure: - if ( hx > hr || ( hx == hr && fx >= fr ) ) - return NOMAD::UNSUCCESSFUL; - - // partial success: - if ( fx > fr ) - return NOMAD::PARTIAL_SUCCESS; - - // full success: - return NOMAD::FULL_SUCCESS; } /*---------------------------------------------------------*/ @@ -347,28 +346,28 @@ NOMAD::success_type NOMAD::Barrier::insert_infeasible ( const NOMAD::Eval_Point /*---------------------------------------------------------*/ const NOMAD::Eval_Point * NOMAD::Barrier::get_best_infeasible ( void ) const { - if ( _filter.empty() || _p.get_barrier_type() == NOMAD::EB ) - return NULL; - - if ( _p.get_barrier_type() == NOMAD::FILTER ) - return _filter.begin()->get_point(); // original - - return (--_filter.end())->get_point(); // original + if ( _filter.empty() || _p.get_barrier_type() == NOMAD::EB ) + return NULL; + + if ( _p.get_barrier_type() == NOMAD::FILTER ) + return _filter.begin()->get_point(); // original + + return (--_filter.end())->get_point(); // original } /*---------------------------------------------------------*/ -/* get_best_infeasible_min_viol() */ +/* get_best_infeasible_min_viol() */ /*---------------------------------------------------------*/ const NOMAD::Eval_Point * NOMAD::Barrier::get_best_infeasible_min_viol ( void ) const { - if ( _filter.empty() || _p.get_barrier_type() == NOMAD::EB ) - return NULL; - - if ( _p.get_barrier_type() == NOMAD::FILTER ) - return (--_filter.end())->get_point(); - - return _filter.begin()->get_point(); + if ( _filter.empty() || _p.get_barrier_type() == NOMAD::EB ) + return NULL; + + if ( _p.get_barrier_type() == NOMAD::FILTER ) + return (--_filter.end())->get_point(); + + return _filter.begin()->get_point(); } @@ -378,79 +377,79 @@ const NOMAD::Eval_Point * NOMAD::Barrier::get_best_infeasible_min_viol ( void ) /*---------------------------------------------------------*/ void NOMAD::Barrier::select_poll_center ( NOMAD::success_type last_it_success ) { - const NOMAD::Eval_Point * best_infeasible = get_best_infeasible(); - - _sec_poll_center = NULL; - if ( !_best_feasible && !best_infeasible ) { - _poll_center = NULL; - return; - } - if ( !best_infeasible ) { - _poll_center = _best_feasible; - return; - } - if ( !_best_feasible ) { - _poll_center = best_infeasible; - return; - } - - // filter: - if ( _p.get_barrier_type() == NOMAD::FILTER ) { - - if ( !_poll_center ) { - _poll_center = _best_feasible; - return; + const NOMAD::Eval_Point * best_infeasible = get_best_infeasible(); + + _sec_poll_center = NULL; + if ( !_best_feasible && !best_infeasible ) { + _poll_center = NULL; + return; } - - // switch: - if ( last_it_success == NOMAD::UNSUCCESSFUL ) - _poll_center = ( _poll_center==best_infeasible ) ? - _best_feasible : best_infeasible; - return; - } - - // progressive barrier: - if ( _p.get_barrier_type() == NOMAD::PB || _p.get_barrier_type() == NOMAD::PEB_P ) { - - const NOMAD::Point * last_poll_center = _poll_center; - - if ( best_infeasible->get_f() < (_best_feasible->get_f() - _p.get_rho()) ) { - _poll_center = best_infeasible; - _sec_poll_center = _best_feasible; + if ( !best_infeasible ) { + _poll_center = _best_feasible; + return; } - else { - _poll_center = _best_feasible; - _sec_poll_center = best_infeasible; + if ( !_best_feasible ) { + _poll_center = best_infeasible; + return; + } + + // filter: + if ( _p.get_barrier_type() == NOMAD::FILTER ) { + + if ( !_poll_center ) { + _poll_center = _best_feasible; + return; + } + + // switch: + if ( last_it_success == NOMAD::UNSUCCESSFUL ) + _poll_center = ( _poll_center==best_infeasible ) ? + _best_feasible : best_infeasible; + return; + } + + // progressive barrier: + if ( _p.get_barrier_type() == NOMAD::PB || _p.get_barrier_type() == NOMAD::PEB_P ) { + + const NOMAD::Point * last_poll_center = _poll_center; + + if ( best_infeasible->get_f() < (_best_feasible->get_f() - _p.get_rho()) ) { + _poll_center = best_infeasible; + _sec_poll_center = _best_feasible; + } + else { + _poll_center = _best_feasible; + _sec_poll_center = best_infeasible; + } + if ( _poll_center != last_poll_center ) + ++_rho_leaps; } - if ( _poll_center != last_poll_center ) - ++_rho_leaps; - } } /*---------------------------------------------------------*/ /* change the value of _h_max (private) */ /*---------------------------------------------------------*/ void NOMAD::Barrier::set_h_max ( const NOMAD::Double & h_max ) -{ - // _h_max update: - _h_max = h_max; - - // we remove all filter points x such that h(x) > h_max: - if ( !_filter.empty() ) { - - if ( _filter.begin()->get_point()->get_h().value() > _h_max.value() ) { - _filter.clear(); - return; +{ + // _h_max update: + _h_max = h_max; + + // we remove all filter points x such that h(x) > h_max: + if ( !_filter.empty() ) { + + if ( _filter.begin()->get_point()->get_h().value() > _h_max.value() ) { + _filter.clear(); + return; + } + + std::set<NOMAD::Filter_Point>::iterator it = _filter.end(); + do + --it; + while ( it != _filter.begin() && + it->get_point()->get_h().value() > _h_max.value() ); + ++it; + _filter.erase ( it , _filter.end() ); } - - std::set<NOMAD::Filter_Point>::iterator it = _filter.end(); - do - --it; - while ( it != _filter.begin() && - it->get_point()->get_h().value() > _h_max.value() ); - ++it; - _filter.erase ( it , _filter.end() ); - } } /*--------------------------------------------------------*/ @@ -459,88 +458,88 @@ void NOMAD::Barrier::set_h_max ( const NOMAD::Double & h_max ) /*--------------------------------------------------------*/ void NOMAD::Barrier::check_PEB_constraints ( const NOMAD::Eval_Point & x , bool display ) { - const NOMAD::Double & h_min = _p.get_h_min(); - const std::vector<NOMAD::bb_output_type> & bbot = _p.get_bb_output_type(); - const NOMAD::Point & bbo = x.get_bb_outputs(); - int nb = static_cast<int>(bbot.size()); - std::list<int> ks; - - for ( int k = 0 ; k < nb ; ++k ) { - if ( bbot[k] == NOMAD::PEB_P && bbo[k] <= h_min ) { - if ( display ) - _p.out() << std::endl - << "change status of blackbox output " << k - << " from progressive barrier constraint to extreme barrier constraint" - << std::endl; - ++_peb_changes; - _p.change_PEB_constraint_status (k); - ks.push_back(k); - } - } - - // at least one constraint changed status, so we have to update the filter - // and remove all points that have their h value changed to infinity - // (it can add new dominant points from the list _peb_lop): - if ( !ks.empty() ) { - - std::list<int>::const_iterator it_k , end_k = ks.end() , begin_k = ks.begin(); - - // we inspect the filter points if some have to be removed; if so, - // all filter candidates (stored in _peb_lop) will be re-inserted - // into the filter: - bool reset_filter = false; - std::set<NOMAD::Filter_Point>::const_iterator end = _filter.end() , it; - - for ( it = _filter.begin() ; it != end ; ++it ) { - - const NOMAD::Point & bbo_cur = it->get_point()->get_bb_outputs(); - for ( it_k = begin_k ; it_k != end_k ; ++it_k ) - if ( bbo_cur[*it_k] > h_min ) { - reset_filter = true; - break; - } - if ( reset_filter ) - break; + const NOMAD::Double & h_min = _p.get_h_min(); + const std::vector<NOMAD::bb_output_type> & bbot = _p.get_bb_output_type(); + const NOMAD::Point & bbo = x.get_bb_outputs(); + int nb = static_cast<int>(bbot.size()); + std::list<int> ks; + + for ( int k = 0 ; k < nb ; ++k ) { + if ( bbot[k] == NOMAD::PEB_P && bbo[k] <= h_min ) { + if ( display ) + _p.out() << std::endl + << "change status of blackbox output " << k + << " from progressive barrier constraint to extreme barrier constraint" + << std::endl; + ++_peb_changes; + _p.change_PEB_constraint_status (k); + ks.push_back(k); + } } - - if ( reset_filter ) { - - if ( display ) - _p.out() << std::endl << "PEB change of status: filter reset" << std::endl; - - ++_peb_filter_reset; - - _filter.clear(); - bool insert; - - std::list<const NOMAD::Eval_Point *>::const_iterator end2 = _peb_lop.end (); - std::list<const NOMAD::Eval_Point *>::iterator it2 = _peb_lop.begin(); - - while ( it2 != end2 ) { - - insert = true; - const NOMAD::Point & bbo_cur = (*it2)->get_bb_outputs(); - - for ( it_k = begin_k ; it_k != end_k ; ++it_k ) - if ( bbo_cur[*it_k] > h_min ) { - insert = false; - break; - } - - // if insert==true: this point is potentially a new filter point: - if ( insert ) { - filter_insertion ( **it2 , insert ); - ++it2; - } - - // if insert==false: it means that the current filter point - // has to be removed from filter and from _peb_lop, and - // in addition, its h is put to INF: - else { - NOMAD::Cache::get_modifiable_point ( **it2 ).set_h ( NOMAD::Double() ); - _peb_lop.erase(it2++); - } - } + + // at least one constraint changed status, so we have to update the filter + // and remove all points that have their h value changed to infinity + // (it can add new dominant points from the list _peb_lop): + if ( !ks.empty() ) { + + std::list<int>::const_iterator it_k , end_k = ks.end() , begin_k = ks.begin(); + + // we inspect the filter points if some have to be removed; if so, + // all filter candidates (stored in _peb_lop) will be re-inserted + // into the filter: + bool reset_filter = false; + std::set<NOMAD::Filter_Point>::const_iterator end = _filter.end() , it; + + for ( it = _filter.begin() ; it != end ; ++it ) { + + const NOMAD::Point & bbo_cur = it->get_point()->get_bb_outputs(); + for ( it_k = begin_k ; it_k != end_k ; ++it_k ) + if ( bbo_cur[*it_k] > h_min ) { + reset_filter = true; + break; + } + if ( reset_filter ) + break; + } + + if ( reset_filter ) { + + if ( display ) + _p.out() << std::endl << "PEB change of status: filter reset" << std::endl; + + ++_peb_filter_reset; + + _filter.clear(); + bool insert; + + std::list<const NOMAD::Eval_Point *>::const_iterator end2 = _peb_lop.end (); + std::list<const NOMAD::Eval_Point *>::iterator it2 = _peb_lop.begin(); + + while ( it2 != end2 ) { + + insert = true; + const NOMAD::Point & bbo_cur = (*it2)->get_bb_outputs(); + + for ( it_k = begin_k ; it_k != end_k ; ++it_k ) + if ( bbo_cur[*it_k] > h_min ) { + insert = false; + break; + } + + // if insert==true: this point is potentially a new filter point: + if ( insert ) { + filter_insertion ( **it2 , insert ); + ++it2; + } + + // if insert==false: it means that the current filter point + // has to be removed from filter and from _peb_lop, and + // in addition, its h is put to INF: + else { + NOMAD::Cache::get_modifiable_point ( **it2 ).set_h ( NOMAD::Double() ); + _peb_lop.erase(it2++); + } + } + } } - } } diff --git a/src/Barrier.hpp b/src/Barrier.hpp index 0d9df29..2b303a4 100644 --- a/src/Barrier.hpp +++ b/src/Barrier.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Cache.cpp b/src/Cache.cpp index 6fd9d30..dea9a34 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Cache.cpp - \brief Cache memorizing all evaluations (implementation) - \author Sebastien Le Digabel - \date 2010-04-12 - \see Cache.hpp -*/ + \file Cache.cpp + \brief Cache memorizing all evaluations (implementation) + \author Sebastien Le Digabel + \date 2010-04-12 + \see Cache.hpp + */ #include "Cache.hpp" /*-----------------------------------*/ @@ -52,7 +52,7 @@ std::set<std::string> NOMAD::Cache::_locked_files; /*------------------------------------------------------*/ int NOMAD::Cache::sizeof_init ( void ) const { - return + return sizeof ( _cache1 ) + sizeof ( _cache2 ) + sizeof ( _cache3 ) + @@ -67,8 +67,8 @@ int NOMAD::Cache::sizeof_init ( void ) const /*---------------------------------------------------------------------*/ void NOMAD::Cache::insert_extern_point ( const NOMAD::Eval_Point & x ) const { - if ( !x.get_current_run() ) - _extern_pts.push_front ( &x ); + if ( !x.get_current_run() ) + _extern_pts.push_front ( &x ); } /*----------------------------------------------------------*/ @@ -77,11 +77,11 @@ void NOMAD::Cache::insert_extern_point ( const NOMAD::Eval_Point & x ) const /*----------------------------------------------------------*/ const NOMAD::Eval_Point * NOMAD::Cache::get_and_remove_extern_point ( void ) const { - if ( _extern_pts.empty() ) - return NULL; - const NOMAD::Eval_Point * extern_point = *_extern_pts.begin(); - _extern_pts.pop_front(); - return extern_point; + if ( _extern_pts.empty() ) + return NULL; + const NOMAD::Eval_Point * extern_point = *_extern_pts.begin(); + _extern_pts.pop_front(); + return extern_point; } /*------------------------------------------*/ @@ -90,18 +90,18 @@ const NOMAD::Eval_Point * NOMAD::Cache::get_and_remove_extern_point ( void ) con /*------------------------------------------*/ const NOMAD::Eval_Point * NOMAD::Cache::find ( const NOMAD::Eval_Point & x ) const { - // check the eval types: - if ( x.get_eval_type() != _eval_type ) - throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ , - "NOMAD::Cache:find(x): x.eval_type != cache.eval_type" ); - - // find: - std::set<NOMAD::Cache_Point>::const_iterator it; - NOMAD::cache_index_type cache_index; - const NOMAD::Eval_Point * cache_x + // check the eval types: + if ( x.get_eval_type() != _eval_type ) + throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ , + "NOMAD::Cache:find(x): x.eval_type != cache.eval_type" ); + + // find: + std::set<NOMAD::Cache_Point>::const_iterator it; + NOMAD::cache_index_type cache_index; + const NOMAD::Eval_Point * cache_x = NOMAD::Cache::find ( x , it , cache_index ); - - return cache_x; + + return cache_x; } /*----------------------------------------------------*/ @@ -113,33 +113,33 @@ const NOMAD::Eval_Point * NOMAD::Cache::find ( const NOMAD::Eval_Point & x ) con /*----------------------------------------------------*/ const NOMAD::Eval_Point * NOMAD::Cache::find ( const NOMAD::Eval_Point & x , - std::set<NOMAD::Cache_Point>::const_iterator & it , - NOMAD::cache_index_type & cache_index ) const + std::set<NOMAD::Cache_Point>::const_iterator & it , + NOMAD::cache_index_type & cache_index ) const { - // search in _cache2 (points to write in a cache file): - NOMAD::Cache_Point cp ( &x ); - it = _cache2.find ( cp ); - if ( it != _cache2.end() ) { - cache_index = NOMAD::CACHE_2; - return it->get_point(); - } - - // search in _cache3 (points saved in a file): - it = _cache3.find ( cp ); - if ( it != _cache3.end() ) { - cache_index = NOMAD::CACHE_3; - return it->get_point(); - } - - // search in _cache1 (points read in an initial cache file): - it = _cache1.find ( cp ); - if ( it != _cache1.end() ) { - cache_index = NOMAD::CACHE_1; - return it->get_point(); - } - - cache_index = NOMAD::UNDEFINED_CACHE; - return NULL; + // search in _cache2 (points to write in a cache file): + NOMAD::Cache_Point cp ( &x ); + it = _cache2.find ( cp ); + if ( it != _cache2.end() ) { + cache_index = NOMAD::CACHE_2; + return it->get_point(); + } + + // search in _cache3 (points saved in a file): + it = _cache3.find ( cp ); + if ( it != _cache3.end() ) { + cache_index = NOMAD::CACHE_3; + return it->get_point(); + } + + // search in _cache1 (points read in an initial cache file): + it = _cache1.find ( cp ); + if ( it != _cache1.end() ) { + cache_index = NOMAD::CACHE_1; + return it->get_point(); + } + + cache_index = NOMAD::UNDEFINED_CACHE; + return NULL; } /*-----------------------------------------------------*/ @@ -153,56 +153,56 @@ const NOMAD::Eval_Point * NOMAD::Cache::find /*-----------------------------------------------------*/ bool NOMAD::Cache::erase ( const NOMAD::Eval_Point & x ) { - // check the eval types: - if ( x.get_eval_type() != _eval_type ) - throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ , - "NOMAD::Cache:erase(x): x.eval_type != cache.eval_type" ); - - std::set<NOMAD::Cache_Point>::iterator it; - NOMAD::cache_index_type cache_index; - - // search in cache: - const NOMAD::Eval_Point * cache_x = find ( x , it , cache_index ); - - // the point has been found: - if ( cache_x ) { - - // remove the point from the list of extern points: - if ( cache_x->get_current_run() || x.get_current_run() ) { - std::list<const NOMAD::Eval_Point*>::const_iterator end2 = _extern_pts.end(); - std::list<const NOMAD::Eval_Point*>::iterator it2 = _extern_pts.begin(); - while ( it2 != end2 ) { - if ( *it2 == cache_x || *it2 == &x ) { - _extern_pts.erase ( it2 ); - break; - } - ++it2; - } - } - - // erase the point in cache if its address is different from &x: - if ( cache_x != &x ) - delete cache_x; - - // remove the point from the cache: - _sizeof -= x.size_of(); - - switch ( cache_index ) { - case NOMAD::CACHE_1: - _cache1.erase ( it ); - break; - case NOMAD::CACHE_2: - _cache2.erase ( it ); - break; - case NOMAD::CACHE_3: - _cache3.erase ( it ); - break; - case NOMAD::UNDEFINED_CACHE: - break; + // check the eval types: + if ( x.get_eval_type() != _eval_type ) + throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ , + "NOMAD::Cache:erase(x): x.eval_type != cache.eval_type" ); + + std::set<NOMAD::Cache_Point>::iterator it; + NOMAD::cache_index_type cache_index; + + // search in cache: + const NOMAD::Eval_Point * cache_x = find ( x , it , cache_index ); + + // the point has been found: + if ( cache_x ) { + + // remove the point from the list of extern points: + if ( cache_x->get_current_run() || x.get_current_run() ) { + std::list<const NOMAD::Eval_Point*>::const_iterator end2 = _extern_pts.end(); + std::list<const NOMAD::Eval_Point*>::iterator it2 = _extern_pts.begin(); + while ( it2 != end2 ) { + if ( *it2 == cache_x || *it2 == &x ) { + _extern_pts.erase ( it2 ); + break; + } + ++it2; + } + } + + // erase the point in cache if its address is different from &x: + if ( cache_x != &x ) + delete cache_x; + + // remove the point from the cache: + _sizeof -= x.size_of(); + + switch ( cache_index ) { + case NOMAD::CACHE_1: + _cache1.erase ( it ); + break; + case NOMAD::CACHE_2: + _cache2.erase ( it ); + break; + case NOMAD::CACHE_3: + _cache3.erase ( it ); + break; + case NOMAD::UNDEFINED_CACHE: + break; + } + return true; } - return true; - } - return false; + return false; } /*-----------------------------------------------------*/ @@ -210,19 +210,19 @@ bool NOMAD::Cache::erase ( const NOMAD::Eval_Point & x ) /*-----------------------------------------------------*/ void NOMAD::Cache::clear ( void ) { - const NOMAD::Eval_Point * x = begin(); - while ( x ) { - delete x; - x = next(); - } - _cache1.clear(); - _cache2.clear(); - _cache3.clear(); - unlock(); - - _extern_pts.clear(); - - _sizeof = static_cast<float> ( sizeof_init() ); + const NOMAD::Eval_Point * x = begin(); + while ( x ) { + delete x; + x = next(); + } + _cache1.clear(); + _cache2.clear(); + _cache3.clear(); + unlock(); + + _extern_pts.clear(); + + _sizeof = static_cast<float> ( sizeof_init() ); } /*------------------------------------------------*/ @@ -231,19 +231,19 @@ void NOMAD::Cache::clear ( void ) /*------------------------------------------------*/ void NOMAD::Cache::insert ( const NOMAD::Eval_Point & x ) { - // check the eval types: - if ( x.get_eval_type() != _eval_type ) - throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ , - "NOMAD::Cache:insert(x): x.eval_type != cache.eval_type" ); - - // insertion in _extern_pts: - insert_extern_point ( x ); - - // insertion in _cache2: - NOMAD::Cache_Point cp ( &x ); - _cache2.insert ( cp ); - x.set_in_cache ( true ); - _sizeof += x.size_of(); + // check the eval types: + if ( x.get_eval_type() != _eval_type ) + throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ , + "NOMAD::Cache:insert(x): x.eval_type != cache.eval_type" ); + + // insertion in _extern_pts: + insert_extern_point ( x ); + + // insertion in _cache2: + NOMAD::Cache_Point cp ( &x ); + _cache2.insert ( cp ); + x.set_in_cache ( true ); + _sizeof += x.size_of(); } /*-------------------------------------------------------------------------*/ @@ -253,42 +253,42 @@ void NOMAD::Cache::insert ( const NOMAD::Eval_Point & x ) /*-------------------------------------------------------------------------*/ void NOMAD::Cache::insert ( Cache & c ) { - if ( &c == this ) - return; - - // check the eval types: - if ( c._eval_type != _eval_type ) - throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ , - "NOMAD::Cache:insert(c): c._eval_type != this->_eval_type" ); - - // insertion: - NOMAD::Point bbo_cache , bbo_cur; - const NOMAD::Eval_Point * cache_x; - const NOMAD::Eval_Point * cur = c.begin(); - - while ( cur ) { + if ( &c == this ) + return; - cache_x = find ( *cur ); - - // the current point is already in cache: - if ( cache_x ) { - update ( get_modifiable_point ( *cache_x ) , *cur ); - delete cur; + // check the eval types: + if ( c._eval_type != _eval_type ) + throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ , + "NOMAD::Cache:insert(c): c._eval_type != this->_eval_type" ); + + // insertion: + NOMAD::Point bbo_cache , bbo_cur; + const NOMAD::Eval_Point * cache_x; + const NOMAD::Eval_Point * cur = c.begin(); + + while ( cur ) { + + cache_x = find ( *cur ); + + // the current point is already in cache: + if ( cache_x ) { + update ( get_modifiable_point ( *cache_x ) , *cur ); + delete cur; + } + + // point not in cache: + else + insert ( *cur ); + + cur = c.next(); } - - // point not in cache: - else - insert ( *cur ); - - cur = c.next(); - } - - c._sizeof = static_cast<float> ( sizeof_init() ); - - c._cache1.clear(); - c._cache2.clear(); - c._cache3.clear(); - c._extern_pts.clear(); + + c._sizeof = static_cast<float> ( sizeof_init() ); + + c._cache1.clear(); + c._cache2.clear(); + c._cache3.clear(); + c._extern_pts.clear(); } /*------------------------------------------------------------------*/ @@ -309,52 +309,52 @@ void NOMAD::Cache::insert ( Cache & c ) // -------- const NOMAD::Eval_Point * NOMAD::Cache::begin ( void ) const { - if ( !_cache2.empty() ) { - _it = _cache2.begin(); - return _it->get_point(); - } - if ( !_cache3.empty() ) { - _it = _cache3.begin(); - return _it->get_point(); - } - if ( !_cache1.empty() ) { - _it = _cache1.begin(); - return _it->get_point(); - } - return NULL; -} - -// next() (supposes that begin() has been called) -// ------- -const NOMAD::Eval_Point * NOMAD::Cache::next ( void ) const -{ - ++_it; - - if ( !_cache2.empty() && _it == _cache2.end() ) { + if ( !_cache2.empty() ) { + _it = _cache2.begin(); + return _it->get_point(); + } if ( !_cache3.empty() ) { - _it = _cache3.begin(); - return _it->get_point(); + _it = _cache3.begin(); + return _it->get_point(); } if ( !_cache1.empty() ) { - _it = _cache1.begin(); - return _it->get_point(); + _it = _cache1.begin(); + return _it->get_point(); } return NULL; - } - +} - if ( !_cache3.empty() && _it == _cache3.end() ) { - if ( !_cache1.empty() ) { - _it = _cache1.begin(); - return _it->get_point(); +// next() (supposes that begin() has been called) +// ------- +const NOMAD::Eval_Point * NOMAD::Cache::next ( void ) const +{ + ++_it; + + if ( !_cache2.empty() && _it == _cache2.end() ) { + if ( !_cache3.empty() ) { + _it = _cache3.begin(); + return _it->get_point(); + } + if ( !_cache1.empty() ) { + _it = _cache1.begin(); + return _it->get_point(); + } + return NULL; } - return NULL; - } - - if ( !_cache1.empty() && _it == _cache1.end() ) - return NULL; - - return _it->get_point(); + + + if ( !_cache3.empty() && _it == _cache3.end() ) { + if ( !_cache1.empty() ) { + _it = _cache1.begin(); + return _it->get_point(); + } + return NULL; + } + + if ( !_cache1.empty() && _it == _cache1.end() ) + return NULL; + + return _it->get_point(); } /*---------------------------------------------------------------------*/ @@ -362,9 +362,9 @@ const NOMAD::Eval_Point * NOMAD::Cache::next ( void ) const /*---------------------------------------------------------------------*/ bool NOMAD::Cache::is_locked ( const std::string & file_name ) { - if ( file_name == _locked_file ) - return true; - return ( Cache::_locked_files.find ( file_name ) != Cache::_locked_files.end() ); + if ( file_name == _locked_file ) + return true; + return ( Cache::_locked_files.find ( file_name ) != Cache::_locked_files.end() ); } /*---------------------------------------------------------------------*/ @@ -372,13 +372,13 @@ bool NOMAD::Cache::is_locked ( const std::string & file_name ) /*---------------------------------------------------------------------*/ bool NOMAD::Cache::lock ( const std::string & file_name ) { - if ( is_locked ( file_name ) ) - return false; - - Cache::_locked_files.insert ( file_name ); - _locked_file = file_name; - - return true; + if ( is_locked ( file_name ) ) + return false; + + Cache::_locked_files.insert ( file_name ); + _locked_file = file_name; + + return true; } /*---------------------------------------------------------------------*/ @@ -386,14 +386,14 @@ bool NOMAD::Cache::lock ( const std::string & file_name ) /*---------------------------------------------------------------------*/ void NOMAD::Cache::unlock ( void ) { - if ( _locked_file.empty() ) - return; - - std::set<std::string>::iterator it = Cache::_locked_files.find ( _locked_file ); - if ( it != Cache::_locked_files.end() ) - _locked_files.erase(it); - - _locked_file.clear(); + if ( _locked_file.empty() ) + return; + + std::set<std::string>::iterator it = Cache::_locked_files.find ( _locked_file ); + if ( it != Cache::_locked_files.end() ) + _locked_files.erase(it); + + _locked_file.clear(); } /*----------------------------------------------------*/ @@ -402,77 +402,77 @@ void NOMAD::Cache::unlock ( void ) /* . private method */ /*----------------------------------------------------*/ bool NOMAD::Cache::read_points_from_cache_file ( std::ifstream & fin , - const int * p_nb_bb_outputs , - bool display ) + const int * p_nb_bb_outputs , + bool display ) { - try { - - NOMAD::Clock c; - - // the stream is placed at the first point (after the CACHE_FILE_ID tag): - fin.seekg ( sizeof ( NOMAD::CACHE_FILE_ID ) , std::ios::beg ); - - NOMAD::Cache_File_Point cfp; - NOMAD::Eval_Point * cur; - const NOMAD::Eval_Point * cache_x; - - // main loop: - while ( !fin.eof() ) { - - // reading of the Cache_File_Point: - if ( !cfp.read ( fin ) ) { - if ( fin.eof() ) - break; - return false; - } - - // we ignore this cache file point if it has a different - // number of blackbox outputs than *p_nb_bb_outputs: - if ( p_nb_bb_outputs && cfp.get_m() != *p_nb_bb_outputs ) - continue; - - // creation of the Eval_Point: - cur = new NOMAD::Eval_Point ( cfp , _eval_type ); - - // we look if the current point is already in cache: - cache_x = find ( *cur ); - - // the current point is already in cache: - if ( cache_x ) { - update ( get_modifiable_point ( *cache_x ) , *cur ); - delete cur; - } - - // point not in cache: insertion: - else { - - // insertion in _extern_pts: - insert_extern_point ( *cur ); - - // insertion in _cache1: - NOMAD::Cache_Point cp ( cur ); - _cache1.insert ( cp ); - cur->set_in_cache ( true ); - _sizeof += cur->size_of(); - } - - } // end of main loop - - // display stats on the cache load: - if ( display ) { - _out << "number of points: " << static_cast<int>(_cache1.size()) << std::endl - << "size : "; - _out.display_size_of ( _sizeof ); - _out << std::endl - << "load time : " << c.get_real_time() << 's' << std::endl; + try { + + NOMAD::Clock c; + + // the stream is placed at the first point (after the CACHE_FILE_ID tag): + fin.seekg ( sizeof ( NOMAD::CACHE_FILE_ID ) , std::ios::beg ); + + NOMAD::Cache_File_Point cfp; + NOMAD::Eval_Point * cur; + const NOMAD::Eval_Point * cache_x; + + // main loop: + while ( !fin.eof() ) { + + // reading of the Cache_File_Point: + if ( !cfp.read ( fin ) ) { + if ( fin.eof() ) + break; + return false; + } + + // we ignore this cache file point if it has a different + // number of blackbox outputs than *p_nb_bb_outputs: + if ( p_nb_bb_outputs && cfp.get_m() != *p_nb_bb_outputs ) + continue; + + // creation of the Eval_Point: + cur = new NOMAD::Eval_Point ( cfp , _eval_type ); + + // we look if the current point is already in cache: + cache_x = find ( *cur ); + + // the current point is already in cache: + if ( cache_x ) { + update ( get_modifiable_point ( *cache_x ) , *cur ); + delete cur; + } + + // point not in cache: insertion: + else { + + // insertion in _extern_pts: + insert_extern_point ( *cur ); + + // insertion in _cache1: + NOMAD::Cache_Point cp ( cur ); + _cache1.insert ( cp ); + cur->set_in_cache ( true ); + _sizeof += cur->size_of(); + } + + } // end of main loop + + // display stats on the cache load: + if ( display ) { + _out << "number of points: " << static_cast<int>(_cache1.size()) << std::endl + << "size : "; + _out.display_size_of ( _sizeof ); + _out << std::endl + << "load time : " << c.get_real_time() << 's' << std::endl; + } } - } - catch ( ... ) { - return false; - } - return true; + catch ( ... ) { + return false; + } + return true; } - + /*---------------------------------------------------------------------*/ /* . load a cache file (fill the set _cache1) */ /* . lock the file 'file_name' */ @@ -490,78 +490,78 @@ bool NOMAD::Cache::read_points_from_cache_file ( std::ifstream & fin /* ignored */ /*---------------------------------------------------------------------*/ bool NOMAD::Cache::load ( const std::string & file_name , - const int * p_nb_bb_outputs , - bool display ) + const int * p_nb_bb_outputs , + bool display ) { - if ( !file_name.empty() && file_name == _locked_file ) - return true; - - if ( file_name.empty() || !_locked_file.empty() || is_locked(file_name) ) - return false; - - // the file exists: - if ( NOMAD::check_read_file ( file_name ) ) { - - int id; - std::ifstream fin ( file_name.c_str() , std::ios::binary ); - - fin.read ( (char *) &id , sizeof(int) ); + if ( !file_name.empty() && file_name == _locked_file ) + return true; - // it is a valid cache file: - if ( !fin.fail() && id == NOMAD::CACHE_FILE_ID ) { - - // display: - if ( display ) - _out << std::endl - << NOMAD::open_block ( "loading of \'" + file_name + "\'" ); - - // read the points: - if ( !read_points_from_cache_file ( fin , p_nb_bb_outputs , display ) ) { - fin.close(); - return false; // it is not a valid cache file - } - - // lock the file: - lock ( file_name ); - - fin.close(); - - if ( display ) - _out.close_block(); - - return true; + if ( file_name.empty() || !_locked_file.empty() || is_locked(file_name) ) + return false; + + // the file exists: + if ( NOMAD::check_read_file ( file_name ) ) { + + int id; + std::ifstream fin ( file_name.c_str() , std::ios::binary ); + + fin.read ( (char *) &id , sizeof(int) ); + + // it is a valid cache file: + if ( !fin.fail() && id == NOMAD::CACHE_FILE_ID ) { + + // display: + if ( display ) + _out << std::endl + << NOMAD::open_block ( "loading of \'" + file_name + "\'" ); + + // read the points: + if ( !read_points_from_cache_file ( fin , p_nb_bb_outputs , display ) ) { + fin.close(); + return false; // it is not a valid cache file + } + + // lock the file: + lock ( file_name ); + + fin.close(); + + if ( display ) + _out.close_block(); + + return true; + } + + // it is not a valid cache file: + else { + fin.close(); + return false; + } } - - // it is not a valid cache file: + + // the file does not exist: else { - fin.close(); - return false; - } - } - - // the file does not exist: - else { - - // display: - if ( display ) - _out << std::endl << "creating cache file \'" << file_name << "\'" << std::endl; - - // create the file as a valid cache file: - std::ofstream fout ( file_name.c_str() , std::ios::binary ); - - if ( fout.fail() ) { - fout.close(); - return false; - } - - fout.write ( (char *) &NOMAD::CACHE_FILE_ID , sizeof ( NOMAD::CACHE_FILE_ID ) ); - fout.close(); - - // lock: - lock ( file_name ); - } - - return true; + + // display: + if ( display ) + _out << std::endl << "creating cache file \'" << file_name << "\'" << std::endl; + + // create the file as a valid cache file: + std::ofstream fout ( file_name.c_str() , std::ios::binary ); + + if ( fout.fail() ) { + fout.close(); + return false; + } + + fout.write ( (char *) &NOMAD::CACHE_FILE_ID , sizeof ( NOMAD::CACHE_FILE_ID ) ); + fout.close(); + + // lock: + lock ( file_name ); + } + + return true; } /*------------------------------------------------------------------*/ @@ -574,69 +574,69 @@ bool NOMAD::Cache::load ( const std::string & file_name , /*------------------------------------------------------------------*/ bool NOMAD::Cache::save ( bool overwrite , bool display ) { - if ( _locked_file.empty() ) - return true; - - // display: - if ( display ) - _out << std::endl << "saving cache file \'" << _locked_file << "\'" << std::endl; - - std::ofstream fout; - - if ( overwrite ) { - - // open: - fout.open ( _locked_file.c_str() , std::ios::binary ); - if ( fout.fail() ) { - fout.close(); - return false; - } - - // cache file tag: - fout.write ( (char *) &NOMAD::CACHE_FILE_ID , sizeof ( NOMAD::CACHE_FILE_ID ) ); - - // save all cache points: - const NOMAD::Eval_Point * cur = begin(); - while ( cur ) { - NOMAD::Cache_File_Point cfp ( *cur ); - if ( !cfp.write ( fout ) ) { - fout.close(); - return false; - } - cur = next(); - } - } - - else { - - // open and go at the end of the file: - fout.open ( _locked_file.c_str() , std::ios::binary | std::ios::app ); - if ( fout.fail() ) { - fout.close(); - return false; + if ( _locked_file.empty() ) + return true; + + // display: + if ( display ) + _out << std::endl << "saving cache file \'" << _locked_file << "\'" << std::endl; + + std::ofstream fout; + + if ( overwrite ) { + + // open: + fout.open ( _locked_file.c_str() , std::ios::binary ); + if ( fout.fail() ) { + fout.close(); + return false; + } + + // cache file tag: + fout.write ( (char *) &NOMAD::CACHE_FILE_ID , sizeof ( NOMAD::CACHE_FILE_ID ) ); + + // save all cache points: + const NOMAD::Eval_Point * cur = begin(); + while ( cur ) { + NOMAD::Cache_File_Point cfp ( *cur ); + if ( !cfp.write ( fout ) ) { + fout.close(); + return false; + } + cur = next(); + } } - std::set<NOMAD::Cache_Point>::iterator it = _cache2.begin(); - while ( it != _cache2.end() ) { - - // write it->get_point() in 'fout': - NOMAD::Cache_File_Point cfp ( *it->get_point() ); - if ( !cfp.write ( fout ) ) { - fout.close(); - return false; - } - - // transfer the point from _cache2 to _cache3: - NOMAD::Cache_Point cp = *it; // ( it->get_point() ); - _cache3.insert ( cp ); - _cache2.erase ( it++ ); + else { + + // open and go at the end of the file: + fout.open ( _locked_file.c_str() , std::ios::binary | std::ios::app ); + if ( fout.fail() ) { + fout.close(); + return false; + } + + std::set<NOMAD::Cache_Point>::iterator it = _cache2.begin(); + while ( it != _cache2.end() ) { + + // write it->get_point() in 'fout': + NOMAD::Cache_File_Point cfp ( *it->get_point() ); + if ( !cfp.write ( fout ) ) { + fout.close(); + return false; + } + + // transfer the point from _cache2 to _cache3: + NOMAD::Cache_Point cp = *it; // ( it->get_point() ); + _cache3.insert ( cp ); + _cache2.erase ( it++ ); + } } - } - - // close the file: - fout.close(); - - return true; + + // close the file: + fout.close(); + + return true; } /*-----------------------------------------------------------------*/ @@ -647,65 +647,66 @@ bool NOMAD::Cache::save ( bool overwrite , bool display ) /* . private method */ /*-----------------------------------------------------------------*/ void NOMAD::Cache::update ( NOMAD::Eval_Point & cache_x , - const NOMAD::Eval_Point & x ) const + const NOMAD::Eval_Point & x ) const { - const NOMAD::Point & bbo_x = x.get_bb_outputs(); - - if ( &cache_x == &x || - !x.is_eval_ok() || - !cache_x.is_in_cache() || - bbo_x.empty() || - cache_x != x ) - return; - - // check the eval types: - if ( x.get_eval_type () != _eval_type || - cache_x.get_eval_type() != _eval_type ) - throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ , - "NOMAD::Cache:update(): problem with the eval. types" ); - - const NOMAD::Point & bbo_cache_x = cache_x.get_bb_outputs(); - int m = bbo_cache_x.size(); - - _sizeof -= cache_x.size_of(); - - // if the current point could not evaluate and x did, - // or if the number of bb outputs is different, we set cache_x = x: - if ( !cache_x.is_eval_ok() || m != bbo_x.size() ) { - cache_x.set_eval_status ( NOMAD::EVAL_OK ); - cache_x.set_bb_output ( bbo_x ); - cache_x.set_signature ( x.get_signature () ); - cache_x.set_direction ( x.get_direction () ); - cache_x.set_mesh_index ( x.get_mesh_index() ); + const NOMAD::Point & bbo_x = x.get_bb_outputs(); + + if ( &cache_x == &x || + !x.is_eval_ok() || + !cache_x.is_in_cache() || + bbo_x.empty() || + cache_x != x ) + return; + + // check the eval types: + if ( x.get_eval_type () != _eval_type || + cache_x.get_eval_type() != _eval_type ) + throw NOMAD::Cache::Cache_Error ( "Cache.cpp" , __LINE__ , + "NOMAD::Cache:update(): problem with the eval. types" ); + + const NOMAD::Point & bbo_cache_x = cache_x.get_bb_outputs(); + int m = bbo_cache_x.size(); + + _sizeof -= cache_x.size_of(); + + // if the current point could not evaluate and x did, + // or if the number of bb outputs is different, we set cache_x = x: + if ( !cache_x.is_eval_ok() || m != bbo_x.size() ) + { + cache_x.set_eval_status ( NOMAD::EVAL_OK ); + cache_x.set_bb_output ( bbo_x ); + cache_x.set_signature ( x.get_signature () ); + cache_x.set_direction ( x.get_direction () ); + + _sizeof += cache_x.size_of(); + return; + } + + // we complete _bb_outputs: + int c1 = 0; + int c2 = 0; + + for ( int i = 0 ; i < m ; ++i ) { + + if ( bbo_cache_x[i].is_defined() ) + ++c1; + + if ( bbo_x[i].is_defined() ) + ++c2; + + if ( !bbo_cache_x[i].is_defined() && bbo_x[i].is_defined() ) + cache_x.set_bb_output ( i , bbo_x[i] ); + } + + // the two points are 'eval_ok' and have comparable outputs: + // we select the best as the one with the more defined bb_outputs: + if ( c2 > c1 ) { + cache_x.set_signature ( x.get_signature () ); + cache_x.set_direction ( x.get_direction () ); + + } + _sizeof += cache_x.size_of(); - return; - } - - // we complete _bb_outputs: - int c1 = 0; - int c2 = 0; - - for ( int i = 0 ; i < m ; ++i ) { - - if ( bbo_cache_x[i].is_defined() ) - ++c1; - - if ( bbo_x[i].is_defined() ) - ++c2; - - if ( !bbo_cache_x[i].is_defined() && bbo_x[i].is_defined() ) - cache_x.set_bb_output ( i , bbo_x[i] ); - } - - // the two points are 'eval_ok' and have comparable outputs: - // we select the best as the one with the more defined bb_outputs: - if ( c2 > c1 ) { - cache_x.set_signature ( x.get_signature () ); - cache_x.set_direction ( x.get_direction () ); - cache_x.set_mesh_index ( x.get_mesh_index() ); - } - - _sizeof += cache_x.size_of(); } /*---------------------------------------------------------*/ @@ -713,16 +714,16 @@ void NOMAD::Cache::update ( NOMAD::Eval_Point & cache_x , /*---------------------------------------------------------*/ void NOMAD::Cache::display_extern_pts ( const NOMAD::Display & out ) const { - int nb = static_cast<int>(_extern_pts.size()); - int cnt = 0; - std::list<const NOMAD::Eval_Point *>::const_iterator it , end = _extern_pts.end(); - for ( it = _extern_pts.begin() ; it != end ; ++it ) { - out << "point "; - out.display_int_w ( ++cnt , nb ); - out << "/" << nb << ": "; - (*it)->display ( out , false ); - out << std::endl; - } + int nb = static_cast<int>(_extern_pts.size()); + int cnt = 0; + std::list<const NOMAD::Eval_Point *>::const_iterator it , end = _extern_pts.end(); + for ( it = _extern_pts.begin() ; it != end ; ++it ) { + out << "point "; + out.display_int_w ( ++cnt , nb ); + out << "/" << nb << ": "; + (*it)->display_eval ( out , false ); + out << std::endl; + } } /*---------------------------------------------------------*/ @@ -730,40 +731,40 @@ void NOMAD::Cache::display_extern_pts ( const NOMAD::Display & out ) const /*---------------------------------------------------------*/ void NOMAD::Cache::display ( const NOMAD::Display & out ) const { - out << "number of cache points: " << size() << std::endl - << "size in memory : "; - out.display_size_of ( _sizeof ); - out << std::endl << "cache file : "; - if ( _locked_file.empty() ) - out << "-" << std::endl; - else - out << _locked_file << std::endl; - + out << "number of cache points: " << size() << std::endl + << "size in memory : "; + out.display_size_of ( _sizeof ); + out << std::endl << "cache file : "; + if ( _locked_file.empty() ) + out << "-" << std::endl; + else + out << _locked_file << std::endl; + #ifdef DEBUG - int nb = size(); - int cnt = 0; - out << NOMAD::open_block ( "cache points" ) << std::endl; - const NOMAD::Eval_Point * cur = begin(); - while ( cur ) { - out << "point "; - out.display_int_w ( ++cnt , nb ); - out << "/" << nb << ": "; - cur->display ( out , false ); + int nb = size(); + int cnt = 0; + out << NOMAD::open_block ( "cache points" ) << std::endl; + const NOMAD::Eval_Point * cur = begin(); + while ( cur ) { + out << "point "; + out.display_int_w ( ++cnt , nb ); + out << "/" << nb << ": "; + cur->display_eval ( out , false ); + out << std::endl; + cur = next(); + } + out.close_block(); + + // this display is repeated here as there can + // be a lot of points displayed just before: + out << "number of cache points: " << size() << std::endl + << "size in memory : "; + out.display_size_of ( _sizeof ); + out << std::endl << "cache file : "; + if ( _locked_file.empty() ) + out << "-"; + else + out << _locked_file; out << std::endl; - cur = next(); - } - out.close_block(); - - // this display is repeated here as there can - // be a lot of points displayed just before: - out << "number of cache points: " << size() << std::endl - << "size in memory : "; - out.display_size_of ( _sizeof ); - out << std::endl << "cache file : "; - if ( _locked_file.empty() ) - out << "-"; - else - out << _locked_file; - out << std::endl; #endif } diff --git a/src/Cache.hpp b/src/Cache.hpp index 1e3b132..99cfbfb 100644 --- a/src/Cache.hpp +++ b/src/Cache.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Cache_File_Point.cpp b/src/Cache_File_Point.cpp index fdece59..97aca5d 100644 --- a/src/Cache_File_Point.cpp +++ b/src/Cache_File_Point.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -82,65 +82,68 @@ NOMAD::Cache_File_Point::Cache_File_Point ( const NOMAD::Eval_Point & x ) _bbo_def ( NULL ) , _bbo_index ( NULL ) { - int i; - - // eval_status: - switch ( x.get_eval_status() ) { - case NOMAD::EVAL_FAIL: - _eval_status = 0; - break; - case NOMAD::EVAL_OK: - _eval_status = 1; - break; - case NOMAD::EVAL_IN_PROGRESS: - _eval_status = 2; - break; - case NOMAD::UNDEFINED_STATUS: - _eval_status = 3; - break; - } - - // inputs: - if ( _n > 0 ) { - _coords = new double [_n]; - for ( i = 0 ; i < _n ; ++i ) - _coords[i] = x[i].value(); - } - else - _n = 0; - - // outputs: - const NOMAD::Point & bbo = x.get_bb_outputs(); - _m = bbo.size(); - if ( _m > 0 ) { - - std::vector<double> vd; - std::vector<int> vi; - - for ( i = 0 ; i < _m ; ++i ) - if ( bbo[i].is_defined() ) { - vd.push_back ( bbo[i].value() ); - vi.push_back ( i ); - } - - _m_def = static_cast<int> ( vd.size() ); - if ( _m_def > 0 ) { - _bbo_def = new double [_m_def]; - _bbo_index = new int [_m_def]; - for ( i = 0 ; i < _m_def ; ++i ) { - _bbo_def [i] = vd[i]; - _bbo_index[i] = vi[i]; - } - } - } - else - _m = 0; - + int i; + + // eval_status: + switch ( x.get_eval_status() ) { + case NOMAD::EVAL_FAIL: + _eval_status = 0; + break; + case NOMAD::EVAL_OK: + _eval_status = 1; + break; + case NOMAD::EVAL_IN_PROGRESS: + _eval_status = 2; + break; + case NOMAD::UNDEFINED_STATUS: + _eval_status = 3; + break; + case NOMAD::EVAL_USER_REJECT: + _eval_status = 3; + break; + } + + // inputs: + if ( _n > 0 ) { + _coords = new double [_n]; + for ( i = 0 ; i < _n ; ++i ) + _coords[i] = x[i].value(); + } + else + _n = 0; + + // outputs: + const NOMAD::Point & bbo = x.get_bb_outputs(); + _m = bbo.size(); + if ( _m > 0 ) { + + std::vector<double> vd; + std::vector<int> vi; + + for ( i = 0 ; i < _m ; ++i ) + if ( bbo[i].is_defined() ) { + vd.push_back ( bbo[i].value() ); + vi.push_back ( i ); + } + + _m_def = static_cast<int> ( vd.size() ); + if ( _m_def > 0 ) { + _bbo_def = new double [_m_def]; + _bbo_index = new int [_m_def]; + for ( i = 0 ; i < _m_def ; ++i ) { + _bbo_def [i] = vd[i]; + _bbo_index[i] = vi[i]; + } + } + } + else + _m = 0; + #ifdef MEMORY_DEBUG - ++NOMAD::Cache_File_Point::_cardinality; - if ( NOMAD::Cache_File_Point::_cardinality > - NOMAD::Cache_File_Point::_max_cardinality ) - ++NOMAD::Cache_File_Point::_max_cardinality; + ++NOMAD::Cache_File_Point::_cardinality; + if ( NOMAD::Cache_File_Point::_cardinality > + NOMAD::Cache_File_Point::_max_cardinality ) + ++NOMAD::Cache_File_Point::_max_cardinality; #endif } diff --git a/src/Cache_File_Point.hpp b/src/Cache_File_Point.hpp index 717849d..3fcf4f0 100644 --- a/src/Cache_File_Point.hpp +++ b/src/Cache_File_Point.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Cache_Point.cpp b/src/Cache_Point.cpp index 01073a2..9b17725 100644 --- a/src/Cache_Point.cpp +++ b/src/Cache_Point.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Cache_Point.hpp b/src/Cache_Point.hpp index d4dfe62..eb76b6a 100644 --- a/src/Cache_Point.hpp +++ b/src/Cache_Point.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Cache_Search.cpp b/src/Cache_Search.cpp index 591c20d..58cbd70 100644 --- a/src/Cache_Search.cpp +++ b/src/Cache_Search.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Cache_Search.hpp b/src/Cache_Search.hpp index 8b954fc..25e2e51 100644 --- a/src/Cache_Search.hpp +++ b/src/Cache_Search.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Clock.cpp b/src/Clock.cpp index db4e8a5..6f95c22 100644 --- a/src/Clock.cpp +++ b/src/Clock.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -53,7 +53,8 @@ const double NOMAD::Clock::_D_CLOCKS_PER_SEC = static_cast<double>(CLOCKS_PER_SE /*---------------------------------------------------------*/ int NOMAD::Clock::get_real_time ( void ) const { - time_t t2; - time (&t2); - return static_cast<int> (difftime ( t2 , _real_t0 ) ); + time_t t2; + time (&t2); + int dti= static_cast<int>( difftime ( t2 , _real_t0 ) ); + return dti; } diff --git a/src/Clock.hpp b/src/Clock.hpp index da2fcdb..adc303d 100644 --- a/src/Clock.hpp +++ b/src/Clock.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Direction.cpp b/src/Direction.cpp index 647dfd2..7eda227 100644 --- a/src/Direction.cpp +++ b/src/Direction.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Direction.hpp b/src/Direction.hpp index 6e90984..b6c192e 100644 --- a/src/Direction.hpp +++ b/src/Direction.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Directions.cpp b/src/Directions.cpp index 6d75ab0..e52f61f 100644 --- a/src/Directions.cpp +++ b/src/Directions.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,51 +34,47 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Directions.cpp - \brief Set of polling directions (implementation) - \author Sebastien Le Digabel - \date 2010-04-13 - \see Directions.hpp -*/ + \file Directions.cpp + \brief Set of polling directions (implementation) + \author Sebastien Le Digabel + \date 2010-04-13 + \see Directions.hpp + */ #include "Directions.hpp" - -/*-----------------------------------*/ -/* static members initialization */ -/*-----------------------------------*/ -int NOMAD::Directions::_max_halton_seed = -1; +#include <math.h> +#include "XMesh.hpp" +#include "SMesh.hpp" + /*---------------------------------------------------------*/ /* constructor */ /*---------------------------------------------------------*/ -/* the Halton seed will be automatically computed later */ -/* if Parameters::_halton_seed==-1 */ -/*---------------------------------------------------------*/ NOMAD::Directions::Directions ( int nc , - const std::set<NOMAD::direction_type> & direction_types , - const std::set<NOMAD::direction_type> & sec_poll_dir_types , - int halton_seed , - const NOMAD::Display & out ) - : _nc ( nc ) , - _direction_types ( direction_types ) , - _sec_poll_dir_types ( sec_poll_dir_types ) , - _is_binary ( false ) , - _is_categorical ( false ) , - _lt_initialized ( false ) , - _primes ( NULL ) , - _halton_seed ( halton_seed ) , - _out ( out ) + const std::set<NOMAD::direction_type> & direction_types , + const std::set<NOMAD::direction_type> & sec_poll_dir_types , + const NOMAD::Display & out ) +: _nc ( nc ) , +_direction_types ( direction_types ) , +_sec_poll_dir_types ( sec_poll_dir_types ) , +_is_binary ( false ) , +_is_categorical ( false ) , +_lt_initialized ( false ) , +_out ( out ) { - // check the directions: - if ( _direction_types.find ( NOMAD::NO_DIRECTION ) != _direction_types.end() ) - _direction_types.clear(); - if ( _sec_poll_dir_types.find ( NOMAD::NO_DIRECTION ) != _sec_poll_dir_types.end() ) - _sec_poll_dir_types.clear(); - - // is_orthomads: true if at least one direction is of type Ortho-MADS: - _is_orthomads = NOMAD::dirs_have_orthomads ( _direction_types ); - if ( !_is_orthomads ) - _is_orthomads = NOMAD::dirs_have_orthomads ( _sec_poll_dir_types ); + // check the directions: + if ( _direction_types.find ( NOMAD::NO_DIRECTION ) != _direction_types.end() ) + _direction_types.clear(); + + if ( _sec_poll_dir_types.find ( NOMAD::NO_DIRECTION ) != _sec_poll_dir_types.end() ) + _sec_poll_dir_types.clear(); + + // is_orthomads: true if at least one direction is of type Ortho-MADS: + _is_orthomads = NOMAD::dirs_have_orthomads ( _direction_types ); + if ( !_is_orthomads ) + _is_orthomads = NOMAD::dirs_have_orthomads ( _sec_poll_dir_types ); + + } /*---------------------------------------------------------*/ @@ -86,12 +82,13 @@ NOMAD::Directions::Directions /*---------------------------------------------------------*/ NOMAD::Directions::~Directions ( void ) { - if ( _lt_initialized ) { - int n = 2 * NOMAD::L_LIMITS; - for ( int i = 0 ; i <= n ; ++i ) - delete _bl[i]; - } - delete [] _primes; + if ( _lt_initialized ) + { + int n = 2 * NOMAD::L_LIMITS; + for ( int i = 0 ; i <= n ; ++i ) + delete _bl[i]; + } + } /*---------------------------------------------------------*/ @@ -99,53 +96,13 @@ NOMAD::Directions::~Directions ( void ) /*---------------------------------------------------------*/ void NOMAD::Directions::lt_mads_init ( void ) { - int n = 2 * NOMAD::L_LIMITS; - for ( int i = 0 ; i <= n ; ++i ) { - _bl [i] = NULL; - _hat_i[i] = -1; - } - _lt_initialized = true; -} - -/*------------------------------------------------------*/ -/* static method for computing a Halton seed (static) */ -/*------------------------------------------------------*/ -int NOMAD::Directions::compute_halton_seed ( int n ) { - int * primes = new int [n]; - NOMAD::construct_primes ( n , primes ); - int halton_seed = primes[n-1]; - delete [] primes; - if ( halton_seed > NOMAD::Directions::_max_halton_seed ) - NOMAD::Directions::_max_halton_seed = halton_seed; - if ( halton_seed > NOMAD::Mesh::get_max_halton_index() ) - NOMAD::Mesh::set_max_halton_index ( halton_seed ); - return halton_seed; -} - -/*---------------------------------------------------------*/ -/* Ortho-MADS initializations (private) */ -/*---------------------------------------------------------*/ -void NOMAD::Directions::ortho_mads_init ( int halton_seed ) -{ - _is_orthomads = true; - - if ( !_primes ) { - _primes = new int[_nc]; - NOMAD::construct_primes ( _nc , _primes ); - } - - _halton_seed = ( halton_seed < 0 ) ? _primes[_nc-1] : halton_seed; - - if ( _halton_seed > NOMAD::Directions::_max_halton_seed ) - NOMAD::Directions::_max_halton_seed = _halton_seed; - -#ifdef DEBUG - _out << std::endl << "Ortho-MADS Halton seed (t0) = " - << _halton_seed << std::endl; -#endif - - if ( halton_seed > NOMAD::Mesh::get_max_halton_index() ) - NOMAD::Mesh::set_max_halton_index ( halton_seed ); + int n = 2 * NOMAD::L_LIMITS; + for ( int i = 0 ; i <= n ; ++i ) + { + _bl [i] = NULL; + _hat_i[i] = -1; + } + _lt_initialized = true; } /*---------------------------------------------------------*/ @@ -153,16 +110,15 @@ void NOMAD::Directions::ortho_mads_init ( int halton_seed ) /*---------------------------------------------------------*/ void NOMAD::Directions::set_binary ( void ) { - _is_binary = true; - _is_categorical = false; - _is_orthomads = false; - _halton_seed = -1; - _direction_types.clear(); - _direction_types.insert ( NOMAD::GPS_BINARY ); - if ( !_sec_poll_dir_types.empty() ) { - _sec_poll_dir_types.clear(); - _sec_poll_dir_types.insert ( NOMAD::GPS_BINARY ); - } + _is_binary = true; + _is_categorical = false; + _is_orthomads = false; + _direction_types.clear(); + _direction_types.insert ( NOMAD::GPS_BINARY ); + if ( !_sec_poll_dir_types.empty() ) { + _sec_poll_dir_types.clear(); + _sec_poll_dir_types.insert ( NOMAD::GPS_BINARY ); + } } /*---------------------------------------------------------*/ @@ -170,12 +126,11 @@ void NOMAD::Directions::set_binary ( void ) /*---------------------------------------------------------*/ void NOMAD::Directions::set_categorical ( void ) { - _is_categorical = true; - _is_binary = false; - _is_orthomads = false; - _halton_seed = -1; - _direction_types.clear(); - _sec_poll_dir_types.clear(); + _is_categorical = true; + _is_binary = false; + _is_orthomads = false; + _direction_types.clear(); + _sec_poll_dir_types.clear(); } /*----------------------------------------------------------------------*/ @@ -185,674 +140,532 @@ void NOMAD::Directions::set_categorical ( void ) void NOMAD::Directions::compute_binary_directions ( std::list<NOMAD::Direction> & d ) const { - // _GPS_BINARY_ n directions: - NOMAD::Direction * pd; - for ( int i = 0 ; i < _nc ; ++i ) { - d.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_BINARY ) ); - pd = &(*(--d.end())); - (*pd)[i] = 1.0; - } + // _GPS_BINARY_ n directions: + NOMAD::Direction * pd; + for ( int i = 0 ; i < _nc ; ++i ) { + d.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_BINARY ) ); + pd = &(*(--d.end())); + (*pd)[i] = 1.0; + } } -/*---------------------------------------------------------*/ -/* get the directions for a given mesh */ -/*---------------------------------------------------------*/ -void NOMAD::Directions::compute ( std::list<NOMAD::Direction> & dirs, - NOMAD::poll_type poll , - const NOMAD::Point & poll_center , - int mesh_index , - int halton_index , - const NOMAD::Direction & feas_success_dir , - const NOMAD::Direction & infeas_success_dir ) + +/*----------------------------------------------------------------------------*/ +/* get the directions on a unit n-sphere for a given mesh */ +/*----------------------------------------------------------------------------*/ +void NOMAD::Directions::compute ( std::list<NOMAD::Direction> & dirs , + NOMAD::poll_type poll , + const NOMAD::OrthogonalMesh & mesh ) { - - dirs.clear(); - - // categorical variables: do nothing: - if ( _is_categorical ) - return; - - // binary variables: we use special directions: - if ( _is_binary ) - { - compute_binary_directions ( dirs ); - return; - } - - NOMAD::Double pow_gps , cst; - const NOMAD::Direction * bl; - NOMAD::Direction * pd; - int i , j , k , hat_i; - std::list<NOMAD::Direction>::const_iterator it2 , end2; - - /*-----------------------------------*/ - /* loop on the types of directions */ - /*-----------------------------------*/ - const std::set<NOMAD::direction_type> & dir_types = + + dirs.clear(); + + // categorical variables: do nothing: + if ( _is_categorical ) + return; + + // binary variables: we use special directions: + if ( _is_binary ) + { + compute_binary_directions ( dirs ); + return; + } + + NOMAD::Double pow_gps , cst; + const NOMAD::Direction * bl; + NOMAD::Direction * pd; + int i , j , k , hat_i; + std::list<NOMAD::Direction>::iterator it2 , end2; + + const NOMAD::Point mesh_indices=mesh.get_mesh_indices(); + int mesh_index=int(mesh_indices[0].value()); // single mesh_index used only for isotropic mesh + + + /*-----------------------------------*/ + /* loop on the types of directions */ + /*-----------------------------------*/ + const std::set<NOMAD::direction_type> & dir_types = (poll == NOMAD::PRIMARY) ? _direction_types : _sec_poll_dir_types; - - std::set<NOMAD::direction_type>::const_iterator it , end = dir_types.end() ; - for ( it = dir_types.begin() ; it != end ; ++it ) - { - - if ( *it == NOMAD::UNDEFINED_DIRECTION || - *it == NOMAD::NO_DIRECTION || - *it == NOMAD::MODEL_SEARCH_DIR ) - continue; - - /*--------------*/ - /* Ortho-MADS */ - /*--------------*/ - if ( NOMAD::dir_is_orthomads (*it) ) - { - - // Ortho-MADS initializations: - if ( !_primes ) - ortho_mads_init ( _halton_seed ); - - // halton index: - if ( halton_index < 0 ) - { - int max_halton_index = NOMAD::Mesh::get_max_halton_index(); - - // mesh_index+ _halton_seed -> used to make sure that the sequence of strictly increasing mesh_index produces a non biased sequence of halton_index - halton_index = ( mesh_index >= NOMAD::Mesh::get_max_mesh_index() ) ? mesh_index + _halton_seed : max_halton_index + 1; - if ( halton_index > max_halton_index ) - NOMAD::Mesh::set_max_halton_index ( halton_index ); - } - - NOMAD::Direction halton_dir ( _nc , 0.0 , *it ); - NOMAD::Double alpha_t_l; - - if ( compute_halton_dir ( halton_index , - mesh_index , - alpha_t_l , - halton_dir ) ) { - + + std::set<NOMAD::direction_type>::const_iterator it , end = dir_types.end() ; + for ( it = dir_types.begin() ; it != end ; ++it ) + { + + if ( *it == NOMAD::UNDEFINED_DIRECTION || + *it == NOMAD::NO_DIRECTION || + *it == NOMAD::MODEL_SEARCH_DIR ) + continue; + + /*--------------------------------------------------*/ + /* Ortho-MADS */ + /* ---> dirs are on a unit n-sphere by construction */ + /*--------------------------------------------------*/ + if ( NOMAD::dir_is_orthomads (*it) ) + { + bool success_dir; + + + NOMAD::Direction dir ( _nc , 0.0 , *it ); + NOMAD::Double alpha_t_l; + + success_dir=compute_dir_on_unit_sphere ( dir ); + + if ( success_dir ) + { #ifdef DEBUG - _out << std::endl - << NOMAD::open_block ( "compute Ortho-MADS directions with" ) - << "type = " << *it << std::endl - << "Halton index (tk) = " << halton_index << std::endl - << "mesh index (lk) = " << mesh_index << std::endl - << "alpha (tk,lk) = " << alpha_t_l << std::endl - << "Halton direction = ( "; - halton_dir.NOMAD::Point::display ( _out , " " , -1 , -1 ); - _out << " )" << std::endl << NOMAD::close_block(); + if ( dynamic_cast<const NOMAD::XMesh*> ( &mesh ) ) + { + _out << std::endl + << NOMAD::open_block ( "compute Ortho-MADS directions with XMesh" ) + << "type = " << *it << std::endl; + NOMAD::Point mesh_indices=mesh.get_mesh_indices(); + _out<< "Mesh indices = ( "; + mesh_indices.NOMAD::Point::display( _out, " " , -1 , -1 ); + _out << " )" << std::endl; + _out<< "Unit sphere Direction = ( "; + dir.NOMAD::Point::display ( _out , " " , -1 , -1 ); + _out << " )" << std::endl << NOMAD::close_block(); + } + else if ( dynamic_cast<const NOMAD::SMesh*> ( &mesh ) ) + { + _out << std::endl + << NOMAD::open_block ( "compute Ortho-MADS directions with SMesh" ) + << "type = " << *it + << " on isotropic mesh " << std::endl + << "mesh index (lk) = " << mesh_index << std::endl + << "alpha (tk,lk) = " << alpha_t_l << std::endl + << "Unit sphere Direction = ( "; + dir.NOMAD::Point::display ( _out , " " , -1 , -1 ); + _out << " )" << std::endl << NOMAD::close_block(); + + } + #endif - - - - // Ortho-MADS 2n and n+1: - // ---------------------- - if ( *it == NOMAD::ORTHO_2N || *it == NOMAD::ORTHO_NP1_QUAD || *it == NOMAD::ORTHO_NP1_NEG ) - { - - // creation of the 2n directions: - // For ORTHO_NP1 the reduction from 2N to N+1 is done in MADS::POLL - NOMAD::Direction ** H = new NOMAD::Direction * [2*_nc]; - - // Ordering D_k alternates Hk and -Hk instead of [H_k -H_k] - for ( i = 0 ; i < _nc ; ++i ) - { - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , *it ) ); - H[i ] = &(*(--dirs.end())); - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , *it ) ); - H[i+_nc] = &(*(--dirs.end())); - } - - // Householder transformations on the 2n directions: - householder ( halton_dir , - true , // complete_to_2n = true - H ); - - delete [] H; - - - } - - // Ortho-MADS 1 or Ortho-MADS 2: - // ----------------------------- - else { - dirs.push_back ( halton_dir ); - if ( *it == NOMAD::ORTHO_2 ) - dirs.push_back ( -halton_dir ); - } - } - } - - /*-----------*/ - /* LT-MADS */ - /*-----------*/ - else if ( NOMAD::dir_is_ltmads (*it) ) { - - if ( !_lt_initialized) - lt_mads_init(); - - bl = get_bl ( mesh_index , *it , hat_i ); - - // LT-MADS 1 or LT-MADS 2: -b(l) and/or b(l): - // ------------------------------------------ - if ( *it == NOMAD::LT_1 || *it == NOMAD::LT_2 ) { - dirs.push_back ( - *bl ); - if ( *it == NOMAD::LT_2 ) - dirs.push_back ( *bl ); - } - - // LT-MADS 2n or LT-MADS n+1: - // -------------------------- - else { - - // row permutation vector: - int * row_permutation_vector = new int [_nc]; - row_permutation_vector[hat_i] = hat_i; - - NOMAD::Random_Pickup rp ( _nc ); - - for ( i = 0 ; i < _nc ; ++i ) - if ( i != hat_i ) { - j = rp.pickup(); - if ( j == hat_i ) - j = rp.pickup(); - row_permutation_vector[i] = j; - } - - rp.reset(); - - for ( j = 0 ; j < _nc ; ++j ) { - - i = rp.pickup(); - - if ( i != hat_i ) { - - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , *it ) ); - pd = &(*(--dirs.end())); - - create_lt_direction ( mesh_index , *it , i , hat_i , pd ); - - permute_coords ( *pd , row_permutation_vector ); - } - else - dirs.push_back ( *bl ); - - // completion to maximal basis: - if ( *it == NOMAD::LT_2N ) - dirs.push_back ( NOMAD::Direction ( - *(--dirs.end()) , NOMAD::LT_2N ) ); - } - - delete [] row_permutation_vector; - - // completion to minimal basis: - if ( *it == NOMAD::LT_NP1 ) { - - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::LT_NP1 ) ); - pd = &(*(--dirs.end())); - - end2 = --dirs.end(); - for ( it2 = dirs.begin() ; it2 != end2 ; ++it2 ) { - for ( i = 0 ; i < _nc ; ++i ) - (*pd)[i] -= (*it2)[i]; - } - } - } - } - - /*-------*/ - /* GPS */ - /*-------*/ - else { - - // GPS for binary variables: should'nt be here: - if ( *it == NOMAD::GPS_BINARY ) { + // Ortho-MADS 2n and n+1: + // ---------------------- + if ( *it == NOMAD::ORTHO_2N || *it == NOMAD::ORTHO_NP1_QUAD || *it == NOMAD::ORTHO_NP1_NEG ) + { + + // creation of the 2n directions: + // For ORTHO_NP1 the reduction from 2N to N+1 is done in MADS::POLL + NOMAD::Direction ** H = new NOMAD::Direction * [2*_nc]; + + // Ordering D_k alternates Hk and -Hk instead of [H_k -H_k] + for ( i = 0 ; i < _nc ; ++i ) + { + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , *it ) ); + H[i ] = &(*(--dirs.end())); + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , *it ) ); + H[i+_nc] = &(*(--dirs.end())); + } + + // Householder transformations on the 2n directions on a unit n-sphere: + householder ( dir , true , H ); + + + delete [] H; + + + } + + // Ortho-MADS 1 or Ortho-MADS 2: + // ----------------------------- + else + { + dirs.push_back ( dir ); + if ( *it == NOMAD::ORTHO_2 ) + dirs.push_back ( -dir ); + } + } + } + + /*--------------------------------*/ + /* LT-MADS */ + /* ---> dirs NOT on unit n-sphere */ + /*--------------------------------*/ + else if ( NOMAD::dir_is_ltmads (*it) ) + { + + if ( !_lt_initialized) + lt_mads_init(); + + bl = get_bl ( mesh , *it , hat_i ); + + // LT-MADS 1 or LT-MADS 2: -b(l) and/or b(l): + // ------------------------------------------ + if ( *it == NOMAD::LT_1 || *it == NOMAD::LT_2 ) + { + dirs.push_back ( - *bl ); + if ( *it == NOMAD::LT_2 ) + dirs.push_back ( *bl ); + } + + // LT-MADS 2n or LT-MADS n+1: + // -------------------------- + else { + + // row permutation vector: + int * row_permutation_vector = new int [_nc]; + row_permutation_vector[hat_i] = hat_i; + + NOMAD::Random_Pickup rp ( _nc ); + + for ( i = 0 ; i < _nc ; ++i ) + if ( i != hat_i ) + { + j = rp.pickup(); + if ( j == hat_i ) + j = rp.pickup(); + row_permutation_vector[i] = j; + } + + rp.reset(); + + for ( j = 0 ; j < _nc ; ++j ) + { + i = rp.pickup(); + if ( i != hat_i ) + { + + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , *it ) ); + pd = &(*(--dirs.end())); + + create_lt_direction ( mesh , *it , i , hat_i , pd ); + permute_coords ( *pd , row_permutation_vector ); + } + else + dirs.push_back ( *bl ); + + // completion to maximal basis: + if ( *it == NOMAD::LT_2N ) + dirs.push_back ( NOMAD::Direction ( - *(--dirs.end()) , NOMAD::LT_2N ) ); + + } + + delete [] row_permutation_vector; + + // completion to minimal basis: + if ( *it == NOMAD::LT_NP1 ) + { + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::LT_NP1 ) ); + pd = &(*(--dirs.end())); + + end2 = --dirs.end(); + for ( it2 = dirs.begin() ; it2 != end2 ; ++it2 ) + { + for ( i = 0 ; i < _nc ; ++i ) + (*pd)[i] -= (*it2)[i]; + } + } + } + + + } + + /*--------------------------------*/ + /* GPS */ + /* ---> dirs NOT on unit n-sphere */ + /*--------------------------------*/ + else + { + + // GPS for binary variables: should'nt be here: + if ( *it == NOMAD::GPS_BINARY ) + { #ifdef DEBUG - _out << std::endl << "Warning (" << "Directions.cpp" << ", " << __LINE__ - << "): tried to generate binary directions at the wrong place)" - << std::endl << std::endl; + _out << std::endl << "Warning (" << "Directions.cpp" << ", " << __LINE__ + << "): tried to generate binary directions at the wrong place)" + << std::endl << std::endl; #endif - dirs.clear(); - return; - } - - // this value represents the non-zero values in GPS directions - // (it is tau^{|ell_k|/2}, and it is such that Delta^m_k * pow_gps = Delta^p_k): - if ( !pow_gps.is_defined() ) - pow_gps = pow ( NOMAD::Mesh::get_mesh_update_basis() , abs(mesh_index) / 2.0 ); - - // GPS 2n, static: - // --------------- - if ( *it == NOMAD::GPS_2N_STATIC ) { - - for ( i = 0 ; i < _nc ; ++i ) { - - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_STATIC ) ); - pd = &(*(--dirs.end())); - (*pd)[i] = pow_gps; - - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_STATIC ) ); - pd = &(*(--dirs.end())); - (*pd)[i] = -pow_gps; - } - } - - // GPS 2n, random: - // --------------- - else if ( *it == NOMAD::GPS_2N_RAND ) { - - int v , cnt; - - std::list <int>::const_iterator end3; - std::list <int>::iterator it3; - std::list <int> rem_cols; - std::vector<int> rem_col_by_row ( _nc ); - - // creation of the 2n directions: - std::vector<NOMAD::Direction *> pdirs ( 2 * _nc ); - - for ( i = 0 ; i < _nc ; ++i ) { - - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_RAND ) ); - pdirs[i] = &(*(--dirs.end())); - (*pdirs[i])[i] = pow_gps; - - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_RAND ) ); - pdirs[i+_nc] = &(*(--dirs.end())); - (*pdirs[i+_nc])[i] = -pow_gps; - - rem_cols.push_back(i); - rem_col_by_row[i] = i; - } - - // random perturbations: - for ( i = 1 ; i < _nc ; ++i ) { - if ( rem_col_by_row[i] > 0 ) { - v = NOMAD::RNG::rand()%3 - 1; // v in { -1 , 0 , 1 } - if ( v ) { - - // we decide a (i,j) couple: - k = NOMAD::RNG::rand()%(rem_col_by_row[i]); - cnt = 0; - end3 = rem_cols.end(); - it3 = rem_cols.begin(); - while ( cnt != k ) { - ++it3; - ++cnt; - } - j = *it3; - - // the perturbation: - (*pdirs[i])[j] = (*pdirs[j+_nc])[i] = -v * pow_gps; - (*pdirs[j])[i] = (*pdirs[i+_nc])[j] = v * pow_gps; - - // updates: - rem_cols.erase(it3); - it3 = rem_cols.begin(); - while ( *it3 != i ) - ++it3; - rem_cols.erase(it3); - for ( k = i+1 ; k < _nc ; ++k ) - rem_col_by_row[k] -= j<k ? 2 : 1; - } - } - } - } - - // GPS n+1, static: - // ---------------- - else if ( *it == NOMAD::GPS_NP1_STATIC ) { - - // (n+1)^st direction: - dirs.push_back ( NOMAD::Direction ( _nc , -pow_gps , NOMAD::GPS_NP1_STATIC ) ); - - // first n directions: - for ( i = 0 ; i < _nc ; ++i ) { - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC ) ); - pd = &(*(--dirs.end())); - (*pd)[i] = pow_gps; - } - } - - // GPS n+1, random: - // ---------------- - else if ( *it == NOMAD::GPS_NP1_RAND ) - { - - // (n+1)^st direction: - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_RAND ) ); - NOMAD::Direction * pd1 = &(*(--dirs.end())); - - NOMAD::Double d; - - // first n directions: - for ( i = 0 ; i < _nc ; ++i ) - { - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_RAND ) ); - pd = &(*(--dirs.end())); - - d = NOMAD::RNG::rand()%2 ? -pow_gps : pow_gps; - (*pd )[i] = d; - (*pd1)[i] = -d; - } - } - - // GPS n+1, static, uniform angles: - // -------------------------------- - else if ( *it == NOMAD::GPS_NP1_STATIC_UNIFORM ) - { - - cst = pow_gps * sqrt(static_cast<double>(_nc)*(_nc+1))/_nc; - - // n first directions: - for ( j = _nc-1 ; j >= 0 ; --j ) - { - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); - pd = &(*(--dirs.end())); - - k = _nc-j-1; - - for ( i = 0 ; i < k ; ++i ) - (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); - - (*pd)[k] = (cst * (j+1)) / sqrt(static_cast<double>(j+1)*(j+2)); - - } - - // (n+1)^st direction: - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); - pd = &(*(--dirs.end())); - for ( i = 0 ; i < _nc ; ++i ) - (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); - - } - - // GPS n+1, random, uniform angles: - // -------------------------------- - // (we apply the procedure defined in - // "Pattern Search Methods for user-provided points: - // application to molecular geometry problems", - // by Alberto, Nogueira, Rocha and Vicente, - // SIOPT 14-4, 1216-1236, 2004, doi:10.1137/S1052623400377955) - else if ( *it == NOMAD::GPS_NP1_RAND_UNIFORM ) - { - - cst = pow_gps * sqrt(static_cast<double>(_nc)*(_nc+1))/_nc; - - // n first directions: - for ( j = _nc-1 ; j >= 0 ; --j ) - { - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); - pd = &(*(--dirs.end())); - - k = _nc-j-1; - - for ( i = 0 ; i < k ; ++i ) - (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); - - (*pd)[k] = (cst * (j+1)) / sqrt(static_cast<double>(j+1)*(j+2)); - - } - - // (n+1)^st direction: - dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); - pd = &(*(--dirs.end())); - for ( i = 0 ; i < _nc ; ++i ) - (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); - - // random perturbations: - NOMAD::Random_Pickup rp ( _nc ); - std::vector<bool> done ( _nc ); - bool chg_sgn; - std::list<NOMAD::Direction>::iterator it; - NOMAD::Double tmp; - - end2 = dirs.end(); - for ( i = 0 ; i < _nc ; ++i ) - done[i] = false; - - for ( i = 0 ; i < _nc ; ++i ) - { - - k = rp.pickup(); - - if ( i != k && !done[i] ) - { - - chg_sgn = ( NOMAD::RNG::rand()%2 != 0 ); - - for ( it = dirs.begin() ; it != end2 ; ++it ) - { - tmp = (*it)[i]; - (*it)[i] = ( chg_sgn ? -1.0 : 1.0 ) * (*it)[k]; - (*it)[k] = tmp; - } - - done[i] = done[k] = true; - } - else - if ( NOMAD::RNG::rand()%2 ) - for ( it = dirs.begin() ; it != end2 ; ++it ) - (*it)[i] = -(*it)[i]; - } - } - } - } // end of loop on the types of directions -} - -/*----------------------------------------------------------------*/ -/* get just one direction for a given mesh (used by VNS search) */ -/*----------------------------------------------------------------*/ -bool NOMAD::Directions::compute_one_direction ( NOMAD::Direction & dir, - int mesh_index, - int halton_index ) -{ - dir.clear(); - - // categorical variables: do nothing: - if ( _is_categorical ) - return false; - - /*-------------------------------*/ - /* binary variables */ - /* (we use a random direction) */ - /*-------------------------------*/ - if ( _is_binary ) { - - dir.reset ( _nc , 0.0 ); - dir.set_type ( NOMAD::GPS_BINARY ); - dir[NOMAD::RNG::rand()%_nc] = (NOMAD::RNG::rand()%2) ? -1.0 : 1.0; - } - - /*----------------*/ - /* Ortho-MADS */ - /*----------------*/ - else if ( _is_orthomads ) { - - if ( !_primes ) - ortho_mads_init ( _halton_seed ); - - dir.reset ( _nc , 0.0 ); - dir.set_type ( NOMAD::ORTHO_1 ); - - NOMAD::Double alpha_t_l; - - if ( !compute_halton_dir ( halton_index , mesh_index , alpha_t_l , dir ) ) - return false; -// } - } - - /*-------------*/ - /* LT-MADS 1 */ - /*-------------*/ - else { - if ( !_lt_initialized) - lt_mads_init(); - int hat_i; - dir = *get_bl ( mesh_index , NOMAD::LT_1 , hat_i ); - } - - return true; + dirs.clear(); + return; + } + + // this value represents the non-zero values in GPS directions + // (it is tau^{|ell_k|/2}, and it is such that delta_k * pow_gps = Delta_k): + if ( !pow_gps.is_defined() ) + pow_gps = pow ( mesh.get_update_basis() , abs(mesh_index) / 2.0 ); + + // GPS 2n, static: + // --------------- + + if ( *it == NOMAD::GPS_2N_STATIC ) + { + for ( i = 0 ; i < _nc ; ++i ) + { + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_STATIC ) ); + pd = &(*(--dirs.end())); + (*pd)[i] = pow_gps; + + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_STATIC ) ); + pd = &(*(--dirs.end())); + (*pd)[i] = -pow_gps; + } + } + + // GPS 2n, random: + // --------------- + else if ( *it == NOMAD::GPS_2N_RAND ) + { + + int v , cnt; + + std::list <int>::const_iterator end3; + std::list <int>::iterator it3; + std::list <int> rem_cols; + std::vector<int> rem_col_by_row ( _nc ); + + // creation of the 2n directions: + std::vector<NOMAD::Direction *> pdirs ( 2 * _nc ); + + for ( i = 0 ; i < _nc ; ++i ) + { + + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_RAND ) ); + pdirs[i] = &(*(--dirs.end())); + (*pdirs[i])[i] = pow_gps; + + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_2N_RAND ) ); + pdirs[i+_nc] = &(*(--dirs.end())); + (*pdirs[i+_nc])[i] = -pow_gps; + + rem_cols.push_back(i); + rem_col_by_row[i] = i; + } + + // random perturbations: + for ( i = 1 ; i < _nc ; ++i ) + { + if ( rem_col_by_row[i] > 0 ) + { + v = NOMAD::RNG::rand()%3 - 1; // v in { -1 , 0 , 1 } + if ( v ) + { + + // we decide a (i,j) couple: + k = NOMAD::RNG::rand()%(rem_col_by_row[i]); + cnt = 0; + end3 = rem_cols.end(); + it3 = rem_cols.begin(); + while ( cnt != k ) + { + ++it3; + ++cnt; + } + j = *it3; + + // the perturbation: + (*pdirs[i])[j] = (*pdirs[j+_nc])[i] = -v * pow_gps; + (*pdirs[j])[i] = (*pdirs[i+_nc])[j] = v * pow_gps; + + // updates: + rem_cols.erase(it3); + it3 = rem_cols.begin(); + while ( *it3 != i ) + ++it3; + rem_cols.erase(it3); + for ( k = i+1 ; k < _nc ; ++k ) + rem_col_by_row[k] -= j<k ? 2 : 1; + } + } + } + } + + // GPS n+1, static: + // ---------------- + else if ( *it == NOMAD::GPS_NP1_STATIC ) + { + + // (n+1)^st direction: + dirs.push_back ( NOMAD::Direction ( _nc , -pow_gps , NOMAD::GPS_NP1_STATIC ) ); + + // first n directions: + for ( i = 0 ; i < _nc ; ++i ) + { + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC ) ); + pd = &(*(--dirs.end())); + (*pd)[i] = pow_gps; + } + } + + // GPS n+1, random: + // ---------------- + else if ( *it == NOMAD::GPS_NP1_RAND ) + { + + // (n+1)^st direction: + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_RAND ) ); + NOMAD::Direction * pd1 = &(*(--dirs.end())); + + NOMAD::Double d; + + // first n directions: + for ( i = 0 ; i < _nc ; ++i ) + { + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_RAND ) ); + pd = &(*(--dirs.end())); + + d = NOMAD::RNG::rand()%2 ? -pow_gps : pow_gps; + (*pd )[i] = d; + (*pd1)[i] = -d; + } + } + + // GPS n+1, static, uniform angles: + // -------------------------------- + else if ( *it == NOMAD::GPS_NP1_STATIC_UNIFORM ) + { + + cst = pow_gps * sqrt(static_cast<double>(_nc)*(_nc+1))/_nc; + + // n first directions: + for ( j = _nc-1 ; j >= 0 ; --j ) + { + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); + pd = &(*(--dirs.end())); + + k = _nc-j-1; + + for ( i = 0 ; i < k ; ++i ) + (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); + + (*pd)[k] = (cst * (j+1)) / sqrt(static_cast<double>(j+1)*(j+2)); + + } + + // (n+1)^st direction: + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); + pd = &(*(--dirs.end())); + for ( i = 0 ; i < _nc ; ++i ) + (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); + + } + + // GPS n+1, random, uniform angles: + // -------------------------------- + // (we apply the procedure defined in + // "Pattern Search Methods for user-provided points: + // application to molecular geometry problems", + // by Alberto, Nogueira, Rocha and Vicente, + // SIOPT 14-4, 1216-1236, 2004, doi:10.1137/S1052623400377955) + else if ( *it == NOMAD::GPS_NP1_RAND_UNIFORM ) + { + + cst = pow_gps * sqrt(static_cast<double>(_nc)*(_nc+1))/_nc; + + // n first directions: + for ( j = _nc-1 ; j >= 0 ; --j ) + { + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); + pd = &(*(--dirs.end())); + + k = _nc-j-1; + + for ( i = 0 ; i < k ; ++i ) + (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); + + (*pd)[k] = (cst * (j+1)) / sqrt(static_cast<double>(j+1)*(j+2)); + + } + + // (n+1)^st direction: + dirs.push_back ( NOMAD::Direction ( _nc , 0.0 , NOMAD::GPS_NP1_STATIC_UNIFORM ) ); + pd = &(*(--dirs.end())); + for ( i = 0 ; i < _nc ; ++i ) + (*pd)[i] = -cst / sqrt(static_cast<double>(_nc-i)*(_nc-i+1)); + + // random perturbations: + NOMAD::Random_Pickup rp ( _nc ); + std::vector<bool> done ( _nc ); + bool chg_sgn; + std::list<NOMAD::Direction>::iterator it; + NOMAD::Double tmp; + + end2 = dirs.end(); + for ( i = 0 ; i < _nc ; ++i ) + done[i] = false; + + for ( i = 0 ; i < _nc ; ++i ) + { + k = rp.pickup(); + if ( i != k && !done[i] ) + { + chg_sgn = ( NOMAD::RNG::rand()%2 != 0 ); + + for ( it = dirs.begin() ; it != end2 ; ++it ) + { + tmp = (*it)[i]; + (*it)[i] = ( chg_sgn ? -1.0 : 1.0 ) * (*it)[k]; + (*it)[k] = tmp; + } + + done[i] = done[k] = true; + } + else + if ( NOMAD::RNG::rand()%2 ) + for ( it = dirs.begin() ; it != end2 ; ++it ) + (*it)[i] = -(*it)[i]; + } + } + } + } // end of loop on the types of directions + + // The direction are unscaled on a unit n-sphere when necessary (that is directions that are not orthomads) + for ( it2 = dirs.begin() ; it2 != dirs.end() ; ++it2 ) + if ( ! NOMAD::dir_is_orthomads ( it2->get_type() ) ) + { + NOMAD::Double norm_dir=it2->norm(); + for (int i=0 ; i < _nc ; ++i ) + (*it2)[i] /= norm_dir; + } + } - - -/*---------------------------------------------------------*/ -/* compute the Halton direction q(t,l) (private) */ -/*---------------------------------------------------------*/ -bool NOMAD::Directions::compute_halton_dir ( int halton_index , - int mesh_index , - NOMAD::Double & alpha_t_l , - NOMAD::Direction & halton_dir ) const +/*-----------------------------------------------------------------------------*/ +/* compute a random direction on a unit N-Sphere */ +/* see http://en.wikipedia.org/wiki/N-sphere */ +/*-----------------------------------------------------------------------------*/ +bool NOMAD::Directions::compute_dir_on_unit_sphere ( NOMAD::Direction & random_dir ) const { - alpha_t_l.clear(); - - int i; - NOMAD::Double d , norm = 0.0; - NOMAD::Point b ( _nc ); - - for ( i = 0 ; i < _nc ; ++i ) { - d = Directions::get_phi ( halton_index , _primes[i] ); - b[i] = 2*d - 1.0; - norm += b[i].pow2(); - } - norm = norm.sqrt(); - - // desired squared norm for q: - - NOMAD::direction_type hdt = halton_dir.get_type(); - - NOMAD::Double target = ( hdt == NOMAD::ORTHO_2N || hdt == NOMAD::ORTHO_NP1_QUAD || hdt == NOMAD::ORTHO_NP1_NEG ) ? - pow ( NOMAD::Mesh::get_mesh_update_basis() , abs(mesh_index) / 2.0 ) : - pow ( NOMAD::Mesh::get_mesh_update_basis() , abs(mesh_index) ); - - - NOMAD::Double x = target.sqrt(); - NOMAD::Double fx = eval_ortho_norm ( x , norm , b , halton_dir ); - NOMAD::Double y = 1.0 , fy , delta_x , abs_dx , min , delta_min , diff , eps; - bool inc , possible , set_eps = false; - int cnt = 0; - - while ( fx != target ) - { - - // safety test: - if ( ++cnt > 1000 ) - { -#ifdef DEBUG - _out << std::endl << "Warning (" << "Directions.cpp" << ", " << __LINE__ - << "): could not compute Halton direction for (t=" - << halton_index << ", ell=" << mesh_index - << ")" << std::endl << std::endl; -#endif - alpha_t_l.clear(); - halton_dir.clear(); - return false; - } - - if ( set_eps ) - { - eps = 1e-8; - set_eps = false; - } - else - eps = 0.0; - - inc = ( fx < target ); - - possible = false; - min = 1e+20; - for ( i = 0 ; i < _nc ; ++i ) - { - if ( b[i] != 0.0 ) - { - if ( b[i] > 0.0 ) - { - if ( inc ) - diff = 0.5+eps; - else - diff = -0.5-eps; - } - else - { - if ( inc ) - diff = -0.5-eps; - else - diff = 0.5+eps; - } - - delta_x = norm * ( halton_dir[i] + diff) / b[i] - x; - - y = x + delta_x; - - if ( y > 0 ) - { - abs_dx = delta_x.abs(); - if ( abs_dx < min ) - { - min = abs_dx; - delta_min = delta_x; - possible = true; - } - } - } - } - - if ( !possible ) { -#ifdef DEBUG - _out << std::endl << "Warning (" << "Directions.cpp" << ", " << __LINE__ - << "): could not compute Halton direction for (t=" - << halton_index << ", ell=" << mesh_index << ")" - << std::endl << std::endl; -#endif - alpha_t_l.clear(); - halton_dir.clear(); - return false; - } - - y = x + delta_min; - fy = eval_ortho_norm ( y , norm , b , halton_dir ); - - if ( fx == fy ) { - set_eps = true; - continue; - } - - if ( fy==target ) - break; - - if ( inc && fy > target && fx > 0 ) { - eval_ortho_norm ( x , norm , b , halton_dir ); - break; - } - - if ( !inc && fy < target && fy > 0 ) - break; - - x = y; - fx = fy; - } - - alpha_t_l = y; - - return true; + + int i; + NOMAD::Double norm,d; + + for ( i = 0 ; i < _nc ; ++i ) + random_dir[i]=NOMAD::RNG::normal_rand(0,1); + + norm=random_dir.norm(); + + if ( norm==0 ) + return false; + + + for ( i = 0 ; i < _nc ; ++i ) + random_dir[i]/=norm; + + return true; + } + /*-----------------------------------------------------------------*/ /* compute the squared norm of normalized(2u_t-e) for Ortho-MADS */ /* (private) */ /*-----------------------------------------------------------------*/ NOMAD::Double NOMAD::Directions::eval_ortho_norm ( const NOMAD::Double & x , - const NOMAD::Double & norm , - const NOMAD::Point & b , - NOMAD::Point & new_b ) const + const NOMAD::Double & norm , + const NOMAD::Point & b , + NOMAD::Point & new_b ) const { - NOMAD::Double fx = 0.0; - - for ( int i = 0 ; i < _nc ; ++i ) { - new_b[i] = ( x * b[i] / norm ).round(); - fx += new_b[i]*new_b[i]; - } - - return fx; + NOMAD::Double fx = 0.0; + + for ( int i = 0 ; i < _nc ; ++i ) { + new_b[i] = ( x * b[i] / norm ).round(); + fx += new_b[i]*new_b[i]; + } + + return fx; } /*--------------------------------------------------------*/ @@ -861,66 +674,70 @@ NOMAD::Double NOMAD::Directions::eval_ortho_norm ( const NOMAD::Double & x /*--------------------------------------------------------*/ NOMAD::Double NOMAD::Directions::get_phi ( int t , int p ) { - int div; - int size = int ( ceil ( log(static_cast<double>(t+1)) / - log(static_cast<double>(p)) ) ); - int ll = t; - NOMAD::Double d = 0.0; - - for ( int i = 0 ; i < size ; ++i ) { - div = NOMAD::Double ( pow ( p , size-i-1.0 ) ).round(); - d += ( ll / div ) * pow ( static_cast<double>(p) , i-size ); - ll = ll % div; - } - return d; + int div; + int size = int ( ceil ( log(static_cast<double>(t+1)) / + log(static_cast<double>(p)) ) ); + int ll = t; + NOMAD::Double d = 0.0; + + for ( int i = 0 ; i < size ; ++i ) { + div = NOMAD::Double ( pow ( p , size-i-1.0 ) ).round(); + d += ( ll / div ) * pow ( static_cast<double>(p) , i-size ); + ll = ll % div; + } + return d; } /*----------------------------------------------------------------*/ /* . Householder transformation to generate _nc directions from */ -/* the Halton direction */ +/* a given direction */ /* . compute also H[i+nc] = -H[i] (completion to 2n directions) */ /* . private method */ /*----------------------------------------------------------------*/ -void NOMAD::Directions::householder ( const NOMAD::Direction & halton_dir , - bool complete_to_2n , - NOMAD::Direction ** H ) const +void NOMAD::Directions::householder ( const NOMAD::Direction & dir , + bool complete_to_2n , + NOMAD::Direction ** H ) const { - int i , j; - - NOMAD::Double norm2 = halton_dir.squared_norm() , v , h2i; - - for ( i = 0 ; i < _nc ; ++i ) { + int i , j; - h2i = 2 * halton_dir[i]; - - for ( j = 0 ; j < _nc ; ++j ) { - - // H[i]: - (*H[i])[j] = v = (i==j) ? norm2 - h2i * halton_dir[j] : - h2i * halton_dir[j]; - - // -H[i]: - if ( complete_to_2n ) - (*H[i+_nc])[j] = -v; + NOMAD::Double norm2 = dir.squared_norm() , v , h2i; + + for ( i = 0 ; i < _nc ; ++i ) { + + h2i = 2 * dir[i]; + + for ( j = 0 ; j < _nc ; ++j ) { + + // H[i]: + (*H[i])[j] = v = (i==j) ? norm2 - h2i * dir[j] : - h2i * dir[j]; + + // -H[i]: + if ( complete_to_2n ) + (*H[i+_nc])[j] = -v; + } } - } } /*---------------------------------------------------------*/ /* get the LT-MADS b(l) direction (private) */ /*---------------------------------------------------------*/ -const NOMAD::Direction * NOMAD::Directions::get_bl ( int mesh_index , - NOMAD::direction_type dtype , - int & hat_i ) +const NOMAD::Direction * NOMAD::Directions::get_bl ( const NOMAD::OrthogonalMesh & mesh, + NOMAD::direction_type dtype , + int & hat_i ) { - NOMAD::Direction * bl = _bl [ mesh_index + NOMAD::L_LIMITS ]; - hat_i = _hat_i [ mesh_index + NOMAD::L_LIMITS ]; - - if ( !bl ) { - hat_i = -1; - create_lt_direction ( mesh_index , dtype , -1 , hat_i , bl ); - } - - return bl; + + NOMAD::Point mesh_indices = mesh.get_mesh_indices(); + int mesh_index =static_cast<int>(mesh_indices[0].value()); + NOMAD::Direction * bl = _bl [ mesh_index + NOMAD::L_LIMITS ]; + hat_i = _hat_i [ mesh_index + NOMAD::L_LIMITS ]; + + if ( !bl ) + { + hat_i = -1; + create_lt_direction ( mesh , dtype , -1 , hat_i , bl ); + } + + return bl; } /*---------------------------------------------------------*/ @@ -929,40 +746,44 @@ const NOMAD::Direction * NOMAD::Directions::get_bl ( int mes /* (if hat_i == -1, a new b(l) direction */ /* is created and hat_i is set) */ /*---------------------------------------------------------*/ -void NOMAD::Directions::create_lt_direction ( int mesh_index , - NOMAD::direction_type dtype , - int diag_i , - int & hat_i , - NOMAD::Direction *& dir ) +void NOMAD::Directions::create_lt_direction ( const NOMAD::OrthogonalMesh & mesh , + NOMAD::direction_type dtype , + int diag_i , + int & hat_i , + NOMAD::Direction *& dir ) { - int i_pow_tau = + + int mesh_index=static_cast<int>(mesh.get_mesh_indices()[0].value()); + int i_pow_tau = static_cast<int> - ( ceil ( pow ( NOMAD::Mesh::get_mesh_update_basis() , abs(mesh_index) / 2.0 ) ) ); - - int j = diag_i+1; - - // new b(l) direction: - if ( hat_i < 0 ) { - _hat_i [ mesh_index + NOMAD::L_LIMITS ] = diag_i = hat_i = NOMAD::RNG::rand()%_nc; - _bl [ mesh_index + NOMAD::L_LIMITS ] = dir - = new NOMAD::Direction ( _nc, 0.0, dtype ); - - j = 0; - } - - (*dir)[diag_i] = (NOMAD::RNG::rand()%2) ? -i_pow_tau : i_pow_tau; - - for ( int k = j ; k < _nc ; ++k ) - if ( k != hat_i ) { - (*dir)[k] = NOMAD::RNG::rand()%i_pow_tau; - if ( NOMAD::RNG::rand()%2 && (*dir)[k] > 0.0 ) - (*dir)[k] = -(*dir)[k]; + ( ceil ( pow ( mesh.get_update_basis() , abs(mesh_index) / 2.0 ) ) ); + + int j = diag_i+1; + + // new b(l) direction: + if ( hat_i < 0 ) + { + _hat_i [ mesh_index + NOMAD::L_LIMITS ] = diag_i = hat_i = NOMAD::RNG::rand()%_nc; + _bl [ mesh_index + NOMAD::L_LIMITS ] = dir + = new NOMAD::Direction ( _nc, 0.0, dtype ); + + j = 0; } - + + (*dir)[diag_i] = (NOMAD::RNG::rand()%2) ? -i_pow_tau : i_pow_tau; + + for ( int k = j ; k < _nc ; ++k ) + if ( k != hat_i ) + { + (*dir)[k] = NOMAD::RNG::rand()%i_pow_tau; + if ( NOMAD::RNG::rand()%2 && (*dir)[k] > 0.0 ) + (*dir)[k] = -(*dir)[k]; + } + #ifdef DEBUG - if ( j==0 ) - _out << "new LT-MADS b(l) direction: b(" << mesh_index << ") = " - << *dir << std::endl << std::endl; + if ( j==0 ) + _out << "new LT-MADS b(l) direction: b(" << mesh_index << ") = " + << *dir << std::endl << std::endl; #endif } @@ -970,11 +791,11 @@ void NOMAD::Directions::create_lt_direction ( int mesh_index , /* permute the coordinates of a direction (private) */ /*---------------------------------------------------------*/ void NOMAD::Directions::permute_coords ( NOMAD::Direction & dir , - const int * permutation_vector ) const + const int * permutation_vector ) const { - NOMAD::Point tmp = dir; - for ( int i = 0 ; i < _nc ; ++i ) - dir [ permutation_vector[i] ] = tmp[i]; + NOMAD::Point tmp = dir; + for ( int i = 0 ; i < _nc ; ++i ) + dir [ permutation_vector[i] ] = tmp[i]; } @@ -983,26 +804,21 @@ void NOMAD::Directions::permute_coords ( NOMAD::Direction & dir , /*---------------------------------------------------------*/ void NOMAD::Directions::display ( const NOMAD::Display & out ) const { - out << "n : " << _nc << std::endl - << "types : { "; - std::set<NOMAD::direction_type>::const_iterator it , end = _direction_types.end(); - for ( it = _direction_types.begin() ; it != end ; ++it ) - out << "[" << *it << "] "; - out << "}" << std::endl - << "sec poll types: { "; - end = _sec_poll_dir_types.end(); - for ( it = _sec_poll_dir_types.begin() ; it != end ; ++it ) - out << "[" << *it << "] "; - out << "}" << std::endl; - if ( _is_orthomads ) - { - out << "halton_seed : "; - if ( _halton_seed >= 0 ) - out << _halton_seed; - else - out << "auto"; - out << std::endl; - } + out << "n : " << _nc << std::endl + << "types : { "; + std::set<NOMAD::direction_type>::const_iterator it , end = _direction_types.end(); + for ( it = _direction_types.begin() ; it != end ; ++it ) + out << "[" << *it << "] "; + out << "}" << std::endl + << "sec poll types: { "; + end = _sec_poll_dir_types.end(); + for ( it = _sec_poll_dir_types.begin() ; it != end ; ++it ) + out << "[" << *it << "] "; + out << "}" << std::endl; + if ( _is_orthomads ) + { + out << "seed : " << NOMAD::RNG::get_seed() << endl; + } } /*---------------------------------------------------------*/ @@ -1010,66 +826,60 @@ void NOMAD::Directions::display ( const NOMAD::Display & out ) const /*---------------------------------------------------------*/ bool NOMAD::Directions::operator < ( const NOMAD::Directions & d ) const { - // number of variables: - if ( _nc < d._nc ) - return true; - if ( d._nc < _nc ) - return false; - - // Halton seed: - if ( _halton_seed < d._halton_seed ) - return true; - if ( d._halton_seed < _halton_seed ) - return false; - - // boolean variables: - if ( _is_binary != d._is_binary ) - return _is_binary; - if ( _is_categorical != d._is_categorical ) - return _is_categorical; - if ( _is_orthomads != d._is_orthomads ) - return _is_orthomads; - - // direction types: - size_t nd = _direction_types.size(); - if ( nd < d._direction_types.size() ) - return true; - if ( d._direction_types.size() < nd ) - return false; - - size_t ns = _sec_poll_dir_types.size(); - if ( ns < d._sec_poll_dir_types.size() ) - return true; - if ( d._sec_poll_dir_types.size() < ns ) - return false; - - std::set<NOMAD::direction_type>::const_iterator + // number of variables: + if ( _nc < d._nc ) + return true; + if ( d._nc < _nc ) + return false; + + // boolean variables: + if ( _is_binary != d._is_binary ) + return _is_binary; + if ( _is_categorical != d._is_categorical ) + return _is_categorical; + if ( _is_orthomads != d._is_orthomads ) + return _is_orthomads; + + // direction types: + size_t nd = _direction_types.size(); + if ( nd < d._direction_types.size() ) + return true; + if ( d._direction_types.size() < nd ) + return false; + + size_t ns = _sec_poll_dir_types.size(); + if ( ns < d._sec_poll_dir_types.size() ) + return true; + if ( d._sec_poll_dir_types.size() < ns ) + return false; + + std::set<NOMAD::direction_type>::const_iterator it1 = _direction_types.begin() , it2 = d._direction_types.begin() , end = _direction_types.end(); - - while ( it1 != end ) { - if ( *it1 < *it2 ) - return true; - if ( *it2 < *it1 ) - return false; - ++it1; - ++it2; - } - - it1 = _sec_poll_dir_types.begin(); - it2 = d._sec_poll_dir_types.begin(); - end = _sec_poll_dir_types.end(); - - while ( it1 != end ) { - if ( *it1 < *it2 ) - return true; - if ( *it2 < *it1 ) - return false; - ++it1; - ++it2; - } - - return false; + + while ( it1 != end ) { + if ( *it1 < *it2 ) + return true; + if ( *it2 < *it1 ) + return false; + ++it1; + ++it2; + } + + it1 = _sec_poll_dir_types.begin(); + it2 = d._sec_poll_dir_types.begin(); + end = _sec_poll_dir_types.end(); + + while ( it1 != end ) { + if ( *it1 < *it2 ) + return true; + if ( *it2 < *it1 ) + return false; + ++it1; + ++it2; + } + + return false; } diff --git a/src/Directions.hpp b/src/Directions.hpp index 690be65..a9d87c8 100644 --- a/src/Directions.hpp +++ b/src/Directions.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,322 +34,269 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Directions.hpp - \brief Set of polling directions (headers) - \author Sebastien Le Digabel - \date 2010-04-14 - \see Directions.cpp -*/ + \file Directions.hpp + \brief Set of polling directions (headers) + \author Sebastien Le Digabel + \date 2010-04-14 + \see Directions.cpp + */ #ifndef __DIRECTIONS__ #define __DIRECTIONS__ #include "Random_Pickup.hpp" #include "Direction.hpp" -#include "Mesh.hpp" -#include "RNG.hpp" +#include "OrthogonalMesh.hpp" +#include "RNG.hpp" namespace NOMAD { - - /// Set of polling directions. - class Directions { - - /*--------------------------------------------------------------*/ - private: - - int _nc; ///< Number of non-fixed variables. - - /// Types of the poll directions. - std::set<NOMAD::direction_type> _direction_types; - - /// Types of the secondary poll directions. - std::set<NOMAD::direction_type> _sec_poll_dir_types; - - bool _is_binary; ///< Flag equal to \c true if all variables are binary. - bool _is_categorical; ///< Flag equal to \c true if all variables are categorical. - - bool _is_orthomads; //< Flag equal to \c true if Ortho-MADS directions are used. - - // LT-MADS attributes: - NOMAD::Direction * _bl [1+2*NOMAD::L_LIMITS]; ///< Directions b(ell) (LT-MADS). - int _hat_i [1+2*NOMAD::L_LIMITS]; ///< b(ell) indexes (LT-MADS). - bool _lt_initialized; ///< Flag equal to \c true if LT-MADS has been initialized. - - // Ortho-MADS members: - int * _primes; ///< \c nc first prime numbers. - int _halton_seed; ///< Halton seed \c t_0. - - static int _max_halton_seed; ///< Max Halton seed for all NOMAD::Directions objects. - - const NOMAD::Display & _out; ///< Display. - - /*--------------------------------------------------------------*/ - - /// Affectation operator. - /** - \param d The right-hand side object -- \b IN. - */ - Directions & operator = ( const Directions & d ); - - /// Ortho-MADS initializations. - /** - \param halton_seed Halton seed -- \b IN. - */ - void ortho_mads_init ( int halton_seed ); - - /// LT-MADS initializations. - void lt_mads_init ( void ); - - /// Compute the squared norm of \c normalized(2u_t-e) for Ortho-MADS. - /** - \param x \b IN. - \param norm \b IN. - \param b \b IN. - \param new_b \b OUT. - \return The squared norm. - */ - NOMAD::Double eval_ortho_norm ( const NOMAD::Double & x , - const NOMAD::Double & norm , - const NOMAD::Point & b , - NOMAD::Point & new_b ) const; - - /// Householder transformation. - /** - - Generate \c _nc directions from the Halton direction. - - Computes also \c H[i+nc] \c = \c -H[i] (completion to 2n directions). - \param halton_dir The Halton direction -- \b IN. - \param complete_to_2n Complete or not to \c 2n directions -- \b IN. - \param H The \c _nc directions -- \b OUT. - */ - void householder ( const NOMAD::Direction & halton_dir , - bool complete_to_2n , - NOMAD::Direction ** H ) const; - - /// Get the expression of an integer \c t in inverse base \c p. - /** - \param t \b IN. - \param p \b IN. - \return The expression of \c t in inverse base \c p. - */ - static NOMAD::Double get_phi ( int t , int p ); - - /// Compute the Halton direction \c q(t,ell). - /** - \param halton_index Halton index \c t -- \b IN. - \param mesh_index Mesh index \c ell -- \b IN. - \param alpha_t_l Ortho-MADS \c alpha(t,ell) -- \b OUT. - \param halton_dir Halton direction -- \b OUT. - \return A boolean equal to \c true if the computation went well. - */ - bool compute_halton_dir ( int halton_index , - int mesh_index, - NOMAD::Double & alpha_t_l, - NOMAD::Direction & halton_dir ) const; - - /// Access to the LT-MADS \c b(ell) direction. - /** - \param mesh_index Mesh index \c ell -- \b IN. - \param dtype Direction type -- \b IN. - \param hat_i LT-MADS \c hat{i} index -- \b IN/OUT. - \return The LT-MADS \c b(ell) direction. - */ - const NOMAD::Direction * get_bl ( int mesh_index , - NOMAD::direction_type dtype , - int & hat_i ); - - /// Create a new LT-MADS direction. - /** - If \c hat_i \c == \c -1, a new \c b(ell) direction is created - and \c hat_i is set. - \param mesh_index Mesh index \c ell -- \b IN. - \param dtype Direction type -- \b IN. - \param diag_i Diagonal index -- \b IN. - \param hat_i LT-MADS \c hat{i} index -- \b IN/OUT. - \param dir LT-MADS \c b(ell) direction -- \b OUT. - */ - void create_lt_direction ( int mesh_index , - NOMAD::direction_type dtype , - int diag_i , - int & hat_i , - NOMAD::Direction *& dir ); - - /// Permute the coordinates of a direction. - /** - \param dir The direction -- \b IN/OUT. - \param permutation_vector Permutation vector -- \b IN. - */ - void permute_coords ( NOMAD::Direction & dir , - const int * permutation_vector ) const; - - /// Compute binary directions. - /** - Only if all groups of variables are binary. - \param dirs Set of directions -- \b OUT. - */ - void compute_binary_directions ( std::list<NOMAD::Direction> & dirs ) const; - - /*--------------------------------------------------------------*/ - - public: - - /// Constructor. - /** - The Halton seed will be automatically computed later - if NOMAD::Parameters::_halton_seed==-1. - \param nc Number of non-fixed variables -- \b IN. - \param direction_types Types of the poll directions -- \b IN. - \param sec_poll_dir_types Types of the secondary poll directions -- \b IN. - \param halton_seed Halton seed \c t_0 -- \b IN. - \param out The display -- \b IN. - */ - Directions ( int nc , - const std::set<NOMAD::direction_type> & direction_types , - const std::set<NOMAD::direction_type> & sec_poll_dir_types , - int halton_seed , - const NOMAD::Display & out ); - - /// Copy constructor. - /** - \param d The copied object -- \b IN. - */ - Directions ( const Directions & d ) - : _nc ( d._nc ) , - _direction_types ( d._direction_types ) , - _sec_poll_dir_types ( d._sec_poll_dir_types ) , - _is_binary ( d._is_binary ) , - _is_categorical ( d._is_categorical ) , - _is_orthomads ( d._is_orthomads ) , - _lt_initialized ( false ) , - _primes ( NULL ) , - _halton_seed ( d._halton_seed ) , - _out ( d._out ) {} - /// Destructor. - virtual ~Directions ( void ); + /// Set of polling directions. + class Directions { + + /*--------------------------------------------------------------*/ + private: + + int _nc; ///< Number of non-fixed variables. + + /// Types of the poll directions. + std::set<NOMAD::direction_type> _direction_types; + + /// Types of the secondary poll directions. + std::set<NOMAD::direction_type> _sec_poll_dir_types; + + bool _is_binary; ///< Flag equal to \c true if all variables are binary. + bool _is_categorical; ///< Flag equal to \c true if all variables are categorical. + + bool _is_orthomads; //< Flag equal to \c true if Ortho-MADS directions are used. + + // LT-MADS attributes: + NOMAD::Direction * _bl [1+2*NOMAD::L_LIMITS]; ///< Directions b(ell) (LT-MADS). + int _hat_i [1+2*NOMAD::L_LIMITS]; ///< b(ell) indexes (LT-MADS). + bool _lt_initialized; ///< Flag equal to \c true if LT-MADS has been initialized. + + const NOMAD::Display & _out; ///< Display. + + /*--------------------------------------------------------------*/ + + /// Affectation operator. + /** + \param d The right-hand side object -- \b IN. + */ + Directions & operator = ( const Directions & d ); + + /// LT-MADS initializations. + void lt_mads_init ( void ); + + /// Compute the squared norm of \c normalized(2u_t-e) for Ortho-MADS. + /** + \param x \b IN. + \param norm \b IN. + \param b \b IN. + \param new_b \b OUT. + \return The squared norm. + */ + NOMAD::Double eval_ortho_norm ( const NOMAD::Double & x , + const NOMAD::Double & norm , + const NOMAD::Point & b , + NOMAD::Point & new_b ) const; + + /// Householder transformation. + /** + - Generate \c _nc directions. + - Computes also \c H[i+nc] \c = \c -H[i] (completion to 2n directions). + \param dir The given direction -- \b IN. + \param complete_to_2n Complete or not to \c 2n directions -- \b IN. + \param H The \c _nc directions -- \b OUT. + */ + void householder ( const NOMAD::Direction & dir , + bool complete_to_2n , + NOMAD::Direction ** H ) const; + + /// Get the expression of an integer \c t in inverse base \c p. + /** + \param t \b IN. + \param p \b IN. + \return The expression of \c t in inverse base \c p. + */ + static NOMAD::Double get_phi ( int t , int p ); + + + /// Access to the LT-MADS \c b(ell) direction. + /** + \param mesh the currenet OrthogonalMesh \c ell -- \b IN. + \param dtype Direction type -- \b IN. + \param hat_i LT-MADS \c hat{i} index -- \b IN/OUT. + \return The LT-MADS \c b(ell) direction. + */ + const NOMAD::Direction * get_bl ( const NOMAD::OrthogonalMesh & mesh , + NOMAD::direction_type dtype , + int & hat_i ); + + /// Create a new LT-MADS direction. + /** + If \c hat_i \c == \c -1, a new \c b(ell) direction is created + and \c hat_i is set. + \param mesh the current OrthogonalMesh index \c ell -- \b IN. + \param dtype Direction type -- \b IN. + \param diag_i Diagonal index -- \b IN. + \param hat_i LT-MADS \c hat{i} index -- \b IN/OUT. + \param dir LT-MADS \c b(ell) direction -- \b OUT. + */ + void create_lt_direction ( const NOMAD::OrthogonalMesh & mesh , + NOMAD::direction_type dtype , + int diag_i , + int & hat_i , + NOMAD::Direction *& dir ); + + /// Permute the coordinates of a direction. + /** + \param dir The direction -- \b IN/OUT. + \param permutation_vector Permutation vector -- \b IN. + */ + void permute_coords ( NOMAD::Direction & dir , + const int * permutation_vector ) const; + + /// Compute binary directions. + /** + Only if all groups of variables are binary. + \param dirs Set of directions -- \b OUT. + */ + void compute_binary_directions ( std::list<NOMAD::Direction> & dirs ) const; + + /*--------------------------------------------------------------*/ + + public: + + /// Constructor. + /** + \param nc Number of non-fixed variables -- \b IN. + \param direction_types Types of the poll directions -- \b IN. + \param sec_poll_dir_types Types of the secondary poll directions -- \b IN. + \param out The display -- \b IN. + */ + Directions ( int nc , + const std::set<NOMAD::direction_type> & direction_types , + const std::set<NOMAD::direction_type> & sec_poll_dir_types , + const NOMAD::Display & out ); + + /// Copy constructor. + /** + \param d The copied object -- \b IN. + */ + Directions ( const Directions & d ) + : _nc ( d._nc ) , + _direction_types ( d._direction_types ) , + _sec_poll_dir_types ( d._sec_poll_dir_types ) , + _is_binary ( d._is_binary ) , + _is_categorical ( d._is_categorical ) , + _is_orthomads ( d._is_orthomads ) , + _lt_initialized ( false ) , + _out ( d._out ) {} + + /// Destructor. + virtual ~Directions ( void ); + + /// Compute the directions for a given mesh. + /** + \param mesh The given mesh -- \b IN. + \param dirs Set of directions -- \b OUT. + \param poll Type of poll (primary or secondary) -- \b IN. + */ + void compute ( std::list<NOMAD::Direction> & dirs , + NOMAD::poll_type poll , + const NOMAD::OrthogonalMesh & mesh ); + + /// Compute a random direction on a N-Sphere. + /** + \param random_dir -- \b OUT. + \return A boolean equal to \c true if the computation went well. + */ + bool compute_dir_on_unit_sphere ( NOMAD::Direction & random_dir ) const; + + + /// Check if Ortho-MADS directions are used. + /** + \return A boolean equal to \c true if Ortho-MADS directions are used. + */ + bool is_orthomads ( void ) const + { + return _is_orthomads; + } + + /// Check if all variables are categorical. + /** + \return A boolean equal to \c true if all variables are categorical. + */ + bool is_categorical ( void ) const + { + return _is_categorical; + } + + /// Access to the poll direction types. + /** + \return Poll direction types. + */ + const std::set<NOMAD::direction_type> & get_direction_types ( void ) const + { + return _direction_types; + } + + /// Access to the secondary poll direction types. + /** + \return Secondary poll direction types. + */ + const std::set<NOMAD::direction_type> & get_sec_poll_dir_types ( void ) const + { + return _sec_poll_dir_types; + } + + /// Reset directions for binary variables. + void set_binary ( void ); + + /// Reset directions for categorical variables. + void set_categorical ( void ); + + /// Comparison operator. + /** + \param d The right-hand side object -- \b IN. + \return A boolean equal to \c true if \c *this \c < \c d . + */ + bool operator < ( const Directions & d ) const; + + /// Access to the NOMAD::Display member \c _out. + /** + \return The NOMAD::Display member \c _out. + */ + const NOMAD::Display & out ( void ) const { return _out; } + + /// Display. + /** + \param out The NOMAD::Display object -- \b IN. + */ + void display ( const NOMAD::Display & out ) const; + + /// Display. + /** + Uses the \c this->_out member as NOMAD::Display object. + */ + void display ( void ) const + { + display ( _out ); + } + }; - /// Compute the directions for a given mesh. - /** - \param dirs Set of directions -- \b OUT. - \param poll Type of poll (primary or secondary) -- \b IN. - \param poll_center Poll center -- \b IN. - \param mesh_index Mesh index \c ell -- \b IN. - \param halton_index Halton index \c t (set to \c -1 for a default value) -- \b IN. - \param feas_success_dir Feasible success direction -- \b IN. - \param infeas_success_dir Infeasible success direction -- \b IN. - */ - void compute ( std::list<NOMAD::Direction> & dirs , - NOMAD::poll_type poll , - const NOMAD::Point & poll_center , - int mesh_index , - int halton_index , - const NOMAD::Direction & feas_success_dir , - const NOMAD::Direction & infeas_success_dir ); - - - /// Compute just one direction for a given mesh and provided evaluated pts (used by VNS search and ortho_np1dyn). - /** - \param dir One direction -- \b OUT. - \param mesh_index Mesh index \c ell -- \b IN. - \param halton_index Halton index \c t (must be \c >0) -- \b IN. - \return A boolean equal to \c true if the computation went well. - */ - bool compute_one_direction ( NOMAD::Direction & dir, - int mesh_index, - int halton_index ); - - /// Method for computing a Halton seed. - /** - The Halton seed for \c n variables is computed as the \c n th prime number. - \param n Number of variables -- \b IN. - \return The Halton seed \c t_0. - */ - static int compute_halton_seed ( int n ); - - /// Access to the max value of the Halton index \c t. - /** - \return The max value of the Halton index \c t. - */ - static int get_max_halton_seed ( void ) { return Directions::_max_halton_seed; } - - /// Access to the Halton seed \c t_0. - /** - \return The Halton seed \c t_0. - */ - int get_halton_seed ( void ) const { return _halton_seed; } - - /// Check if Ortho-MADS directions are used. - /** - \return A boolean equal to \c true if Ortho-MADS directions are used. - */ - bool is_orthomads ( void ) const { return _is_orthomads; } - - /// Check if all variables are categorical. - /** - \return A boolean equal to \c true if all variables are categorical. - */ - bool is_categorical ( void ) const { return _is_categorical; } - - /// Access to the poll direction types. + /// Display a NOMAD::Directions object. /** - \return Poll direction types. - */ - const std::set<NOMAD::direction_type> & get_direction_types ( void ) const - { - return _direction_types; - } - - /// Access to the secondary poll direction types. - /** - \return Secondary poll direction types. - */ - const std::set<NOMAD::direction_type> & get_sec_poll_dir_types ( void ) const - { - return _sec_poll_dir_types; - } - - /// Reset directions for binary variables. - void set_binary ( void ); - - /// Reset directions for categorical variables. - void set_categorical ( void ); - - /// Comparison operator. - /** - \param d The right-hand side object -- \b IN. - \return A boolean equal to \c true if \c *this \c < \c d . - */ - bool operator < ( const Directions & d ) const; - - /// Access to the NOMAD::Display member \c _out. - /** - \return The NOMAD::Display member \c _out. - */ - const NOMAD::Display & out ( void ) const { return _out; } - - /// Display. - /** - \param out The NOMAD::Display object -- \b IN. - */ - void display ( const NOMAD::Display & out ) const; - - /// Display. - /** - Uses the \c this->_out member as NOMAD::Display object. - */ - void display ( void ) const { display ( _out ); } - }; - - /// Display a NOMAD::Directions object. - /** \param out The NOMAD::Display object -- \b IN. \param d The NOMAD::Directions object to be displayed -- \b IN. \return The NOMAD::Display object. - */ - inline const NOMAD::Display & operator << ( const NOMAD::Display & out , - const NOMAD::Directions & d ) - { - d.display ( out ); - return out; - } + */ + inline const NOMAD::Display & operator << ( const NOMAD::Display & out , + const NOMAD::Directions & d ) + { + d.display ( out ); + return out; + } } #endif diff --git a/src/Display.cpp b/src/Display.cpp index 215f4f6..e8b340f 100644 --- a/src/Display.cpp +++ b/src/Display.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Display.cpp - \brief Custom class for display (implementation) - \author Sebastien Le Digabel - \date 2010-03-30 - \see Display.hpp -*/ + \file Display.cpp + \brief Custom class for display (implementation) + \author Sebastien Le Digabel + \date 2010-03-30 + \see Display.hpp + */ #include "Display.hpp" /*---------------------------------------------------------*/ @@ -47,17 +47,17 @@ /*---------------------------------------------------------*/ void NOMAD::Display::open_block ( const std::string & msg ) const { - // open braces: - if ( _newline ) - _out << _indent_str; - if ( !msg.empty() ) - _out << msg << " "; - _out << _open_brace << std::endl; - - _newline = true; - - // add a tabulation to the indentation string: - _indent_str += '\t'; + // open braces: + if ( _newline ) + _out << _indent_str; + if ( !msg.empty() ) + _out << msg << " "; + _out << _open_brace << std::endl; + + _newline = true; + + // add a tabulation to the indentation string: + _indent_str += '\t'; } /*---------------------------------------------------------*/ @@ -65,54 +65,55 @@ void NOMAD::Display::open_block ( const std::string & msg ) const /*---------------------------------------------------------*/ void NOMAD::Display::close_block ( const std::string & msg ) const { - _newline = true; - - if ( _indent_str.empty() ) - return; - - // remove a tabulation to the indentation string: - _indent_str.erase ( 0 , 1 ); - - // close braces: - _out << _indent_str << _closed_brace << " " << msg << std::endl; + _newline = true; + + if ( _indent_str.empty() ) + return; + + // remove a tabulation to the indentation string: + _indent_str.erase ( 0 , 1 ); + + // close braces: + _out << _indent_str << _closed_brace << " " << msg << std::endl; } /*---------------------------------------------------------*/ /* set the display degrees */ /*---------------------------------------------------------*/ void NOMAD::Display::set_degrees ( NOMAD::dd_type gen_dd , - NOMAD::dd_type search_dd , - NOMAD::dd_type poll_dd , - NOMAD::dd_type iter_dd ) + NOMAD::dd_type search_dd , + NOMAD::dd_type poll_dd , + NOMAD::dd_type iter_dd ) { - // max = max { gen_dd , search_dd , poll_dd , iter_dd } : - NOMAD::dd_type max = gen_dd; - if ( search_dd > gen_dd ) - max = search_dd; - if ( poll_dd > max ) - max = poll_dd; - if ( iter_dd > max ) - max = iter_dd; - - // max=0: all to 0: - if ( max == NOMAD::NO_DISPLAY ) - _gen_dd = _search_dd = _poll_dd = _iter_dd = NOMAD::NO_DISPLAY; - - // max=1: all to 1: - else if ( max == NOMAD::MINIMAL_DISPLAY ) - _gen_dd = _search_dd = _poll_dd = _iter_dd = NOMAD::MINIMAL_DISPLAY; - - // max=2: all to 2: - else if ( max == NOMAD::NORMAL_DISPLAY ) - _gen_dd = _search_dd = _poll_dd = _iter_dd = NOMAD::NORMAL_DISPLAY; - - // max=3: 0-->0, 1-->0, 2->0 and 3-->3: - else { - _gen_dd = (gen_dd ==NOMAD::FULL_DISPLAY)? NOMAD::FULL_DISPLAY:NOMAD::NO_DISPLAY; - _search_dd = (search_dd==NOMAD::FULL_DISPLAY)? NOMAD::FULL_DISPLAY:NOMAD::NO_DISPLAY; - _poll_dd = (poll_dd ==NOMAD::FULL_DISPLAY)? NOMAD::FULL_DISPLAY:NOMAD::NO_DISPLAY; - _iter_dd = (iter_dd ==NOMAD::FULL_DISPLAY)? NOMAD::FULL_DISPLAY:NOMAD::NO_DISPLAY; - } + // max = max { gen_dd , search_dd , poll_dd , iter_dd } : + NOMAD::dd_type max = gen_dd; + if ( search_dd > gen_dd ) + max = search_dd; + if ( poll_dd > max ) + max = poll_dd; + if ( iter_dd > max ) + max = iter_dd; + + // max=0: all to 0: + if ( max == NOMAD::NO_DISPLAY ) + _gen_dd = _search_dd = _poll_dd = _iter_dd = NOMAD::NO_DISPLAY; + + // max=1: all to 1: + else if ( max == NOMAD::MINIMAL_DISPLAY ) + _gen_dd = _search_dd = _poll_dd = _iter_dd = NOMAD::MINIMAL_DISPLAY; + + // max=2: all to 2: + else if ( max == NOMAD::NORMAL_DISPLAY ) + _gen_dd = _search_dd = _poll_dd = _iter_dd = NOMAD::NORMAL_DISPLAY; + + // max=3: 0-->0, 1-->0, 2->0 and 3-->3: + else + { + _gen_dd = (gen_dd ==NOMAD::FULL_DISPLAY)? NOMAD::FULL_DISPLAY:NOMAD::NO_DISPLAY; + _search_dd = (search_dd==NOMAD::FULL_DISPLAY)? NOMAD::FULL_DISPLAY:NOMAD::NO_DISPLAY; + _poll_dd = (poll_dd ==NOMAD::FULL_DISPLAY)? NOMAD::FULL_DISPLAY:NOMAD::NO_DISPLAY; + _iter_dd = (iter_dd ==NOMAD::FULL_DISPLAY)? NOMAD::FULL_DISPLAY:NOMAD::NO_DISPLAY; + } } /*---------------------------------------------------*/ @@ -120,11 +121,11 @@ void NOMAD::Display::set_degrees ( NOMAD::dd_type gen_dd , /*---------------------------------------------------*/ void NOMAD::Display::get_display_degree ( std::string & dd ) const { - dd.resize ( 4 ); - dd[0] = NOMAD::Display::dd_to_char ( _gen_dd ); - dd[1] = NOMAD::Display::dd_to_char ( _search_dd ); - dd[2] = NOMAD::Display::dd_to_char ( _poll_dd ); - dd[3] = NOMAD::Display::dd_to_char ( _iter_dd ); + dd.resize ( 4 ); + dd[0] = NOMAD::Display::dd_to_char ( _gen_dd ); + dd[1] = NOMAD::Display::dd_to_char ( _search_dd ); + dd[2] = NOMAD::Display::dd_to_char ( _poll_dd ); + dd[3] = NOMAD::Display::dd_to_char ( _iter_dd ); } /*---------------------------------------------*/ @@ -132,11 +133,11 @@ void NOMAD::Display::get_display_degree ( std::string & dd ) const /*---------------------------------------------*/ NOMAD::dd_type NOMAD::Display::get_display_degree ( NOMAD::search_type search ) const { - if ( search == NOMAD::X0_EVAL ) - return _gen_dd; - if ( search == NOMAD::POLL || search == NOMAD::EXTENDED_POLL ) - return _poll_dd; - return _search_dd; + if ( search == NOMAD::X0_EVAL ) + return _gen_dd; + if ( search == NOMAD::POLL || search == NOMAD::EXTENDED_POLL ) + return _poll_dd; + return _search_dd; } /*------------------------------------------*/ @@ -144,13 +145,13 @@ NOMAD::dd_type NOMAD::Display::get_display_degree ( NOMAD::search_type search ) /*------------------------------------------*/ char NOMAD::Display::dd_to_char ( NOMAD::dd_type dd ) { - if ( dd == NOMAD::NO_DISPLAY ) - return '0'; - if ( dd == NOMAD::MINIMAL_DISPLAY) - return '1'; - if ( dd == NOMAD::NORMAL_DISPLAY ) - return '2'; - return '3'; + if ( dd == NOMAD::NO_DISPLAY ) + return '0'; + if ( dd == NOMAD::MINIMAL_DISPLAY) + return '1'; + if ( dd == NOMAD::NORMAL_DISPLAY ) + return '2'; + return '3'; } /*------------------------------------------*/ @@ -158,13 +159,13 @@ char NOMAD::Display::dd_to_char ( NOMAD::dd_type dd ) /*------------------------------------------*/ int NOMAD::Display::dd_to_int ( NOMAD::dd_type dd ) { - if ( dd == NOMAD::NO_DISPLAY ) - return 0; - if ( dd == NOMAD::MINIMAL_DISPLAY ) - return 1; - if ( dd == NOMAD::NORMAL_DISPLAY ) - return 2; - return 3; + if ( dd == NOMAD::NO_DISPLAY ) + return 0; + if ( dd == NOMAD::MINIMAL_DISPLAY ) + return 1; + if ( dd == NOMAD::NORMAL_DISPLAY ) + return 2; + return 3; } /*------------------------------------------*/ @@ -172,14 +173,14 @@ int NOMAD::Display::dd_to_int ( NOMAD::dd_type dd ) /*------------------------------------------*/ NOMAD::dd_type NOMAD::Display::int_to_dd ( int dd ) { - if ( dd <= 0 ) - return NOMAD::NO_DISPLAY; - if ( dd == 1 ) - return NOMAD::MINIMAL_DISPLAY; - if ( dd == 2 ) - return NOMAD::NORMAL_DISPLAY; - - return NOMAD::FULL_DISPLAY; + if ( dd <= 0 ) + return NOMAD::NO_DISPLAY; + if ( dd == 1 ) + return NOMAD::MINIMAL_DISPLAY; + if ( dd == 2 ) + return NOMAD::NORMAL_DISPLAY; + + return NOMAD::FULL_DISPLAY; } /*---------------------------------------------------------*/ @@ -187,9 +188,9 @@ NOMAD::dd_type NOMAD::Display::int_to_dd ( int dd ) /*---------------------------------------------------------*/ void NOMAD::Display::display_int_w ( int i , int max_i ) const { - (*this) << std::setw ( (max_i > 0) ? - (1+int(log(static_cast<double>(max_i))/NOMAD::LOG10)) : 1 ) - << i; + (*this) << std::setw ( (max_i > 0) ? + (1+int(log(static_cast<double>(max_i))/NOMAD::LOG10)) : 1 ) + << i; } /*--------------------------------------------------------*/ @@ -199,22 +200,25 @@ void NOMAD::Display::display_int_w ( int i , int max_i ) const /*--------------------------------------------------------*/ void NOMAD::Display::extract_display_format ( std::string & s , std::string & format ) { - format.clear(); - if ( s.empty() ) - return; - size_t k = s.find("%"); - size_t n = s.size(); - if ( k < n ) { - if ( k > 0 && s[k-1]=='\\' ) { - std::string s1 = s.substr ( 0 , k-1 ); - std::string s2 = s.substr ( k , n-k ); - s = s1 + s2; - } - else { - format = s.substr ( k , n-k ); - s = s.substr ( 0 , k ); + format.clear(); + if ( s.empty() ) + return; + size_t k = s.find("%"); + size_t n = s.size(); + if ( k < n ) + { + if ( k > 0 && s[k-1]=='\\' ) + { + std::string s1 = s.substr ( 0 , k-1 ); + std::string s2 = s.substr ( k , n-k ); + s = s1 + s2; + } + else + { + format = s.substr ( k , n-k ); + s = s.substr ( 0 , k ); + } } - } } /*---------------------------------------------------------*/ @@ -223,19 +227,20 @@ void NOMAD::Display::extract_display_format ( std::string & s , std::string & fo /*---------------------------------------------------------*/ void NOMAD::Display::display_time ( int t ) const { - if ( t > 0 ) { - int h = t / 3600; - t = t % 3600; - int m = t / 60; - t = t % 60; - if ( h > 0 ) - (*this) << h << "h "; - if ( m > 0 || h > 0) - (*this) << m << "m "; - } - else - t = 0; - (*this) << t << "s"; + if ( t > 0 ) + { + int h = t / 3600; + t = t % 3600; + int m = t / 60; + t = t % 60; + if ( h > 0 ) + (*this) << h << "h "; + if ( m > 0 || h > 0) + (*this) << m << "m "; + } + else + t = 0; + (*this) << t << "s"; } /*-----------------------------------------------------------------*/ @@ -243,14 +248,14 @@ void NOMAD::Display::display_time ( int t ) const /*-----------------------------------------------------------------*/ void NOMAD::Display::display_size_of ( float size ) const { - if ( size < 1024 ) - (*this) << static_cast<int>(size) << " B"; - else if ( size < 1048576 ) - (*this) << static_cast<int> ( 10 * size / 1024.0 ) / 10.0 << " KB"; - else if ( size < 1073741824 ) - (*this) << static_cast<int> ( 10 * size / 1048576.0 ) / 10.0 << " MB"; - else - (*this) << static_cast<int> ( 10 * size / 1073741824.0 ) / 10.0 << " GB"; + if ( size < 1024 ) + (*this) << static_cast<int>(size) << " B"; + else if ( size < 1048576 ) + (*this) << static_cast<int> ( 10 * size / 1024.0 ) / 10.0 << " KB"; + else if ( size < 1073741824 ) + (*this) << static_cast<int> ( 10 * size / 1048576.0 ) / 10.0 << " MB"; + else + (*this) << static_cast<int> ( 10 * size / 1073741824.0 ) / 10.0 << " GB"; } /*-------------------------------------------------------------------*/ @@ -259,19 +264,20 @@ void NOMAD::Display::display_size_of ( float size ) const NOMAD::display_stats_type NOMAD::Display::get_display_stats_type ( const std::string & s ) { - int idst; - std::string ss = s , keyword; - NOMAD::toupper ( ss ); - NOMAD::display_stats_type dst = NOMAD::DS_OBJ; - while ( dst < NOMAD::DS_UNDEFINED ) { - keyword = get_display_stats_keyword ( dst ); - if ( keyword == ss ) - return dst; - idst = dst; - ++idst; - dst = static_cast<display_stats_type> ( idst ); - } - return NOMAD::DS_UNDEFINED; + int idst; + std::string ss = s , keyword; + NOMAD::toupper ( ss ); + NOMAD::display_stats_type dst = NOMAD::DS_OBJ; + while ( dst < NOMAD::DS_UNDEFINED ) + { + keyword = get_display_stats_keyword ( dst ); + if ( keyword == ss ) + return dst; + idst = dst; + ++idst; + dst = static_cast<display_stats_type> ( idst ); + } + return NOMAD::DS_UNDEFINED; } /*-------------------------------------------------------------------*/ @@ -281,57 +287,61 @@ NOMAD::display_stats_type NOMAD::Display::get_display_stats_type /*-------------------------------------------------------------------*/ std::string NOMAD::Display::get_display_stats_keyword ( NOMAD::display_stats_type dst ) { - std::string s; - switch ( dst ) { - case NOMAD::DS_OBJ: - s = "OBJ"; - break; - case NOMAD::DS_MESH_INDEX: - s = "MESH_INDEX"; - break; - case NOMAD::DS_DELTA_M: - case NOMAD::DS_MESH_SIZE: - s = "MESH_SIZE"; - break; - case NOMAD::DS_DELTA_P: - case NOMAD::DS_POLL_SIZE: - s = "POLL_SIZE"; - break; - case NOMAD::DS_EVAL: - s = "EVAL"; - break; - case NOMAD::DS_SIM_BBE: - s = "SIM_BBE"; - break; - case NOMAD::DS_BBE: - s = "BBE"; - break; - case NOMAD::DS_SGTE: - s = "SGTE"; - break; - case NOMAD::DS_BBO: - s = "BBO"; - break; - case NOMAD::DS_SOL: - s = "SOL"; - break; - case NOMAD::DS_VAR: - s = "VAR"; - break; - case NOMAD::DS_TIME: - s = "TIME"; - break; - case NOMAD::DS_STAT_SUM: - s = "STAT_SUM"; - break; - case NOMAD::DS_STAT_AVG: - s = "STAT_AVG"; - break; - case NOMAD::DS_UNDEFINED: - s = "undefined"; - break; - } - return s; + std::string s; + switch ( dst ) + { + case NOMAD::DS_OBJ: + s = "OBJ"; + break; + case NOMAD::DS_MESH_INDEX: + s = "MESH_INDEX"; + break; + case NOMAD::DS_DELTA_M: + case NOMAD::DS_MESH_SIZE: + s = "MESH_SIZE"; + break; + case NOMAD::DS_DELTA_P: + case NOMAD::DS_POLL_SIZE: + s = "POLL_SIZE"; + break; + case NOMAD::DS_EVAL: + s = "EVAL"; + break; + case NOMAD::DS_SIM_BBE: + s = "SIM_BBE"; + break; + case NOMAD::DS_BBE: + s = "BBE"; + break; + case NOMAD::DS_BLK_EVA: + s = "BLK_EVA"; + break; + case NOMAD::DS_SGTE: + s = "SGTE"; + break; + case NOMAD::DS_BBO: + s = "BBO"; + break; + case NOMAD::DS_SOL: + s = "SOL"; + break; + case NOMAD::DS_VAR: + s = "VAR"; + break; + case NOMAD::DS_TIME: + s = "TIME"; + break; + case NOMAD::DS_STAT_SUM: + s = "STAT_SUM"; + break; + case NOMAD::DS_STAT_AVG: + s = "STAT_AVG"; + break; + case NOMAD::DS_UNDEFINED: + s = "undefined"; + break; + } + return s; } /*-----------------------------------------------------------------*/ @@ -339,21 +349,22 @@ std::string NOMAD::Display::get_display_stats_keyword ( NOMAD::display_stats_typ /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::dd_type dd ) { - switch ( dd ) { - case NOMAD::NO_DISPLAY: - out << "no display (0)"; - break; - case NOMAD::MINIMAL_DISPLAY: - out << "minimal display (1)"; - break; - case NOMAD::NORMAL_DISPLAY: - out << "normal (2)"; - break; - case NOMAD::FULL_DISPLAY: - default: - out << "full (3)"; - } - return out; + switch ( dd ) + { + case NOMAD::NO_DISPLAY: + out << "no display (0)"; + break; + case NOMAD::MINIMAL_DISPLAY: + out << "minimal display (1)"; + break; + case NOMAD::NORMAL_DISPLAY: + out << "normal (2)"; + break; + case NOMAD::FULL_DISPLAY: + default: + out << "full (3)"; + } + return out; } /*-----------------------------------------------------*/ @@ -361,32 +372,33 @@ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::dd_type dd ) /*-----------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::success_type st ) { - switch ( st ) { - case NOMAD::FULL_SUCCESS: - out << "dominating"; - break; - case NOMAD::PARTIAL_SUCCESS: - out << "improving"; - break; - case NOMAD::UNSUCCESSFUL: - out << "unsuccessful"; - } - return out; + switch ( st ) + { + case NOMAD::FULL_SUCCESS: + out << "dominating"; + break; + case NOMAD::PARTIAL_SUCCESS: + out << "improving"; + break; + case NOMAD::UNSUCCESSFUL: + out << "unsuccessful"; + } + return out; } /*-----------------------------------------------------------------*/ /* to display a vector of bb-input types */ /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , - const std::vector<NOMAD::bb_input_type> & bbits ) + const std::vector<NOMAD::bb_input_type> & bbits ) { - if ( bbits.empty() ) + if ( bbits.empty() ) + return out; + size_t n = bbits.size()-1; + for ( size_t k = 0 ; k < n ; ++k ) + out << std::setw(8) << bbits[k] << " "; + out << std::setw(8) << bbits[n]; return out; - size_t n = bbits.size()-1; - for ( size_t k = 0 ; k < n ; ++k ) - out << std::setw(8) << bbits[k] << " "; - out << std::setw(8) << bbits[n]; - return out; } /*-----------------------------------------------------------------*/ @@ -394,20 +406,20 @@ std::ostream & NOMAD::operator << ( std::ostream & ou /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::bb_input_type bi ) { - switch ( bi ) { - case NOMAD::CONTINUOUS: - out << "cont(R)"; - break; - case NOMAD::CATEGORICAL: - out << "cat(C)"; - break; - case NOMAD::INTEGER: - out << "int(I)"; - break; - case NOMAD::BINARY: - out << "bin(B)"; - } - return out; + switch ( bi ) { + case NOMAD::CONTINUOUS: + out << "cont(R)"; + break; + case NOMAD::CATEGORICAL: + out << "cat(C)"; + break; + case NOMAD::INTEGER: + out << "int(I)"; + break; + case NOMAD::BINARY: + out << "bin(B)"; + } + return out; } /*-----------------------------------------------------------------*/ @@ -415,50 +427,51 @@ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::bb_input_type bi /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::search_type st ) { - switch ( st ) { - case NOMAD::POLL: - out << "poll"; - break; - case NOMAD::EXTENDED_POLL: - out << "extended poll"; - break; - case NOMAD::SEARCH: - out << "search"; - break; - case NOMAD::CACHE_SEARCH: - out << "cache search"; - break; - case NOMAD::USER_SEARCH: - out << "user search"; - break; - case NOMAD::SPEC_SEARCH: - out << "speculative search"; - break; - case NOMAD::LH_SEARCH: - out << "LH search"; - break; - case NOMAD::LH_SEARCH_P1: - out << "LH search - Phase one"; - break; - case NOMAD::P1_SEARCH: - out << "Phase one search"; - break; - case NOMAD::MODEL_SEARCH: - out << "model search"; - break; - case NOMAD::VNS_SEARCH: - out << "VNS search"; - break; - case NOMAD::X0_EVAL: - out << "x0 evaluation"; - break; - case NOMAD::ASYNCHRONOUS: - out << "asynchronous final evaluations"; - break; - case NOMAD::UNDEFINED_SEARCH: - out << "undefined"; - } - return out; + switch ( st ) + { + case NOMAD::POLL: + out << "poll"; + break; + case NOMAD::EXTENDED_POLL: + out << "extended poll"; + break; + case NOMAD::SEARCH: + out << "search"; + break; + case NOMAD::CACHE_SEARCH: + out << "cache search"; + break; + case NOMAD::USER_SEARCH: + out << "user search"; + break; + case NOMAD::SPEC_SEARCH: + out << "speculative search"; + break; + case NOMAD::LH_SEARCH: + out << "LH search"; + break; + case NOMAD::LH_SEARCH_P1: + out << "LH search - Phase one"; + break; + case NOMAD::P1_SEARCH: + out << "Phase one search"; + break; + case NOMAD::MODEL_SEARCH: + out << "model search"; + break; + case NOMAD::VNS_SEARCH: + out << "VNS search"; + break; + case NOMAD::X0_EVAL: + out << "x0 evaluation"; + break; + case NOMAD::ASYNCHRONOUS: + out << "asynchronous final evaluations"; + break; + case NOMAD::UNDEFINED_SEARCH: + out << "undefined"; + } + return out; } /*-----------------------------------------------------------------*/ @@ -466,17 +479,18 @@ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::search_type st ) /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::model_type mt ) { - switch ( mt ) { - case NOMAD::QUADRATIC_MODEL: - out << "quadratic"; - break; - case NOMAD::TGP_MODEL: - out << "TGP"; - break; - case NOMAD::NO_MODEL: - out << "no models"; - } - return out; + switch ( mt ) + { + case NOMAD::QUADRATIC_MODEL: + out << "quadratic"; + break; + case NOMAD::TGP_MODEL: + out << "TGP"; + break; + case NOMAD::NO_MODEL: + out << "no models"; + } + return out; } /*-----------------------------------------------------------------*/ @@ -484,18 +498,19 @@ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::model_type mt ) /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::TGP_mode_type m ) { - switch ( m ) { - case NOMAD::TGP_FAST: - out << "fast"; - break; - case NOMAD::TGP_PRECISE: - out << "precise"; - break; - case NOMAD::TGP_USER: - out << "user"; - break; - } - return out; + switch ( m ) + { + case NOMAD::TGP_FAST: + out << "fast"; + break; + case NOMAD::TGP_PRECISE: + out << "precise"; + break; + case NOMAD::TGP_USER: + out << "user"; + break; + } + return out; } /*-----------------------------------------------------------------*/ @@ -503,14 +518,15 @@ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::TGP_mode_type m /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::eval_type et ) { - switch ( et ) { - case NOMAD::TRUTH: - out << "truth"; - break; - case NOMAD::SGTE: - out << "surrogate"; - } - return out; + switch ( et ) + { + case NOMAD::TRUTH: + out << "truth"; + break; + case NOMAD::SGTE: + out << "surrogate"; + } + return out; } /*-----------------------------------------------------------------*/ @@ -518,20 +534,26 @@ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::eval_type et ) /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::eval_status_type est ) { - switch ( est ) { - case NOMAD::EVAL_FAIL: - out << "fail"; - break; - case NOMAD::EVAL_OK: - out << "ok"; - break; - case NOMAD::EVAL_IN_PROGRESS: - out << "in progress"; - break; - case NOMAD::UNDEFINED_STATUS: - out << "undefined"; - } - return out; + switch ( est ) + { + case NOMAD::EVAL_FAIL: + out << "fail"; + break; + case NOMAD::EVAL_OK: + out << "ok"; + break; + case NOMAD::EVAL_IN_PROGRESS: + out << "in progress"; + break; + case NOMAD::UNDEFINED_STATUS: + out << "undefined"; + break; + case NOMAD::EVAL_USER_REJECT: + out << "rejected"; + break; + + } + return out; } /*-----------------------------------------------------------------*/ @@ -539,91 +561,98 @@ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::eval_status_type /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::stop_type st ) { - switch ( st ) { - case NOMAD::DELTA_M_MIN_REACHED: - out << "min mesh size"; - break; - case NOMAD::DELTA_P_MIN_REACHED: - out << "min poll size"; - break; - case NOMAD::L_MAX_REACHED: - out << "max mesh index"; - break; - case NOMAD::L_LIMITS_REACHED: - out << "mesh index limits (+/- " << NOMAD::L_LIMITS << ")"; - break; - case NOMAD::MAX_TIME_REACHED: - out << "max time"; - break; - case NOMAD::MAX_BB_EVAL_REACHED: - out << "max number of blackbox evaluations"; - break; - case NOMAD::MAX_SGTE_EVAL_REACHED: - out << "max number of sgte evaluations"; - break; - case NOMAD::MAX_EVAL_REACHED: - out << "max number of evaluations"; - break; - case NOMAD::MAX_SIM_BB_EVAL_REACHED: - out << "max number of sim. bb evaluations"; - break; - case NOMAD::MAX_ITER_REACHED: - out << "max number of iterations"; - break; - case NOMAD::MAX_CONS_FAILED_ITER: - out << "max number of consecutive failed iterations"; - break; - case NOMAD::FEAS_REACHED: - out << "feasibility achieved"; - break; - case NOMAD::F_TARGET_REACHED: - out << "objective target reached"; - break; - case NOMAD::L_CURVE_TARGET_REACHED: - out << "L-curve target reached"; - break; - case NOMAD::P1_FAIL: - out << "phase one failed"; - break; - case NOMAD::STAT_SUM_TARGET_REACHED: - out << "stat sum target reached"; - break; - case NOMAD::X0_FAIL: - out << "problem with starting point evaluation"; - break; - case NOMAD::MESH_PREC_REACHED: - out << "mesh size reached NOMAD precision"; - break; - case NOMAD::MULTI_MAX_BB_REACHED: - out << "max number of bb evaluations"; - break; - case NOMAD::MULTI_NB_MADS_RUNS_REACHED: - out << "max number of MADS runs"; - break; - case NOMAD::MULTI_STAGNATION: - out << "stagnation of the multi-obj. algo."; - break; - case NOMAD::MULTI_NO_PARETO_PTS: - out << "initial runs cannot find Pareto points"; - break; - case NOMAD::MAX_CACHE_MEMORY_REACHED: - out << "max cache memory reached"; - break; - case NOMAD::CTRL_C: - out << "terminated by ctrl-c"; - break; - case NOMAD::USER_STOPPED: - out << "terminated by the user inside Evaluator::update_iteration()"; - break; - case NOMAD::UNKNOWN_STOP_REASON: - case NOMAD::NO_STOP: - out << "unknown"; - break; - case NOMAD::ERROR: - out << "error"; - break; - } - return out; + switch ( st ) + { + case NOMAD::DELTA_M_MIN_REACHED: + out << "min mesh size"; + break; + case NOMAD::DELTA_P_MIN_REACHED: + out << "min poll size"; + break; + case NOMAD::L_MAX_REACHED: + out << "max mesh index"; + break; + case NOMAD::L_MIN_REACHED: + out << "min mesh index"; + break; + case NOMAD::L_LIMITS_REACHED: + out << "mesh index limits"; + break; + case NOMAD::XL_LIMITS_REACHED: + out << "mesh index limits"; + break; + case NOMAD::MAX_TIME_REACHED: + out << "max time"; + break; + case NOMAD::MAX_BB_EVAL_REACHED: + out << "max number of blackbox evaluations"; + break; + case NOMAD::MAX_SGTE_EVAL_REACHED: + out << "max number of sgte evaluations"; + break; + case NOMAD::MAX_EVAL_REACHED: + out << "max number of evaluations"; + break; + case NOMAD::MAX_SIM_BB_EVAL_REACHED: + out << "max number of sim. bb evaluations"; + break; + case NOMAD::MAX_ITER_REACHED: + out << "max number of iterations"; + break; + case NOMAD::MAX_CONS_FAILED_ITER: + out << "max number of consecutive failed iterations"; + break; + case NOMAD::FEAS_REACHED: + out << "feasibility achieved"; + break; + case NOMAD::F_TARGET_REACHED: + out << "objective target reached"; + break; + case NOMAD::L_CURVE_TARGET_REACHED: + out << "L-curve target reached"; + break; + case NOMAD::P1_FAIL: + out << "phase one failed"; + break; + case NOMAD::STAT_SUM_TARGET_REACHED: + out << "stat sum target reached"; + break; + case NOMAD::X0_FAIL: + out << "problem with starting point evaluation"; + break; + case NOMAD::MESH_PREC_REACHED: + out << "mesh size reached NOMAD precision"; + break; + case NOMAD::MULTI_MAX_BB_REACHED: + out << "max number of bb evaluations"; + break; + case NOMAD::MULTI_NB_MADS_RUNS_REACHED: + out << "max number of MADS runs"; + break; + case NOMAD::MULTI_STAGNATION: + out << "stagnation of the multi-obj. algo."; + break; + case NOMAD::MULTI_NO_PARETO_PTS: + out << "initial runs cannot find Pareto points"; + break; + case NOMAD::MAX_CACHE_MEMORY_REACHED: + out << "max cache memory reached"; + break; + case NOMAD::CTRL_C: + out << "terminated by ctrl-c"; + break; + case NOMAD::USER_STOPPED: + out << "terminated by the user inside Evaluator::update_iteration()"; + break; + case NOMAD::UNKNOWN_STOP_REASON: + case NOMAD::NO_STOP: + out << "unknown"; + break; + case NOMAD::ERROR: + out << "error"; + break; + } + return out; } /*-----------------------------------------------------------------*/ @@ -631,60 +660,62 @@ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::stop_type st ) /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::bb_output_type bbt ) { - switch ( bbt ) { - case NOMAD::OBJ: - out << "OBJ"; - break; - case NOMAD::EB: - out << "EB"; - break; - case NOMAD::PB: - out << "PB"; - break; - case NOMAD::PEB_P: - out << "PEB(P)"; - break; - case NOMAD::PEB_E: - out << "PEB(E)"; - break; - case NOMAD::FILTER: - out << "F"; - break; - case NOMAD::CNT_EVAL: - out << "CNT_EVAL"; - break; - case NOMAD::STAT_AVG: - out << "STAT_AVG"; - break; - case NOMAD::STAT_SUM: - out << "STAT_SUM"; - break; - case NOMAD::UNDEFINED_BBO: - out << "-"; - } - return out; + switch ( bbt ) + { + case NOMAD::OBJ: + out << "OBJ"; + break; + case NOMAD::EB: + out << "EB"; + break; + case NOMAD::PB: + out << "PB"; + break; + case NOMAD::PEB_P: + out << "PEB(P)"; + break; + case NOMAD::PEB_E: + out << "PEB(E)"; + break; + case NOMAD::FILTER: + out << "F"; + break; + case NOMAD::CNT_EVAL: + out << "CNT_EVAL"; + break; + case NOMAD::STAT_AVG: + out << "STAT_AVG"; + break; + case NOMAD::STAT_SUM: + out << "STAT_SUM"; + break; + case NOMAD::UNDEFINED_BBO: + out << "-"; + } + return out; } /*-----------------------------------------------------------------*/ /* to display a interpolation_type */ /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , - NOMAD::interpolation_type it ) + NOMAD::interpolation_type it ) { - switch ( it ) { - case NOMAD::MFN: - out << "Minimum Frobenius Norm interpolation"; - break; - case NOMAD::REGRESSION: - out << "regression"; - break; - case NOMAD::WP_REGRESSION: - out << "well-poised regression"; - break; - case NOMAD::UNDEFINED_INTERPOLATION_TYPE: - out << "undefined"; - } - return out; + switch ( it ) + { + case NOMAD::MFN: + out << "Minimum Frobenius Norm interpolation"; + break; + case NOMAD::REGRESSION: + out << "regression"; + break; + case NOMAD::WP_REGRESSION: + out << "well-poised regression"; + break; + case NOMAD::UNDEFINED_INTERPOLATION_TYPE: + out << "undefined"; + } + return out; } /*-----------------------------------------------------------------*/ @@ -692,17 +723,18 @@ std::ostream & NOMAD::operator << ( std::ostream & out , /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::hnorm_type hnorm ) { - switch ( hnorm ) { - case NOMAD::L1: - out << "L1"; - break; - case NOMAD::L2: - out << "L2"; - break; - case NOMAD::LINF: - out << "Linf"; - } - return out; + switch ( hnorm ) + { + case NOMAD::L1: + out << "L1"; + break; + case NOMAD::L2: + out << "L2"; + break; + case NOMAD::LINF: + out << "Linf"; + } + return out; } /*-----------------------------------------------------------------*/ @@ -710,101 +742,103 @@ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::hnorm_type hnorm /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::multi_formulation_type f ) { - switch ( f ) { - case NOMAD::NORMALIZED: - out << "normalized"; - break; - case NOMAD::PRODUCT: - out << "product"; - break; - case NOMAD::DIST_L1: - out << "distance L1"; - break; - case NOMAD::DIST_L2: - out << "distance L2"; - break; - case NOMAD::DIST_LINF: - out << "distance Linf"; - break; - case NOMAD::UNDEFINED_FORMULATION: - out << "undefined"; - break; - } - return out; + switch ( f ) + { + case NOMAD::NORMALIZED: + out << "normalized"; + break; + case NOMAD::PRODUCT: + out << "product"; + break; + case NOMAD::DIST_L1: + out << "distance L1"; + break; + case NOMAD::DIST_L2: + out << "distance L2"; + break; + case NOMAD::DIST_LINF: + out << "distance Linf"; + break; + case NOMAD::UNDEFINED_FORMULATION: + out << "undefined"; + break; + } + return out; } /*-----------------------------------------------------------------*/ /* to display a direction_type */ /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , - NOMAD::direction_type dt ) + NOMAD::direction_type dt ) { - switch ( dt ) { - case NOMAD::ORTHO_1: - out << "Ortho-MADS 1"; - break; - case NOMAD::ORTHO_2: - out << "Ortho-MADS 2"; - break; - case NOMAD::ORTHO_NP1_QUAD: - out << "Ortho-MADS n+1 QUAD "; - break; - case NOMAD::ORTHO_NP1_NEG: - out << "Ortho-MADS n+1 NEG "; - break; - case NOMAD::DYN_ADDED: - out << "Dynamic n+1th direction"; - break; - case NOMAD::ORTHO_2N: - out << "Ortho-MADS 2n"; - break; - case NOMAD::LT_1: - out << "LT-MADS 1"; - break; - case NOMAD::LT_2: - out << "LT-MADS 2"; - break; - case NOMAD::LT_2N: - out << "LT-MADS 2n"; - break; - case NOMAD::LT_NP1: - out << "LT-MADS n+1"; - break; - case NOMAD::GPS_BINARY: - out << "GPS n, binary"; - break; - case NOMAD::GPS_2N_STATIC: - out << "GPS 2n, static"; - break; - case NOMAD::GPS_2N_RAND: - out << "GPS 2n, random"; - break; - case NOMAD::GPS_NP1_STATIC_UNIFORM: - out << "GPS n+1, static, uniform angles"; - break; - case NOMAD::GPS_NP1_STATIC: - out << "GPS n+1, static"; - break; - case NOMAD::GPS_NP1_RAND_UNIFORM: - out << "GPS n+1, random, uniform angles"; - break; - case NOMAD::GPS_NP1_RAND: - out << "GPS n+1, random"; - break; - case NOMAD::NO_DIRECTION: - out << "none"; - break; - case NOMAD::MODEL_SEARCH_DIR: - out << "model search direction"; - break; - case NOMAD::UNDEFINED_DIRECTION: - out << "undefined"; - break; - case NOMAD::PROSPECT_DIR: - out << "Prospect direction"; - break; - } - return out; + switch ( dt ) + { + case NOMAD::ORTHO_1: + out << "Ortho-MADS 1"; + break; + case NOMAD::ORTHO_2: + out << "Ortho-MADS 2"; + break; + case NOMAD::ORTHO_NP1_QUAD: + out << "Ortho-MADS n+1 QUAD"; + break; + case NOMAD::ORTHO_NP1_NEG: + out << "Ortho-MADS n+1 NEG"; + break; + case NOMAD::DYN_ADDED: + out << "Dynamic n+1th direction"; + break; + case NOMAD::ORTHO_2N: + out << "Ortho-MADS 2n"; + break; + case NOMAD::LT_1: + out << "LT-MADS 1"; + break; + case NOMAD::LT_2: + out << "LT-MADS 2"; + break; + case NOMAD::LT_2N: + out << "LT-MADS 2n"; + break; + case NOMAD::LT_NP1: + out << "LT-MADS n+1"; + break; + case NOMAD::GPS_BINARY: + out << "GPS n, binary"; + break; + case NOMAD::GPS_2N_STATIC: + out << "GPS 2n, static"; + break; + case NOMAD::GPS_2N_RAND: + out << "GPS 2n, random"; + break; + case NOMAD::GPS_NP1_STATIC_UNIFORM: + out << "GPS n+1, static, uniform angles"; + break; + case NOMAD::GPS_NP1_STATIC: + out << "GPS n+1, static"; + break; + case NOMAD::GPS_NP1_RAND_UNIFORM: + out << "GPS n+1, random, uniform angles"; + break; + case NOMAD::GPS_NP1_RAND: + out << "GPS n+1, random"; + break; + case NOMAD::NO_DIRECTION: + out << "none"; + break; + case NOMAD::MODEL_SEARCH_DIR: + out << "model search direction"; + break; + case NOMAD::UNDEFINED_DIRECTION: + out << "undefined"; + break; + case NOMAD::PROSPECT_DIR: + out << "Prospect direction"; + break; + } + return out; } /*-----------------------------------------------------------------*/ @@ -812,8 +846,8 @@ std::ostream & NOMAD::operator << ( std::ostream & out , /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::display_stats_type dst ) { - out << NOMAD::Display::get_display_stats_keyword ( dst ); - return out; + out << NOMAD::Display::get_display_stats_keyword ( dst ); + return out; } /*-----------------------------------------------------------------*/ @@ -821,28 +855,29 @@ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::display_stats_ty /*-----------------------------------------------------------------*/ std::ostream & NOMAD::operator << ( std::ostream & out , NOMAD::check_failed_type cf ) { - switch ( cf ) { - case NOMAD::CHECK_OK: - out << "ok"; - break; - case NOMAD::LB_FAIL: - out << "lower bound"; - break; - case NOMAD::UB_FAIL: - out << "upper bound"; - break; - case NOMAD::FIX_VAR_FAIL: - out << "fixed variable"; - break; - case NOMAD::BIN_FAIL: - out << "binary variable"; - break; - case NOMAD::CAT_FAIL: - out << "categorical variable"; - break; - case NOMAD::INT_FAIL: - out << "integer variable"; - break; - } - return out; + switch ( cf ) + { + case NOMAD::CHECK_OK: + out << "ok"; + break; + case NOMAD::LB_FAIL: + out << "lower bound"; + break; + case NOMAD::UB_FAIL: + out << "upper bound"; + break; + case NOMAD::FIX_VAR_FAIL: + out << "fixed variable"; + break; + case NOMAD::BIN_FAIL: + out << "binary variable"; + break; + case NOMAD::CAT_FAIL: + out << "categorical variable"; + break; + case NOMAD::INT_FAIL: + out << "integer variable"; + break; + } + return out; } diff --git a/src/Display.hpp b/src/Display.hpp index 593e0d2..e88323b 100644 --- a/src/Display.hpp +++ b/src/Display.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Double.cpp b/src/Double.cpp index 561a685..8a7c067 100644 --- a/src/Double.cpp +++ b/src/Double.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Double.cpp - \brief Custom class for double-precision reals (implementation) - \author Sebastien Le Digabel - \date 2010-04-02 - \see Double.hpp -*/ + \file Double.cpp + \brief Custom class for double-precision reals (implementation) + \author Sebastien Le Digabel + \date 2010-04-02 + \see Double.hpp + */ #include "Double.hpp" /*-----------------------------------*/ @@ -57,13 +57,13 @@ int NOMAD::Double::_max_cardinality = 0; /* constructor 1 */ /*-----------------------------------------------*/ NOMAD::Double::Double ( void ) - : _value ( 0.0 ) , - _defined ( false ) +: _value ( 0.0 ) , +_defined ( false ) { #ifdef MEMORY_DEBUG - ++NOMAD::Double::_cardinality; - if ( NOMAD::Double::_cardinality > NOMAD::Double::_max_cardinality ) - ++NOMAD::Double::_max_cardinality; + ++NOMAD::Double::_cardinality; + if ( NOMAD::Double::_cardinality > NOMAD::Double::_max_cardinality ) + ++NOMAD::Double::_max_cardinality; #endif } @@ -71,13 +71,13 @@ NOMAD::Double::Double ( void ) /* constructor 2 */ /*-----------------------------------------------*/ NOMAD::Double::Double ( double v ) - : _value ( v ) , - _defined ( true ) +: _value ( v ) , +_defined ( true ) { #ifdef MEMORY_DEBUG - ++NOMAD::Double::_cardinality; - if (NOMAD::Double::_cardinality > NOMAD::Double::_max_cardinality) - ++NOMAD::Double::_max_cardinality; + ++NOMAD::Double::_cardinality; + if (NOMAD::Double::_cardinality > NOMAD::Double::_max_cardinality) + ++NOMAD::Double::_max_cardinality; #endif } @@ -85,35 +85,35 @@ NOMAD::Double::Double ( double v ) /* constructor 3 */ /*-----------------------------------------------*/ NOMAD::Double::Double ( const NOMAD::Double & d ) - : _value ( d._value ) , - _defined ( d._defined ) +: _value ( d._value ) , +_defined ( d._defined ) { #ifdef MEMORY_DEBUG - ++NOMAD::Double::_cardinality; - if (NOMAD::Double::_cardinality > NOMAD::Double::_max_cardinality) - ++NOMAD::Double::_max_cardinality; + ++NOMAD::Double::_cardinality; + if (NOMAD::Double::_cardinality > NOMAD::Double::_max_cardinality) + ++NOMAD::Double::_max_cardinality; #endif } /*-----------------------------------------------*/ /* destructor */ /*-----------------------------------------------*/ -NOMAD::Double::~Double ( void ) +NOMAD::Double::~Double ( void ) { #ifdef MEMORY_DEBUG - --NOMAD::Double::_cardinality; + --NOMAD::Double::_cardinality; #endif } /*-----------------------------------------------*/ /* set epsilon (static) */ /*-----------------------------------------------*/ -void NOMAD::Double::set_epsilon ( double eps ) +void NOMAD::Double::set_epsilon ( double eps ) { - if ( eps <= 0.0 ) - throw NOMAD::Exception ( "Double.cpp" , __LINE__ , - "NOMAD::Double::set_epsilon(): invalid epsilon" ); - NOMAD::Double::_epsilon = eps; + if ( eps <= 0.0 ) + throw NOMAD::Exception ( "Double.cpp" , __LINE__ , + "NOMAD::Double::set_epsilon(): invalid epsilon" ); + NOMAD::Double::_epsilon = eps; } /*-----------------------------------------------*/ @@ -121,10 +121,10 @@ void NOMAD::Double::set_epsilon ( double eps ) /*-----------------------------------------------*/ double NOMAD::Double::value ( void ) const { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double::value(): value not defined" ); - return _value; + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double::value(): value not defined" ); + return _value; } /*------------------------------------------*/ @@ -132,13 +132,13 @@ double NOMAD::Double::value ( void ) const /*------------------------------------------*/ std::istream & NOMAD::operator >> ( std::istream & in , NOMAD::Double & d ) { - std::string s; - in >> s; - - if ( !in.fail() && !d.atof (s) ) - in.setstate ( std::ios::failbit ); - - return in; + std::string s; + in >> s; + + if ( !in.fail() && !d.atof (s) ) + in.setstate ( std::ios::failbit ); + + return in; } /*-----------------------------------------------*/ @@ -146,52 +146,52 @@ std::istream & NOMAD::operator >> ( std::istream & in , NOMAD::Double & d ) /*-----------------------------------------------*/ bool NOMAD::Double::atof ( const std::string & ss ) { - - std::string s = ss; - NOMAD::toupper(s); - - if ( s == "-" || ss == NOMAD::Double::_undef_str ) { - _value = 0.0; - _defined = false; - return true; - } - - if ( s == "INF" || s == "+INF" || - ss == NOMAD::Double::_inf_str || - ss == ("+" + NOMAD::Double::_inf_str) ) { - _value = NOMAD::INF; - _defined = true; - return true; - } - - if ( s == "-INF" || ss == ("-" + NOMAD::Double::_inf_str) ) { - _value = -NOMAD::INF; - _defined = true; - return true; - } - - if ( s.empty() || (s.size() == 1 && !isdigit(s[0])) ) - return false; - - if ( !isdigit(s[0]) && s[0] != '+' && s[0] != '-' && s[0] != '.' ) - return false; - - size_t n = s.size(); - for ( size_t k = 1 ; k < n ; ++k ) - if ( !isdigit(s[k]) && s[k] != '.' ) { - if ( s[k] == 'E' ) { - if ( s.size() == k+1 ) - return false; - ++k; - if ( !isdigit(s[k]) && s[k] != '+' && s[k] != '-' ) - return false; - } - else - return false; + + std::string s = ss; + NOMAD::toupper(s); + + if ( s == "-" || ss == NOMAD::Double::_undef_str ) { + _value = 0.0; + _defined = false; + return true; } - - *this = std::atof ( s.c_str() ); - return true; + + if ( s == "INF" || s == "+INF" || + ss == NOMAD::Double::_inf_str || + ss == ("+" + NOMAD::Double::_inf_str) ) { + _value = NOMAD::INF; + _defined = true; + return true; + } + + if ( s == "-INF" || ss == ("-" + NOMAD::Double::_inf_str) ) { + _value = -NOMAD::INF; + _defined = true; + return true; + } + + if ( s.empty() || (s.size() == 1 && !isdigit(s[0])) ) + return false; + + if ( !isdigit(s[0]) && s[0] != '+' && s[0] != '-' && s[0] != '.' ) + return false; + + size_t n = s.size(); + for ( size_t k = 1 ; k < n ; ++k ) + if ( !isdigit(s[k]) && s[k] != '.' ) { + if ( s[k] == 'E' ) { + if ( s.size() == k+1 ) + return false; + ++k; + if ( !isdigit(s[k]) && s[k] != '+' && s[k] != '-' ) + return false; + } + else + return false; + } + + *this = std::atof ( s.c_str() ); + return true; } /*-------------------------------------------------*/ @@ -200,16 +200,16 @@ bool NOMAD::Double::atof ( const std::string & ss ) /*-------------------------------------------------*/ bool NOMAD::Double::relative_atof ( const std::string & s , bool & relative ) { - if ( std::toupper(s[0]) == 'R' ) { - relative = true; - std::string ss = s; - ss.erase(ss.begin()); - if ( !atof(ss) ) - return false; - return ( *this >= 0.0 ); - } - relative = false; - return atof(s); + if ( std::toupper(s[0]) == 'R' ) { + relative = true; + std::string ss = s; + ss.erase(ss.begin()); + if ( !atof(ss) ) + return false; + return ( *this >= 0.0 ); + } + relative = false; + return atof(s); } /*-----------------------------------------------*/ @@ -217,9 +217,9 @@ bool NOMAD::Double::relative_atof ( const std::string & s , bool & relative ) /*-----------------------------------------------*/ bool NOMAD::Double::is_integer ( void ) const { - if ( !_defined ) - return false; - return ( NOMAD::Double(std::floor(_value))) == ( NOMAD::Double(std::ceil(_value)) ); + if ( !_defined ) + return false; + return ( NOMAD::Double(std::floor(_value))) == ( NOMAD::Double(std::ceil(_value)) ); } /*-----------------------------------------------*/ @@ -227,21 +227,21 @@ bool NOMAD::Double::is_integer ( void ) const /*-----------------------------------------------*/ bool NOMAD::Double::is_binary ( void ) const { - if ( !_defined ) - return false; - return ( NOMAD::Double(_value) == 0.0 || NOMAD::Double(_value) == 1.0 ); + if ( !_defined ) + return false; + return ( NOMAD::Double(_value) == 0.0 || NOMAD::Double(_value) == 1.0 ); } /*-------------------------------------*/ /* d = d1/d2 */ /*-------------------------------------*/ const NOMAD::Double NOMAD::operator / ( const NOMAD::Double & d1 , - const NOMAD::Double & d2 ) + const NOMAD::Double & d2 ) { - if ( d2.value() == 0.0 ) - throw NOMAD::Double::Invalid_Value ( "Double.cpp" , __LINE__ , - "NOMAD::Double: d1 / d2: division by zero" ); - return NOMAD::Double ( d1.value() / d2.value() ); + if ( d2.value() == 0.0 ) + throw NOMAD::Double::Invalid_Value ( "Double.cpp" , __LINE__ , + "NOMAD::Double: d1 / d2: division by zero" ); + return NOMAD::Double ( d1.value() / d2.value() ); } /*-------------------------------------*/ @@ -249,11 +249,11 @@ const NOMAD::Double NOMAD::operator / ( const NOMAD::Double & d1 , /*-------------------------------------*/ const NOMAD::Double & NOMAD::Double::operator += ( const NOMAD::Double & d2 ) { - if ( !_defined || !d2._defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double: d1 += d2: d1 or d2 not defined" ); - _value += d2._value; - return *this; + if ( !_defined || !d2._defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double: d1 += d2: d1 or d2 not defined" ); + _value += d2._value; + return *this; } /*-------------------------------------*/ @@ -261,11 +261,11 @@ const NOMAD::Double & NOMAD::Double::operator += ( const NOMAD::Double & d2 ) /*-------------------------------------*/ const NOMAD::Double & NOMAD::Double::operator -= ( const NOMAD::Double & d2 ) { - if ( !_defined || !d2._defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double: d1 -= d2: d1 or d2 not defined" ); - _value -= d2._value; - return *this; + if ( !_defined || !d2._defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double: d1 -= d2: d1 or d2 not defined" ); + _value -= d2._value; + return *this; } /*-------------------------------------*/ @@ -273,11 +273,11 @@ const NOMAD::Double & NOMAD::Double::operator -= ( const NOMAD::Double & d2 ) /*-------------------------------------*/ const NOMAD::Double & NOMAD::Double::operator *= ( const NOMAD::Double & d2 ) { - if ( !_defined || !d2._defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double: d1 *= d2: d1 or d2 not defined" ); - _value *= d2._value; - return *this; + if ( !_defined || !d2._defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double: d1 *= d2: d1 or d2 not defined" ); + _value *= d2._value; + return *this; } /*-------------------------------------*/ @@ -285,14 +285,14 @@ const NOMAD::Double & NOMAD::Double::operator *= ( const NOMAD::Double & d2 ) /*-------------------------------------*/ const NOMAD::Double & NOMAD::Double::operator /= ( const NOMAD::Double & d2 ) { - if ( !_defined || !d2._defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double: d1 /= d2: d1 or d2 not defined" ); - if ( d2._value == 0.0 ) - throw Invalid_Value ( "Double.cpp" , __LINE__ , - "NOMAD::Double: d1 /= d2: division by zero" ); - _value /= d2._value; - return *this; + if ( !_defined || !d2._defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double: d1 /= d2: d1 or d2 not defined" ); + if ( d2._value == 0.0 ) + throw Invalid_Value ( "Double.cpp" , __LINE__ , + "NOMAD::Double: d1 /= d2: division by zero" ); + _value /= d2._value; + return *this; } /*-------------------------------------*/ @@ -300,10 +300,10 @@ const NOMAD::Double & NOMAD::Double::operator /= ( const NOMAD::Double & d2 ) /*-------------------------------------*/ NOMAD::Double & NOMAD::Double::operator++ ( void ) { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , "NOMAD::Double: ++d: d not defined" ); - _value += 1; - return *this; + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , "NOMAD::Double: ++d: d not defined" ); + _value += 1; + return *this; } /*-------------------------------------*/ @@ -311,13 +311,13 @@ NOMAD::Double & NOMAD::Double::operator++ ( void ) /*-------------------------------------*/ NOMAD::Double NOMAD::Double::operator++ ( int n ) { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , "NOMAD::Double: d++: d not defined" ); - NOMAD::Double tmp = *this; - if( n <= 0 ) - n = 1; - _value += n; - return tmp; + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , "NOMAD::Double: d++: d not defined" ); + NOMAD::Double tmp = *this; + if( n <= 0 ) + n = 1; + _value += n; + return tmp; } /*-------------------------------------*/ @@ -325,10 +325,10 @@ NOMAD::Double NOMAD::Double::operator++ ( int n ) /*-------------------------------------*/ NOMAD::Double & NOMAD::Double::operator-- ( void ) { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , "NOMAD::Double: --d: d not defined" ); - _value -= 1; - return *this; + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , "NOMAD::Double: --d: d not defined" ); + _value -= 1; + return *this; } /*-------------------------------------*/ @@ -336,14 +336,14 @@ NOMAD::Double & NOMAD::Double::operator-- ( void ) /*-------------------------------------*/ NOMAD::Double NOMAD::Double::operator-- ( int n ) { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double: d--: d not defined" ); - NOMAD::Double tmp = *this; - if ( n <= 0 ) - n = 1; - _value -= n; - return tmp; + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double: d--: d not defined" ); + NOMAD::Double tmp = *this; + if ( n <= 0 ) + n = 1; + _value -= n; + return tmp; } /*-------------------------------------*/ @@ -351,16 +351,16 @@ NOMAD::Double NOMAD::Double::operator-- ( int n ) /*-------------------------------------*/ NOMAD::Double & NOMAD::Double::operator = ( const NOMAD::Double & d ) { - _value = d._value; - _defined = d._defined; - return *this; + _value = d._value; + _defined = d._defined; + return *this; } NOMAD::Double & NOMAD::Double::operator = ( double r ) { - _value = r; - _defined = true; - return *this; + _value = r; + _defined = true; + return *this; } /*------------------------------------------*/ @@ -368,176 +368,179 @@ NOMAD::Double & NOMAD::Double::operator = ( double r ) /*------------------------------------------*/ void NOMAD::Double::display ( const NOMAD::Display & out ) const { - if ( _defined ) { - if ( _value == NOMAD::INF ) - out << NOMAD::Double::_inf_str; - else if ( _value == -NOMAD::INF ) - out << "-" << NOMAD::Double::_inf_str; - else if ( std::floor(_value) == std::ceil(_value) && fabs(_value) < INT_MAX-1 ) - out << static_cast<int>(_value); + if ( _defined ) { + if ( _value == NOMAD::INF ) + out << NOMAD::Double::_inf_str; + else if ( _value == -NOMAD::INF ) + out << "-" << NOMAD::Double::_inf_str; + else if ( std::floor(_value) == std::ceil(_value) && fabs(_value) < INT_MAX-1 ) + out << static_cast<int>(_value); + else + out << _value; + } else - out << _value; - } - else - out << NOMAD::Double::_undef_str; + out << NOMAD::Double::_undef_str; } /*------------------------------------------*/ /* display with format */ /*------------------------------------------*/ void NOMAD::Double::display ( const NOMAD::Display & out , - const std::string & format ) const -{ - // interpret the format: - // --------------------- - - // %f w=-1 prec=-1 c='f' - // %4.5f w= 4 prec= 5 c='f' - // %4f w= 4 prec= 1 c='f' - // %.5f w=-1 prec= 5 c='f' - // %.f w=-1 prec= 0 c='f' - - // c may be in 'e', 'E', 'f', 'g', 'G', 'd', or 'i' - - // e Scientific notation (mantise/exponent) using e character 3.9265e+2 - // E Scientific notation (mantise/exponent) using E character 3.9265E+2 - // f Decimal floating point 392.65 - // g Use the shorter of %e or %f 392.65 - // G Use the shorter of %E or %f 392.65 - // d or i Integer rounded value 393 - - - std::string format2 = format; - - int w = -1; - int prec = -1; - char c = 0; - - if ( !format2.empty() && format2[0]=='%' ) - { - - size_t n = format2.size(); - - c = format2[n-1]; - - if ( c!='e' && c!='E' && c!='f' && c!='g' && c!='G' && c!='d' && c!='i' ) { - c = ( std::floor(_value) == std::ceil(_value) && fabs(_value) < INT_MAX-1 ) ? - 'd' : 'f'; - format2.push_back(c); - ++n; - } - - if ( n > 2 ) - { - - std::string sw , sprec; - - size_t k = format2.find("."); - - if ( k > 0 && k < n-1 ) - { - if ( n==3 ) { - sprec = "0"; - } - else - { - if ( k > 1 ) - sw = format2.substr ( 1 , k-1 ); - sprec = format2.substr ( k+1 , n-k-2 ); - } - } - else { - sw = format2.substr ( 1 , n-2 ); - } - - if ( !NOMAD::atoi ( sw , w ) ) - w = -1; - - if ( !NOMAD::atoi ( sprec , prec ) ) - prec = -1; - } - - if ( c=='d' || c=='i' ) - prec = 0; - } - - // display the value: - out << std::setw(w); - if ( _defined ) - { - if ( _value == NOMAD::INF ) - out << NOMAD::Double::_inf_str; - else if ( c=='d' || c=='i' || - ( format2.empty() && - std::floor(_value) == std::ceil(_value) && fabs(_value) < INT_MAX-1 ) ) - out << round(); - else - { - - int old_prec = out.precision(); - std::ios_base::fmtflags old_flags = out.flags(); - - if ( prec >= 0 ) - out.precision ( prec ); - - if ( c == 'f' ) - out.setf ( std::ios::fixed ); - - else if ( c == 'e' ) - { - out.unsetf ( std::ios::fixed ); - out.setf ( std::ios::scientific ); - } - - else if ( c == 'E' ) - { - out.unsetf ( std::ios::fixed ); - out.setf ( std::ios::scientific | std::ios::uppercase ); - } - - else if ( c == 'g' ) - { - std::ostringstream streamS,streamF; - streamS.precision ( prec ); - streamF.precision ( prec ); - streamF.unsetf(std::ios::scientific); - streamF.setf( std::ios::fixed ); - streamS.unsetf(std::ios::fixed); - streamS.setf( std::ios::scientific); - streamS << _value; - streamF << _value; - if (streamS.str().length() < streamF.str().length()) - out.setf(std::ios::scientific); - else - out.setf(std::ios::fixed); - } - - else if ( c == 'G' ) - { - std::ostringstream streamS,streamF; - streamS.precision ( prec ); - streamF.precision ( prec ); - streamF.unsetf(std::ios::scientific); - streamF.setf( std::ios::fixed ); - streamS.unsetf(std::ios::fixed); - streamS.setf( std::ios::scientific); - streamS << _value ; - streamF << _value ; - if (streamS.str().length() < streamF.str().length()) - out.setf(std::ios::scientific | std::ios::uppercase ); - else - out.setf(std::ios::fixed | std::ios::uppercase ); - - } - - out << _value; - - out.precision ( old_prec ); - out.flags ( old_flags ); - } - } - else - out << NOMAD::Double::_undef_str; + const std::string & format ) const +{ + // interpret the format: + // --------------------- + + // %f w=-1 prec=-1 c='f' + // %4.5f w= 4 prec= 5 c='f' + // %4f w= 4 prec= 1 c='f' + // %.5f w=-1 prec= 5 c='f' + // %.f w=-1 prec= 0 c='f' + + // c may be in 'e', 'E', 'f', 'g', 'G', 'd', or 'i' + + // e Scientific notation (mantise/exponent) using e character 3.9265e+2 + // E Scientific notation (mantise/exponent) using E character 3.9265E+2 + // f Decimal floating point 392.65 + // g Use the shorter of %e or %f 392.65 + // G Use the shorter of %E or %f 392.65 + // d or i Integer rounded value 393 + + + std::string format2 = format; + + int w = -1; + int prec = -1; + char c = 0; + + if ( !format2.empty() && format2[0]=='%' ) + { + + size_t n = format2.size(); + + c = format2[n-1]; + + if ( c!='e' && c!='E' && c!='f' && c!='g' && c!='G' && c!='d' && c!='i' ) + { + c = ( std::floor(_value) == std::ceil(_value) && fabs(_value) < INT_MAX-1 ) ? + 'd' : 'f'; + format2.push_back(c); + ++n; + } + + if ( n > 2 ) + { + + std::string sw , sprec; + + size_t k = format2.find("."); + + if ( k > 0 && k < n-1 ) + { + if ( n==3 ) + { + sprec = "0"; + } + else + { + if ( k > 1 ) + sw = format2.substr ( 1 , k-1 ); + sprec = format2.substr ( k+1 , n-k-2 ); + } + } + else + { + sw = format2.substr ( 1 , n-2 ); + } + + if ( !NOMAD::atoi ( sw , w ) ) + w = -1; + + if ( !NOMAD::atoi ( sprec , prec ) ) + prec = -1; + } + + if ( c=='d' || c=='i' ) + prec = 0; + } + + // display the value: + out << std::setw(w); + if ( _defined ) + { + if ( _value == NOMAD::INF ) + out << NOMAD::Double::_inf_str; + else if ( c=='d' || c=='i' || + ( format2.empty() && + std::floor(_value) == std::ceil(_value) && fabs(_value) < INT_MAX-1 ) ) + out << round(); + else + { + + int old_prec = out.precision(); + std::ios_base::fmtflags old_flags = out.flags(); + + if ( prec >= 0 ) + out.precision ( prec ); + + if ( c == 'f' ) + out.setf ( std::ios::fixed ); + + else if ( c == 'e' ) + { + out.unsetf ( std::ios::fixed ); + out.setf ( std::ios::scientific ); + } + + else if ( c == 'E' ) + { + out.unsetf ( std::ios::fixed ); + out.setf ( std::ios::scientific | std::ios::uppercase ); + } + + else if ( c == 'g' ) + { + std::ostringstream streamS,streamF; + streamS.precision ( prec ); + streamF.precision ( prec ); + streamF.unsetf(std::ios::scientific); + streamF.setf( std::ios::fixed ); + streamS.unsetf(std::ios::fixed); + streamS.setf( std::ios::scientific); + streamS << _value; + streamF << _value; + if (streamS.str().length() < streamF.str().length()) + out.setf(std::ios::scientific); + else + out.setf(std::ios::fixed); + + } + + else if ( c == 'G' ) + { + std::ostringstream streamS,streamF; + streamS.precision ( prec ); + streamF.precision ( prec ); + streamF.unsetf(std::ios::scientific); + streamF.setf( std::ios::fixed ); + streamS.unsetf(std::ios::fixed); + streamS.setf( std::ios::scientific); + streamS << _value ; + streamF << _value ; + if (streamS.str().length() < streamF.str().length()) + out.setf(std::ios::scientific | std::ios::uppercase ); + else + out.setf(std::ios::fixed | std::ios::uppercase ); + } + + out << _value; + + out.precision ( old_prec ); + out.flags ( old_flags ); + } + } + else + out << NOMAD::Double::_undef_str; } /*------------------------------------------*/ @@ -545,10 +548,10 @@ void NOMAD::Double::display ( const NOMAD::Display & out , /*------------------------------------------*/ int NOMAD::Double::round ( void ) const { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double::round(): value not defined" ); - return static_cast<int>(_value < 0.0 ? -std::floor(.5-_value) : std::floor(.5+_value)); + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double::round(): value not defined" ); + return static_cast<int>(_value < 0.0 ? -std::floor(.5-_value) : std::floor(.5+_value)); } @@ -557,10 +560,10 @@ int NOMAD::Double::round ( void ) const /*------------------------------------------*/ const NOMAD::Double NOMAD::Double::ceil ( void ) const { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double::ceil(): value not defined" ); - return NOMAD::Double(std::ceil(_value)); + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double::ceil(): value not defined" ); + return NOMAD::Double(std::ceil(_value)); } /*------------------------------------------*/ @@ -568,10 +571,10 @@ const NOMAD::Double NOMAD::Double::ceil ( void ) const /*------------------------------------------*/ const NOMAD::Double NOMAD::Double::floor ( void ) const { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double::floor(): value not defined" ); - return NOMAD::Double(std::floor(_value)); + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double::floor(): value not defined" ); + return NOMAD::Double(std::floor(_value)); } /*------------------------------------------*/ @@ -579,10 +582,10 @@ const NOMAD::Double NOMAD::Double::floor ( void ) const /*------------------------------------------*/ const NOMAD::Double NOMAD::Double::abs ( void ) const { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double::abs(): value not defined" ); - return fabs ( _value ); + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double::abs(): value not defined" ); + return fabs ( _value ); } /*------------------------------------------*/ @@ -590,10 +593,10 @@ const NOMAD::Double NOMAD::Double::abs ( void ) const /*------------------------------------------*/ const NOMAD::Double NOMAD::Double::pow2 ( void ) const { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double::pow2(): value not defined" ); - return pow ( _value , 2 ); + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double::pow2(): value not defined" ); + return pow ( _value , 2 ); } /*------------------------------------------*/ @@ -601,14 +604,14 @@ const NOMAD::Double NOMAD::Double::pow2 ( void ) const /*------------------------------------------*/ const NOMAD::Double NOMAD::Double::sqrt ( void ) const { - if ( !_defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double::sqrt(): value not defined" ); - if ( *this < 0.0 ) - throw NOMAD::Double::Invalid_Value ( "Double.cpp" , __LINE__ , - "NOMAD::Double::sqrt(x): x < 0" ); - - return std::sqrt ( _value ); + if ( !_defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double::sqrt(): value not defined" ); + if ( *this < 0.0 ) + throw NOMAD::Double::Invalid_Value ( "Double.cpp" , __LINE__ , + "NOMAD::Double::sqrt(x): x < 0" ); + + return std::sqrt ( _value ); } /*---------------------------------------------*/ @@ -622,45 +625,45 @@ const NOMAD::Double NOMAD::Double::sqrt ( void ) const // // The error will be in [0;2] // -// Modified: 2012-06-07, S. Le Digabel +// Modified: 2014-06-07, S. Le Digabel // const NOMAD::Double NOMAD::Double::rel_err ( const Double & x ) const { - if ( !_defined || !x._defined ) - throw Not_Defined ( "Double.cpp" , __LINE__ , - "NOMAD::Double::rel_err(): one of the values is not defined" ); - - // 1. test if x==y: - if ( this == &x || _value == x._value ) - return 0.0; - - double diff = fabs ( _value - x._value ); - - // 2. test if one of the values is zero: - if ( _value == 0.0 || x._value == 0.0 ) { - - // we return min{2,|x-y|} (instead of 1): - if ( diff > 2.0 ) - return 2.0; - return diff; - } - - // 3. compute the original error: - double a = fabs ( _value ); - double b = fabs ( x._value ); - double err = diff / ( (a<b) ? b : a ); - - // 4. test if we have opposite signs: - if ( _value * x._value < 0.0 ) { - - // the original error gives err in ]1;2] : we check if |x-y| < 1 - // and if so we return |x-y| : - if ( diff < 1.0 ) - return diff; - } - - // we return the original error: - return err; + if ( !_defined || !x._defined ) + throw Not_Defined ( "Double.cpp" , __LINE__ , + "NOMAD::Double::rel_err(): one of the values is not defined" ); + + // 1. test if x==y: + if ( this == &x || _value == x._value ) + return 0.0; + + double diff = fabs ( _value - x._value ); + + // 2. test if one of the values is zero: + if ( _value == 0.0 || x._value == 0.0 ) { + + // we return min{2,|x-y|} (instead of 1): + if ( diff > 2.0 ) + return 2.0; + return diff; + } + + // 3. compute the original error: + double a = fabs ( _value ); + double b = fabs ( x._value ); + double err = diff / ( (a<b) ? b : a ); + + // 4. test if we have opposite signs: + if ( _value * x._value < 0.0 ) { + + // the original error gives err in ]1;2] : we check if |x-y| < 1 + // and if so we return |x-y| : + if ( diff < 1.0 ) + return diff; + } + + // we return the original error: + return err; } @@ -669,22 +672,22 @@ const NOMAD::Double NOMAD::Double::rel_err ( const Double & x ) const /*---------------------------------------------------------------------*/ bool NOMAD::Double::comp_with_undef ( const NOMAD::Double & d ) const { - if ( this == &d ) - return false; - - bool d1d = is_defined(); - bool d2d = d.is_defined(); - - if ( !d1d && !d2d ) - return false; - - if ( !d1d ) - return true; - - if ( !d2d ) - return false; - - return ( *this < d ); + if ( this == &d ) + return false; + + bool d1d = is_defined(); + bool d2d = d.is_defined(); + + if ( !d1d && !d2d ) + return false; + + if ( !d1d ) + return true; + + if ( !d2d ) + return false; + + return ( *this < d ); } /*------------------------------------*/ @@ -692,23 +695,23 @@ bool NOMAD::Double::comp_with_undef ( const NOMAD::Double & d ) const /* ( *this = ref + k * delta ) */ /*------------------------------------*/ void NOMAD::Double::project_to_mesh ( const NOMAD::Double & ref , - const NOMAD::Double & delta , - const NOMAD::Double & lb , - const NOMAD::Double & ub ) -{ - if ( !_defined ) - return; - - NOMAD::Double v0 = ( ref._defined ) ? ref : 0.0; - - if ( delta._defined && delta != 0.0 ) { - - *this = v0 + ( (*this-v0) / delta).round() * delta; - - if ( ub._defined && *this > ub ) - *this = ub; - - if ( lb._defined && *this < lb ) - *this = lb; - } + const NOMAD::Double & delta , + const NOMAD::Double & lb , + const NOMAD::Double & ub ) +{ + if ( !_defined ) + return; + + NOMAD::Double v0 = ( ref._defined ) ? ref : 0.0; + + if ( delta._defined && delta != 0.0 ) { + + *this = v0 + ( (*this-v0) / delta).round() * delta; + + if ( ub._defined && *this > ub ) + *this = ub; + + if ( lb._defined && *this < lb ) + *this = lb; + } } diff --git a/src/Double.hpp b/src/Double.hpp index 3050710..5a9cf7f 100644 --- a/src/Double.hpp +++ b/src/Double.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Eval_Point.cpp b/src/Eval_Point.cpp index 02ddbe7..fa193fe 100644 --- a/src/Eval_Point.cpp +++ b/src/Eval_Point.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Eval_Point.cpp - \brief Evaluation point (implementation) - \author Sebastien Le Digabel - \date 2010-04-14 - \see Eval_Point.hpp -*/ + \file Eval_Point.cpp + \brief Evaluation point (implementation) + \author Sebastien Le Digabel + \date 2010-04-14 + \see Eval_Point.hpp + */ #include "Cache_File_Point.hpp" #include "Eval_Point.hpp" #include "Slave.hpp" @@ -48,25 +48,25 @@ /* static members initialization */ /*-----------------------------------*/ int NOMAD::Eval_Point::_current_tag = 0; - +int NOMAD::Eval_Point::_current_bbe = 0; +int NOMAD::Eval_Point::_current_sgte_bbe = 0; /*---------------------------------------------------------------------*/ /* constructor 1 */ /*---------------------------------------------------------------------*/ NOMAD::Eval_Point::Eval_Point ( void ) - : _tag ( NOMAD::Eval_Point::_current_tag++ ) , - _signature ( NULL ) , - _in_cache ( false ) , - _current_run ( false ) , - _eval_type ( NOMAD::TRUTH ) , - _direction ( NULL ) , - _mesh_index ( NULL ) , - _poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ) , - _eval_status ( NOMAD::UNDEFINED_STATUS ) , - _EB_ok ( true ) +: _tag ( NOMAD::Eval_Point::_current_tag++ ) , +_signature ( NULL ) , +_in_cache ( false ) , +_current_run ( false ) , +_eval_type ( NOMAD::TRUTH ) , +_direction ( NULL ) , +_poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ) , +_eval_status ( NOMAD::UNDEFINED_STATUS ) , +_EB_ok ( true ) { #ifdef MODEL_STATS - _mod_use = -1; - _nY = -1; + _mod_use = -1; + _nY = -1; #endif } @@ -74,22 +74,21 @@ NOMAD::Eval_Point::Eval_Point ( void ) /* constructor 2 */ /*---------------------------------------------------------------------*/ NOMAD::Eval_Point::Eval_Point ( int n , int m ) - : NOMAD::Point ( n ) , - _tag ( NOMAD::Eval_Point::_current_tag++ ) , - _signature ( NULL ) , - _in_cache ( false ) , - _current_run ( false ) , - _eval_type ( NOMAD::TRUTH ) , - _direction ( NULL ) , - _mesh_index ( NULL ) , - _poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ) , - _eval_status ( NOMAD::UNDEFINED_STATUS ) , - _EB_ok ( true ) , - _bb_outputs ( m ) +: NOMAD::Point ( n ) , +_tag ( NOMAD::Eval_Point::_current_tag++ ) , +_signature ( NULL ) , +_in_cache ( false ) , +_current_run ( false ) , +_eval_type ( NOMAD::TRUTH ) , +_direction ( NULL ) , +_poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ) , +_eval_status ( NOMAD::UNDEFINED_STATUS ) , +_EB_ok ( true ) , +_bb_outputs ( m ) { #ifdef MODEL_STATS - _mod_use = -1; - _nY = -1; + _mod_use = -1; + _nY = -1; #endif } @@ -99,12 +98,11 @@ NOMAD::Eval_Point::Eval_Point ( int n , int m ) NOMAD::Eval_Point::Eval_Point ( const NOMAD::Point & x , int m ) : NOMAD::Point ( x ) , _direction ( NULL ) , -_mesh_index ( NULL ) , _bb_outputs ( m ) { #ifdef MODEL_STATS - _mod_use = -1; - _nY = -1; + _mod_use = -1; + _nY = -1; #endif } @@ -115,40 +113,39 @@ _bb_outputs ( m ) /* constructor 4 ( used in Cache::load() ) */ /*---------------------------------------------------------------------*/ NOMAD::Eval_Point::Eval_Point ( const NOMAD::Cache_File_Point & x , NOMAD::eval_type et ) - : NOMAD::Point ( x.get_n() ) , - _tag ( NOMAD::Eval_Point::_current_tag++ ) , - _signature ( NULL ) , - _in_cache ( false ) , - _current_run ( false ) , - _eval_type ( et ) , - _direction ( NULL ) , - _mesh_index ( NULL ) , - _poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ) , - _EB_ok ( true ) , - _bb_outputs ( x.get_bb_outputs() ) +: NOMAD::Point ( x.get_n() ) , +_tag ( NOMAD::Eval_Point::_current_tag++ ) , +_signature ( NULL ) , +_in_cache ( false ) , +_current_run ( false ) , +_eval_type ( et ) , +_direction ( NULL ) , +_poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ) , +_EB_ok ( true ) , +_bb_outputs ( x.get_bb_outputs() ) { - int n = size(); - for ( int i = 0 ; i < n ; ++i ) - (*this)[i] = x.get_coord(i); - - switch ( x.get_eval_status() ) { - case 0: - _eval_status = NOMAD::EVAL_FAIL; - break; - case 1: - _eval_status = NOMAD::EVAL_OK; - break; - case 2: - _eval_status = NOMAD::EVAL_IN_PROGRESS; - break; - case 3: - _eval_status = NOMAD::UNDEFINED_STATUS; - break; - } - + int n = size(); + for ( int i = 0 ; i < n ; ++i ) + (*this)[i] = x.get_coord(i); + + switch ( x.get_eval_status() ) { + case 0: + _eval_status = NOMAD::EVAL_FAIL; + break; + case 1: + _eval_status = NOMAD::EVAL_OK; + break; + case 2: + _eval_status = NOMAD::EVAL_IN_PROGRESS; + break; + case 3: + _eval_status = NOMAD::UNDEFINED_STATUS; + break; + } + #ifdef MODEL_STATS - _mod_use = -1; - _nY = -1; + _mod_use = -1; + _nY = -1; #endif } @@ -157,40 +154,33 @@ NOMAD::Eval_Point::Eval_Point ( const NOMAD::Cache_File_Point & x , NOMAD::eval_ /* copy constructor */ /*---------------------------------------------------------------------*/ NOMAD::Eval_Point::Eval_Point ( const Eval_Point & x ) - : NOMAD::Point ( x.get_n() ) , - _tag ( NOMAD::Eval_Point::_current_tag++ ) , - _signature ( x._signature ) , - _f ( x._f ) , - _h ( x._h ) , - _in_cache ( x._in_cache ) , - _current_run ( x._current_run ) , - _eval_type ( x._eval_type ) , - _direction ( NULL ) , - _mesh_index ( NULL ) , - _poll_center_type ( x._poll_center_type ) , - _eval_status ( x._eval_status ) , - _EB_ok ( x._EB_ok ) , - _bb_outputs ( x.get_bb_outputs() ) , - _user_eval_priority ( x._user_eval_priority ) , - _rand_eval_priority ( x._rand_eval_priority ) -{ - // point coordinates: - int n = size(); - for ( int i = 0 ; i < n ; ++i ) - (*this)[i] = x[i]; - - // _direction: - if ( x._direction ) - _direction = new Direction ( *x._direction ); - - // _mesh_index: - if ( x._mesh_index ) { - _mesh_index = new int; - *_mesh_index = *x._mesh_index; - } - +: NOMAD::Point ( x.get_n() ) , +_tag ( NOMAD::Eval_Point::_current_tag++ ) , +_signature ( x._signature ) , +_f ( x._f ) , +_h ( x._h ) , +_in_cache ( x._in_cache ) , +_current_run ( x._current_run ) , +_eval_type ( x._eval_type ) , +_direction ( NULL ) , +_poll_center_type ( x._poll_center_type ) , +_eval_status ( x._eval_status ) , +_EB_ok ( x._EB_ok ) , +_bb_outputs ( x.get_bb_outputs() ) , +_user_eval_priority ( x._user_eval_priority ) , +_rand_eval_priority ( x._rand_eval_priority ) +{ + // point coordinates: + int n = size(); + for ( int i = 0 ; i < n ; ++i ) + (*this)[i] = x[i]; + + // _direction: + if ( x._direction ) + _direction = new Direction ( *x._direction ); + #ifdef MODEL_STATS - set_model_data ( x ); + set_model_data ( x ); #endif } @@ -199,10 +189,8 @@ NOMAD::Eval_Point::Eval_Point ( const Eval_Point & x ) /*---------------------------------------------------------------------*/ NOMAD::Eval_Point::~Eval_Point ( void ) { - if (_mesh_index) - delete _mesh_index; - if (_direction) - delete _direction; + if ( _direction ) + delete _direction; } /*-------------------------------------------------------*/ @@ -210,14 +198,14 @@ NOMAD::Eval_Point::~Eval_Point ( void ) /*-------------------------------------------------------*/ void NOMAD::Eval_Point::set ( int n , int m ) { - reset ( n ); - _bb_outputs.reset ( m ); + reset ( n ); + _bb_outputs.reset ( m ); } void NOMAD::Eval_Point::set ( const NOMAD::Point & x , int m ) { - NOMAD::Point::operator = ( x ); - _bb_outputs.reset ( m ); + NOMAD::Point::operator = ( x ); + _bb_outputs.reset ( m ); } /*-------------------------------------------------------*/ @@ -227,32 +215,41 @@ void NOMAD::Eval_Point::set ( const NOMAD::Point & x , int m ) /*-------------------------------------------------------*/ void NOMAD::Eval_Point::set_tag ( int tag ) { - _tag = tag; - NOMAD::Eval_Point::_current_tag = tag+1; + _tag = tag; + NOMAD::Eval_Point::_current_tag = tag+1; } -/*---------------------------------------------------------------------*/ -/* SET methods for _direction and _mesh_index */ -/*---------------------------------------------------------------------*/ -void NOMAD::Eval_Point::set_mesh_index ( const int * ell ) +/*-------------------------------------------------------*/ +/* increment counted black box evaluations */ +/* All points have unique tags */ +/*-------------------------------------------------------*/ +void NOMAD::Eval_Point::increment_bbe ( void ) +{ + NOMAD::Eval_Point::_current_bbe ++; + _bbe=_current_bbe; +} + + +/*-------------------------------------------------------*/ +/* increment counted black box evaluations */ +/* All points have unique tags */ +/*-------------------------------------------------------*/ +void NOMAD::Eval_Point::increment_sgte_bbe ( void ) { - delete _mesh_index; - _mesh_index = NULL; - if ( ell ) { - _mesh_index = new int; - *_mesh_index = *ell; - } + NOMAD::Eval_Point::_current_sgte_bbe ++; + _sgte_bbe=_current_sgte_bbe; } + void NOMAD::Eval_Point::set_direction ( const NOMAD::Direction * dir ) { - delete _direction; - _direction = ( dir ) ? new NOMAD::Direction ( *dir ) : NULL; + delete _direction; + _direction = ( dir ) ? new NOMAD::Direction ( *dir ) : NULL; } void NOMAD::Eval_Point::set_poll_center ( const NOMAD::Eval_Point * pc ) { - _poll_center=pc; + _poll_center=pc; } /*-------------------------------------------------------*/ @@ -260,16 +257,16 @@ void NOMAD::Eval_Point::set_poll_center ( const NOMAD::Eval_Point * pc ) /*-------------------------------------------------------*/ void NOMAD::Eval_Point::set_signature ( NOMAD::Signature * s ) { - if ( !s ) { - _signature = NULL; - return; - } - - if ( !s->is_compatible(*this) ) - throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , - "x.Eval_Point::set_signature(s): x and s are incompatible" ); - - _signature = s; + if ( !s ) { + _signature = NULL; + return; + } + + if ( !s->is_compatible(*this) ) + throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , + "x.Eval_Point::set_signature(s): x and s are incompatible" ); + + _signature = s; } /*------------------------------------------*/ @@ -278,11 +275,11 @@ void NOMAD::Eval_Point::set_signature ( NOMAD::Signature * s ) NOMAD::Signature * NOMAD::Eval_Point::get_signature ( void ) const { #ifdef USE_MPI - if ( !NOMAD::Slave::is_master() ) - throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , - "Eval_Point::get_signature(): cannot be invoked by slave processes" ); + if ( !NOMAD::Slave::is_master() ) + throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , + "Eval_Point::get_signature(): cannot be invoked by slave processes" ); #endif - return _signature; + return _signature; } /*-------------------------------------------------------*/ @@ -290,7 +287,7 @@ NOMAD::Signature * NOMAD::Eval_Point::get_signature ( void ) const /*-------------------------------------------------------*/ int NOMAD::Eval_Point::size_of ( void ) const { - return NOMAD::Point::size_of () + + return NOMAD::Point::size_of () + _bb_outputs.size_of () + _f.size_of () + _h.size_of () + @@ -303,10 +300,8 @@ int NOMAD::Eval_Point::size_of ( void ) const sizeof (_eval_type ) + sizeof (_eval_status ) + sizeof (_EB_ok ) + - sizeof (_mesh_index ) + sizeof (_direction ) + - (( _mesh_index ) ? sizeof(*_mesh_index) : 0) + - ((_direction ) ? _direction->size_of() : 0); + ((_direction ) ? _direction->size_of() : 0); } /*-------------------------------------------------------*/ @@ -314,10 +309,10 @@ int NOMAD::Eval_Point::size_of ( void ) const /*-------------------------------------------------------*/ void NOMAD::Eval_Point::scale ( void ) { - if ( !_signature ) - throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , - "x.Eval_Point::scale(): x has no signature" ); - _signature->scale ( *this ); + if ( !_signature ) + throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , + "x.Eval_Point::scale(): x has no signature" ); + _signature->scale ( *this ); } /*-------------------------------------------------------*/ @@ -325,10 +320,10 @@ void NOMAD::Eval_Point::scale ( void ) /*-------------------------------------------------------*/ void NOMAD::Eval_Point::unscale ( void ) { - if ( !_signature ) - throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , - "x.Eval_Point::unscale(): x has no signature" ); - _signature->unscale ( *this ); + if ( !_signature ) + throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , + "x.Eval_Point::unscale(): x has no signature" ); + _signature->unscale ( *this ); } /*-------------------------------------------------------*/ @@ -337,10 +332,10 @@ void NOMAD::Eval_Point::unscale ( void ) /*-------------------------------------------------------*/ bool NOMAD::Eval_Point::snap_to_bounds ( void ) { - if ( !_signature ) - throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , - "x.Eval_Point::snap_to_bounds(): x has no signature" ); - return _signature->snap_to_bounds ( *this , _direction ); + if ( !_signature ) + throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , + "x.Eval_Point::snap_to_bounds(): x has no signature" ); + return _signature->snap_to_bounds ( *this , _direction ); } /*-------------------------------------------------------*/ @@ -349,11 +344,11 @@ bool NOMAD::Eval_Point::snap_to_bounds ( void ) /*-------------------------------------------------------*/ bool NOMAD::Eval_Point::treat_periodic_variables ( NOMAD::Direction *& new_dir ) { - if (!_signature) - throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , - "x.Eval_Point::treat_periodic_variables(): x has no signature" ); - - return _signature->treat_periodic_variables ( *this , _direction , new_dir ); + if (!_signature) + throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , + "x.Eval_Point::treat_periodic_variables(): x has no signature" ); + + return _signature->treat_periodic_variables ( *this , _direction , new_dir ); } /*--------------------------------------------------*/ @@ -361,69 +356,72 @@ bool NOMAD::Eval_Point::treat_periodic_variables ( NOMAD::Direction *& new_dir ) /*--------------------------------------------------*/ bool NOMAD::Eval_Point::check ( int m , NOMAD::check_failed_type & cf ) const { - if ( size() <= 0 || !_signature || m != _bb_outputs.size() ) { - std::string err = "Eval_Point::check() could not procede"; - if ( !_signature ) - err += " (no signature)"; - else if ( m != _bb_outputs.size() ) - err += " (wrong number of blackbox outputs)"; - else - err += " (point size <= 0 !)"; - throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , err ); - } - - cf = NOMAD::CHECK_OK; - - const std::vector<NOMAD::bb_input_type> - & input_types = _signature->get_input_types(); - const NOMAD::Point & lb = _signature->get_lb(); - const NOMAD::Point & ub = _signature->get_ub(); - const NOMAD::Point & fv = _signature->get_fixed_variables(); - int n = size(); - NOMAD::bb_input_type iti; - - for ( int i = 0 ; i < n ; ++i ) { - - const NOMAD::Double xi = (*this)[i]; - - // undefined coordinates ? - if ( !xi.is_defined() ) - throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , - "Eval_Point::check() could not procede (undefined coordinates)" ); - - // check the bounds: - const NOMAD::Double & lbi = lb[i]; - if ( lbi.is_defined() && xi < lbi ) { - cf = NOMAD::LB_FAIL; - return false; - } - - const NOMAD::Double & ubi = ub[i]; - if ( ubi.is_defined() && xi > ubi ) { - cf = NOMAD::UB_FAIL; - return false; + if ( size() <= 0 || !_signature || m != _bb_outputs.size() ) { + std::string err = "Eval_Point::check() could not procede"; + if ( !_signature ) + err += " (no signature)"; + else if ( m != _bb_outputs.size() ) + err += " (wrong number of blackbox outputs)"; + else + err += " (point size <= 0 !)"; + throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , err ); } - - // check the integer/categorical/binary variables: - iti = input_types[i]; - if ( iti == NOMAD::BINARY && !xi.is_binary() ) { - cf = NOMAD::BIN_FAIL; - return false; - } - if ( ( iti == NOMAD::INTEGER || iti == NOMAD::CATEGORICAL ) - && !xi.is_integer() ) { - cf = ( iti == NOMAD::INTEGER ) ? NOMAD::INT_FAIL : NOMAD::CAT_FAIL; - return false; + + cf = NOMAD::CHECK_OK; + + const std::vector<NOMAD::bb_input_type> + & input_types = _signature->get_input_types(); + const NOMAD::Point & lb = _signature->get_lb(); + const NOMAD::Point & ub = _signature->get_ub(); + const NOMAD::Point & fv = _signature->get_fixed_variables(); + int n = size(); + NOMAD::bb_input_type iti; + + for ( int i = 0 ; i < n ; ++i ) + { + + const NOMAD::Double xi = (*this)[i]; + + // undefined coordinates ? + if ( !xi.is_defined() ) + throw NOMAD::Exception ( "Eval_Point.cpp" , __LINE__ , + "Eval_Point::check() could not procede (undefined coordinates)" ); + + // check the bounds: + const NOMAD::Double & lbi = lb[i]; + if ( lbi.is_defined() && xi < lbi ) + { + cf = NOMAD::LB_FAIL; + return false; + } + + const NOMAD::Double & ubi = ub[i]; + if ( ubi.is_defined() && xi > ubi ) + { + cf = NOMAD::UB_FAIL; + return false; + } + + // check the integer/categorical/binary variables: + iti = input_types[i]; + if ( iti == NOMAD::BINARY && !xi.is_binary() ) { + cf = NOMAD::BIN_FAIL; + return false; + } + if ( ( iti == NOMAD::INTEGER || iti == NOMAD::CATEGORICAL ) + && !xi.is_integer() ) { + cf = ( iti == NOMAD::INTEGER ) ? NOMAD::INT_FAIL : NOMAD::CAT_FAIL; + return false; + } + + // check the fixed-variables: + const NOMAD::Double & fvi = fv[i]; + if ( fvi.is_defined() && fvi != xi ) { + cf = NOMAD::FIX_VAR_FAIL; + return false; + } } - - // check the fixed-variables: - const NOMAD::Double & fvi = fv[i]; - if ( fvi.is_defined() && fvi != xi ) { - cf = NOMAD::FIX_VAR_FAIL; - return false; - } - } - return true; + return true; } /*--------------------------------------------------*/ @@ -431,44 +429,44 @@ bool NOMAD::Eval_Point::check ( int m , NOMAD::check_failed_type & cf ) const /*--------------------------------------------------*/ void NOMAD::Eval_Point::display_tag ( const NOMAD::Display & out ) const { - out << "#"; - out.display_int_w ( _tag , NOMAD::Eval_Point::_current_tag ); + out << "#"; + out.display_int_w ( _tag , NOMAD::Eval_Point::_current_tag ); } /*--------------------------------------------------*/ /* display */ /*--------------------------------------------------*/ -void NOMAD::Eval_Point::display ( const NOMAD::Display & out , bool in_block ) const +void NOMAD::Eval_Point::display_eval( const NOMAD::Display & out , bool in_block ) const { - if ( in_block ) { - - std::ostringstream oss; - oss << "#" << _tag; - out << NOMAD::open_block ( oss.str() ) - << "x = ( "; - NOMAD::Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl - << "F(x) = [ "; - _bb_outputs.display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); - out << " ]" << std::endl; - if ( _h.is_defined() ) - out << "h = " << _h << std::endl; - if ( _f.is_defined() ) - out << "f = " << _f << std::endl; - out.close_block(); - } - else { - display_tag ( out ); - out << " x=( "; - NOMAD::Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); - out << " ) F(x)=[ "; - _bb_outputs.display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); - out << " ]"; - if ( _h.is_defined() ) - out << " h=" << _h; - if ( _f.is_defined() ) - out << " f=" << _f; - } + if ( in_block ) { + + std::ostringstream oss; + oss << "#" << _tag; + out << NOMAD::open_block ( oss.str() ) + << "x = ( "; + NOMAD::Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl + << "F(x) = [ "; + _bb_outputs.display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); + out << " ]" << std::endl; + if ( _h.is_defined() ) + out << "h = " << _h << std::endl; + if ( _f.is_defined() ) + out << "f = " << _f << std::endl; + out.close_block(); + } + else { + display_tag ( out ); + out << " x=( "; + NOMAD::Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); + out << " ) F(x)=[ "; + _bb_outputs.display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); + out << " ]"; + if ( _h.is_defined() ) + out << " h=" << _h; + if ( _f.is_defined() ) + out << " f=" << _f; + } } /*--------------------------------------------------------------*/ @@ -477,21 +475,21 @@ void NOMAD::Eval_Point::display ( const NOMAD::Display & out , bool in_block ) c /*--------------------------------------------------------------*/ bool NOMAD::Eval_Point::operator < ( const NOMAD::Eval_Point & x ) const { - if ( this == &x || !is_eval_ok() || !_EB_ok ) + if ( this == &x || !is_eval_ok() || !_EB_ok ) + return false; + + double h = _h.value(); + double f = _f.value(); + double hx = x._h.value(); + double fx = x._f.value(); + + if ( h < hx ) + return ( f <= fx ); + + if ( h == hx ) + return ( f < fx ); + return false; - - double h = _h.value(); - double f = _f.value(); - double hx = x._h.value(); - double fx = x._f.value(); - - if ( h < hx ) - return ( f <= fx ); - - if ( h == hx ) - return ( f < fx ); - - return false; } /*--------------------------------------------------------------*/ @@ -499,19 +497,19 @@ bool NOMAD::Eval_Point::operator < ( const NOMAD::Eval_Point & x ) const /*--------------------------------------------------------------*/ bool NOMAD::Eval_Point::check_nan ( void ) const { - int m = _bb_outputs.size(); - for ( int i = 0 ; i < m ; ++i ) { - if ( _bb_outputs[i].is_defined() ) { + int m = _bb_outputs.size(); + for ( int i = 0 ; i < m ; ++i ) { + if ( _bb_outputs[i].is_defined() ) { #ifdef WINDOWS - if ( isnan ( _bb_outputs[i].value() ) ) - return true; + if ( isnan ( _bb_outputs[i].value() ) ) + return true; #else - if ( std::isnan ( _bb_outputs[i].value() ) ) - return true; + if ( std::isnan ( _bb_outputs[i].value() ) ) + return true; #endif + } } - } - return false; + return false; } #ifdef MODEL_STATS @@ -521,12 +519,12 @@ bool NOMAD::Eval_Point::check_nan ( void ) const /*--------------------------------------------------------------*/ void NOMAD::Eval_Point::set_model_data ( const NOMAD::Eval_Point & x ) const { - _mod_use = x._mod_use; - _nY = x._nY; - _cond = x._cond; - _Yw = x._Yw; - _mh = x._mh; - _mf = x._mf; + _mod_use = x._mod_use; + _nY = x._nY; + _cond = x._cond; + _Yw = x._Yw; + _mh = x._mh; + _mf = x._mf; } /*--------------------------------------------------------------*/ @@ -534,12 +532,12 @@ void NOMAD::Eval_Point::set_model_data ( const NOMAD::Eval_Point & x ) const /*--------------------------------------------------------------*/ void NOMAD::Eval_Point::clear_model_data ( void ) const { - _mod_use = -1; - _nY = -1; - _cond.clear(); - _Yw.clear(); - _mh.clear(); - _mf.clear(); + _mod_use = -1; + _nY = -1; + _cond.clear(); + _Yw.clear(); + _mh.clear(); + _mf.clear(); } #endif diff --git a/src/Eval_Point.hpp b/src/Eval_Point.hpp index 72e204f..6418403 100644 --- a/src/Eval_Point.hpp +++ b/src/Eval_Point.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Eval_Point.hpp - \brief Evaluation point (headers) - \author Sebastien Le Digabel - \date 2010-04-14 - \see Eval_Point.cpp -*/ + \file Eval_Point.hpp + \brief Evaluation point (headers) + \author Sebastien Le Digabel + \date 2010-04-14 + \see Eval_Point.cpp + */ #ifndef __EVAL_POINT__ #define __EVAL_POINT__ @@ -47,527 +47,570 @@ #include "Cache_File_Point.hpp" #include "Set_Element.hpp" -#ifdef WINDOWS +#ifdef WINDOWS #ifndef isnan inline bool isnan ( double x ) { return x != x; } #endif #endif namespace NOMAD { - - /// Class for the representation of an evaluation point. - /** - An evaluation point gathers the point coordinates \c x, and the blackbox - outputs at these coordinates \c f(x). - */ - class Eval_Point : public NOMAD::Point { - - private: - static int _current_tag; ///< Current tag for all NOMAD::Eval_Point objects. - int _tag; ///< Unique tag. - - NOMAD::Signature * _signature; ///< Signature of the point. - - /** - \c f is explicitely computed by a NOMAD::Evaluator object - and is not saved in the cache file. - */ - NOMAD::Double _f; - - /** - \c h is explicitely computed by a NOMAD::Evaluator object - and is not saved in the cache file. - */ - NOMAD::Double _h; - - /// Flag equal to \c true if this eval point is in the cache. - mutable bool _in_cache; - - /** - Flag equal to \c true if the point has been evaluated - during the current run. - */ - mutable bool _current_run; - - /// Type of the evaluation (true function or surrogate). - NOMAD::eval_type _eval_type; - - /// Direction from which the point has been constructed. - /** - May be \c NULL if no direction has been used. - */ - NOMAD::Direction * _direction; - - - /// Poll center from which the point has been constructed. - /** - May be \c NULL if no direction has been used. - */ - const NOMAD::Eval_Point * _poll_center; - - /** - - Pointer to the Mesh index \c ell from which - the point has been constructed. - - May be \c NULL if no mesh index has been used. - */ - int * _mesh_index; - - /** - Type of the poll center (feasible or not) - from which the point has been constructed. - */ - NOMAD::poll_center_type _poll_center_type; - - /// Evaluation status. + /// Class for the representation of an evaluation point. /** - Indicates if the evaluation failed, succeeded, - or is in progress. - */ - NOMAD::eval_status_type _eval_status; - - /// Flag equal to \c true if all EB constraints have been satisfied. - bool _EB_ok; - - /// Blackbox outputs. - NOMAD::Point _bb_outputs; - - /// User evaluation priority. - /** - - Decided by the user in his custom + An evaluation point gathers the point coordinates \c x, and the blackbox + outputs at these coordinates \c f(x). + */ + class Eval_Point : public NOMAD::Point { + + private: + + static int _current_tag; ///< Current tag for all NOMAD::Eval_Point objects. + int _tag; ///< Unique tag. + + static int _current_bbe; ///< Current bbe for all NOMAD::Eval_Point objects + static int _current_sgte_bbe; ///< Current sgte_bbe for all NOMAD::Eval_Point objects . + int _bbe; /// Recorded bbe for current NOMAD::Eval_Point object + int _sgte_bbe; /// Recorded sgte_bbe for current NOMAD::Eval_Point object + int _real_time; /// Recorded time for current NOMAD::Eval_Point object + + NOMAD::Signature * _signature; ///< Signature of the point. + + /** + \c f is explicitely computed by a NOMAD::Evaluator object + and is not saved in the cache file. + */ + NOMAD::Double _f; + + /** + \c h is explicitely computed by a NOMAD::Evaluator object + and is not saved in the cache file. + */ + NOMAD::Double _h; + + /// Flag equal to \c true if this eval point is in the cache. + mutable bool _in_cache; + + /** + Flag equal to \c true if the point has been evaluated + during the current run. + */ + mutable bool _current_run; + + /// Type of the evaluation (true function or surrogate). + NOMAD::eval_type _eval_type; + + /// Direction from which the point has been constructed. + /** + May be \c NULL if no direction has been used. + */ + NOMAD::Direction * _direction; + + + /// Poll center from which the point has been constructed. + /** + May be \c NULL if no direction has been used. + */ + const NOMAD::Eval_Point * _poll_center; + + /** + Type of the poll center (feasible or not) + from which the point has been constructed. + */ + NOMAD::poll_center_type _poll_center_type; + + /// Evaluation status. + /** + Indicates if the evaluation failed, succeeded, + or is in progress. + */ + NOMAD::eval_status_type _eval_status; + + /// Flag equal to \c true if all EB constraints have been satisfied. + bool _EB_ok; + + /// Blackbox outputs. + NOMAD::Point _bb_outputs; + + /// User evaluation priority. + /** + - Decided by the user in his custom NOMAD::Evaluator::eval_x() function, via \c set_user_eval_priority(). - - Points with higher priorities + - Points with higher priorities will be evaluated first. - */ - NOMAD::Double _user_eval_priority; - - /// Random evaluation priority. - /** - Same idea than \c _user_eval_priority - for a random ordering of trial points. - */ - NOMAD::Double _rand_eval_priority; - - /// Affectation operator. - /** - \param x The right-hand side object -- \b IN. - \return \c *this as the result of the affectation. - */ - Eval_Point & operator = ( const Eval_Point & x ); - - public: - - /// Constructor #1. - explicit Eval_Point ( void ); - - /// Constructor #2. - /** - \param n Number of variables -- \b IN. - \param m Number of blackbox outputs -- \b IN. - */ - Eval_Point ( int n , int m ); - - /// Constructor #3. - /** - \param x Coordinates of a point taken in a cache -- \b IN. - \param et Type of the evaluation (true or surrogate) -- \b IN. - */ - explicit Eval_Point ( const NOMAD::Cache_File_Point & x , - NOMAD::eval_type et ); - - - ///Constructor 4 - /** - \param x Coordinates of a point -- \b IN. - \param m Number of blackbox outputs -- \b IN. - */ - explicit Eval_Point ( const NOMAD::Point & x, int m ) ; - - - - /// Copy constructor. - /** - \param x The copied object. - */ - explicit Eval_Point ( const Eval_Point & x ); - - /// Destructor. - virtual ~Eval_Point ( void ); - - /// Check the evaluation point. - /** - \param m Number of blackbox outputs -- \b IN. - \param cf The reason for a check failure -- \b OUT. - \return A boolean equal to \c true if the point is valid. - */ - bool check ( int m , NOMAD::check_failed_type & cf ) const; - - /*---------------*/ - /* GET methods */ - /*---------------*/ - - /// Size of the point in memory. - /** - \return Size of the point in memory, in bytes. - */ - virtual int size_of ( void ) const; - - /// Access to the signature of the point. - /** - \return A pointer to the signature of the point. - */ - NOMAD::Signature * get_signature ( void ) const; - - /// Access to the number of blackbox outputs. - /** - \return Number of blackbox outputs. - */ - int get_m ( void ) const { return _bb_outputs.size(); } - - /// Access to the number of variables. - /** - \return Number of variables. - */ - int get_n ( void ) const { return size(); } - - /// Check if the evaluation at this point is valid. - /** - \return A boolean equal to \c true if the evaluation is valid. - */ - bool is_eval_ok ( void ) const { return (_eval_status == NOMAD::EVAL_OK); } - - /// Access to the tag of the point. - /** - \return The tag. - */ - int get_tag ( void ) const { return _tag; } - - /// Access to the objective value \c f. - /** - \return The objective value. - */ - const NOMAD::Double & get_f ( void ) const { return _f; } - - /// Access to the feasibility value \c h. - /** - \return The feasibility value. - */ - const NOMAD::Double & get_h ( void ) const { return _h; } - - /// Access to the blackbox outputs. - /** - \return The \c m blackblack outputs. - */ - const NOMAD::Point & get_bb_outputs ( void ) const { return _bb_outputs; } - - /// Access to the direction used to construct the point. - /** - \return The direction used to construct the point; - may be \c NULL if no direction has been used. - */ - const NOMAD::Direction * get_direction ( void ) const { return _direction; } - - /// Access to the poll_center used to construct the point. - /** - \return The poll center used to construct the point; - may be \c NULL if no poll center has been used. - */ - const NOMAD::Eval_Point * get_poll_center ( void ) const { return _poll_center ; } - - /// Access to the mesh index \c ell used to construct the point. - /** - \return A pointer to the mesh index value; - may be \c NULL if no mesh index was used. - */ - const int * get_mesh_index ( void ) const { return _mesh_index; } - - /// Check if the point has been generated during the current run. - /** - \return A boolean equal to \c true if the point has been - generated during the current run. - */ - bool get_current_run ( void ) const { return _current_run; } - - /// Check if the point is in cache. - /** - \return A boolean equal to \c true if the point is in cache. - */ - bool is_in_cache ( void ) const { return _in_cache; } - - /// Check if the point respects the EB constraints. - /** - \return A boolean equal to \c true if the point respects the EB constraints. - */ - bool is_EB_ok ( void ) const { return _EB_ok; } - - /// Access to the evaluation type. - /** - \return The evaluation type (true or surrogate). - */ - NOMAD::eval_type get_eval_type ( void ) const { return _eval_type; } - - /// Access to the poll center type. - /** - \return The poll center type (feasible or not). - */ - NOMAD::poll_center_type get_poll_center_type ( void ) const - { - return _poll_center_type; - } - - /// Access to the evaluation status. - /** - \return The evaluation status - (evaluation failed, succeeded, or is in progress). - */ - NOMAD::eval_status_type get_eval_status ( void ) const { return _eval_status; } - - /// Access to the user evaluation priority. - /** - \return The user evaluation priority. - */ - const NOMAD::Double & get_user_eval_priority ( void ) const - { - return _user_eval_priority; - } - - /// Access to the random evaluation priority. - /** - \return The random evaluation priority. - */ - const NOMAD::Double & get_rand_eval_priority ( void ) const - { - return _rand_eval_priority; - } - - /// Check the point feasibility. - /** - The point is feasible if \c h \c <= \c h_min. - \param h_min Feasibility threshold -- \b IN. - \return A boolean equal to \c true if the point is feasible. - */ - bool is_feasible ( const NOMAD::Double & h_min ) const - { - return ( _h.is_defined() && _h <= h_min ); - } - - /// Scaling. - void scale ( void ); - - /// Unscaling. - void unscale ( void ); - - /// Snap to bounds. - /** - \return A boolean equal to \c true if the snapping went well. - */ - bool snap_to_bounds ( void ); - - /// Treat the periodic variables. - /** - \param new_dir A pointer to the modified direction used to generate - this point from the poll center; may be \c NULL if no - direction has been used -- \b OUT. - \return A boolean equal to \c true if the treatment went well. - */ - bool treat_periodic_variables ( NOMAD::Direction *& new_dir ); - - /// Comparison operator. - /** - \param x Right-hand side object -- \b IN. - \return A boolean equal to \c true if \c *this \c < \c x . - */ - bool operator < ( const Eval_Point & x ) const; - - /*---------------*/ - /* SET methods */ - /*---------------*/ - - /// Set the \c n and \c m. - /** - \param n Number of variables -- \b IN. - \param m Number of blackbox outputs -- \b IN. - */ - void set ( int n , int m ); - - /// Set the coordinates and \c m. - /** - \param x Coordinates of the point -- \b IN. - \param m Number of blackbox outputs -- \b IN. - */ - void set ( const NOMAD::Point & x , int m ); - - /// Set the tag. - /** - \param tag The tag -- \b IN. - */ - void set_tag ( int tag ); - - /// Set the objective value \c f. - /** - \param f Objective value -- \b IN. - */ - void set_f ( const NOMAD::Double & f ) { _f = f; } - - /// Set the feasibility value \c h. - /** - \param h Feasibility value -- \b IN. - */ - void set_h ( const NOMAD::Double & h ) { _h = h; } - - /// Set the user evaluation priority. - /** - \param u User evaluation priority -- \b IN. - */ - void set_user_eval_priority ( const NOMAD::Double & u ) { _user_eval_priority = u; } - - /// Set the random evaluation priority. - /** - \param r Random evaluation priority -- \b IN. - */ - void set_rand_eval_priority ( const NOMAD::Double & r ) { _rand_eval_priority = r; } - - /// Set one blackbox output. - /** - \param i Index of the output to set -- \b IN. - \param v Value of the output -- \b IN. - */ - void set_bb_output ( int i , const NOMAD::Double & v ) { _bb_outputs[i]= v; } - - /// Set all blackbox outputs. - /** - \param b The \c m blackbox outputs -- \b IN. - */ - void set_bb_output ( const NOMAD::Point & b ) { _bb_outputs = b; } - - /// Set the evaluation status. - /** - \param e Evaluation status (failed, succeeded, or in progress) - -- \b IN. - */ - void set_eval_status ( const NOMAD::eval_status_type & e ) { _eval_status = e; } - - /// Set if the point respects the EB constraints. - /** - \param e A boolean equal to \c true if the point - respects the EB constraints. - */ - void set_EB_ok ( bool e ) { _EB_ok = e; } - - /// Set the evaluation type. - /** - \param e Evaluation type (true or surrogate) -- \b IN. - */ - void set_eval_type ( NOMAD::eval_type e ) { _eval_type = e; } - - /// Set the type of the poll center. - /** - \param p Type of the poll center (feasible or not) -- \b IN. - */ - void set_poll_center_type ( NOMAD::poll_center_type p ) { _poll_center_type = p; } - - /// Indicate if the point has been generated during the current run. - /** - \param c A boolean equal to \c true if the point - has been generated during the current run -- \b IN. - */ - void set_current_run ( bool c ) const { _current_run = c; } - - /// Indicate if the point is in cache. - /** - \param i A boolean equal to \c true if the point is in cache - -- \b IN. - */ - void set_in_cache ( bool i ) const { _in_cache = i; } - - /// Set the mesh index. - /** - \param ell A pointer to the mesh index; may be \c NULL -- \b IN. - */ - void set_mesh_index ( const int * ell ); - - /// Set the direction used to create the point. - /** - \param d A pointer to the direction; may be \c NULL -- \b IN. - */ - void set_direction ( const NOMAD::Direction * d ); - - - /// Set the poll center used to create the point. - /** - \param d A pointer to the poll center; may be \c NULL -- \b IN. - */ - void set_poll_center ( const NOMAD::Eval_Point * d ); - - /// Set the signature. - /** - \param s A pointer to the signature -- \b IN. - */ - void set_signature ( NOMAD::Signature * s ); - - /// Check if there are nan's in the blackbox outputs: - /** - \return \c true if there is at least a nan. - */ - bool check_nan ( void ) const; - + */ + NOMAD::Double _user_eval_priority; + + /// Random evaluation priority. + /** + Same idea than \c _user_eval_priority + for a random ordering of trial points. + */ + NOMAD::Double _rand_eval_priority; + + /// Affectation operator. + /** + \param x The right-hand side object -- \b IN. + \return \c *this as the result of the affectation. + */ + Eval_Point & operator = ( const Eval_Point & x ); + + public: + + /// Constructor #1. + explicit Eval_Point ( void ); + + /// Constructor #2. + /** + \param n Number of variables -- \b IN. + \param m Number of blackbox outputs -- \b IN. + */ + Eval_Point ( int n , int m ); + + /// Constructor #3. + /** + \param x Coordinates of a point taken in a cache -- \b IN. + \param et Type of the evaluation (true or surrogate) -- \b IN. + */ + explicit Eval_Point ( const NOMAD::Cache_File_Point & x , + NOMAD::eval_type et ); + + + ///Constructor 4 + /** + \param x Coordinates of a point -- \b IN. + \param m Number of blackbox outputs -- \b IN. + */ + explicit Eval_Point ( const NOMAD::Point & x, int m ) ; + + + + /// Copy constructor. + /** + \param x The copied object. + */ + explicit Eval_Point ( const Eval_Point & x ); + + /// Destructor. + virtual ~Eval_Point ( void ); + + /// Check the evaluation point. + /** + \param m Number of blackbox outputs -- \b IN. + \param cf The reason for a check failure -- \b OUT. + \return A boolean equal to \c true if the point is valid. + */ + bool check ( int m , NOMAD::check_failed_type & cf ) const; + + /*---------------*/ + /* GET methods */ + /*---------------*/ + + /// Size of the point in memory. + /** + \return Size of the point in memory, in bytes. + */ + virtual int size_of ( void ) const; + + /// Access to the signature of the point. + /** + \return A pointer to the signature of the point. + */ + NOMAD::Signature * get_signature ( void ) const; + + /// Access to the number of blackbox outputs. + /** + \return Number of blackbox outputs. + */ + int get_m ( void ) const { return _bb_outputs.size(); } + + /// Access to the number of variables. + /** + \return Number of variables. + */ + int get_n ( void ) const { return size(); } + + /// Check if the evaluation at this point is valid. + /** + \return A boolean equal to \c true if the evaluation is valid. + */ + bool is_eval_ok ( void ) const { return (_eval_status == NOMAD::EVAL_OK); } + + /// Check if the evaluation at this point has been rejected by the user. + /** + \return A boolean equal to \c true if the evaluation has been rejected by the user. + */ + bool check_rejected ( void ) const { return (_eval_status == NOMAD::EVAL_USER_REJECT); } + + + /// Access to the tag of the point. + /** + \return The tag. + */ + int get_tag ( void ) const { return _tag; } + + /// Access to the bbe of the point. + /** + \return The bbe. + */ + int get_bbe ( void ) const { return _bbe; } + + /// Access to the bbe of the point. + /** + \return The sgte_bbe. + */ + int get_sgte_bbe ( void ) const { return _sgte_bbe; } + + + /// Access to the real time of the point evaluation. + /** + \return The real time. + */ + int get_real_time( void ) const { return _real_time; } + + + /// Access to the objective value \c f. + /** + \return The objective value. + */ + const NOMAD::Double & get_f ( void ) const { return _f; } + + /// Access to the feasibility value \c h. + /** + \return The feasibility value. + */ + const NOMAD::Double & get_h ( void ) const { return _h; } + + /// Access to the blackbox outputs. + /** + \return The \c m blackblack outputs. + */ + const NOMAD::Point & get_bb_outputs ( void ) const { return _bb_outputs; } + + /// Access to the direction used to construct the point. + /** + \return The direction used to construct the point; + may be \c NULL if no direction has been used. + */ + const NOMAD::Direction * get_direction ( void ) const { return _direction; } + + /// Access to the poll_center used to construct the point. + /** + \return The poll center used to construct the point; + may be \c NULL if no poll center has been used. + */ + const NOMAD::Eval_Point * get_poll_center ( void ) const { return _poll_center ; } + + + /// Check if the point has been generated during the current run. + /** + \return A boolean equal to \c true if the point has been + generated during the current run. + */ + bool get_current_run ( void ) const { return _current_run; } + + /// Check if the point is in cache. + /** + \return A boolean equal to \c true if the point is in cache. + */ + bool is_in_cache ( void ) const { return _in_cache; } + + /// Check if the point respects the EB constraints. + /** + \return A boolean equal to \c true if the point respects the EB constraints. + */ + bool is_EB_ok ( void ) const { return _EB_ok; } + + /// Access to the evaluation type. + /** + \return The evaluation type (true or surrogate). + */ + NOMAD::eval_type get_eval_type ( void ) const { return _eval_type; } + + /// Access to the poll center type. + /** + \return The poll center type (feasible or not). + */ + NOMAD::poll_center_type get_poll_center_type ( void ) const + { + return _poll_center_type; + } + + /// Access to the evaluation status. + /** + \return The evaluation status + (evaluation failed, succeeded, or is in progress). + */ + NOMAD::eval_status_type get_eval_status ( void ) const { return _eval_status; } + + /// Access to the user evaluation priority. + /** + \return The user evaluation priority. + */ + const NOMAD::Double & get_user_eval_priority ( void ) const + { + return _user_eval_priority; + } + + /// Access to the random evaluation priority. + /** + \return The random evaluation priority. + */ + const NOMAD::Double & get_rand_eval_priority ( void ) const + { + return _rand_eval_priority; + } + + /// Check the point feasibility. + /** + The point is feasible if \c h \c <= \c h_min. + \param h_min Feasibility threshold -- \b IN. + \return A boolean equal to \c true if the point is feasible. + */ + bool is_feasible ( const NOMAD::Double & h_min ) const + { + return ( _h.is_defined() && _h <= h_min ); + } + + /// Scaling. + void scale ( void ); + + /// Unscaling. + void unscale ( void ); + + /// Snap to bounds. + /** + \return A boolean equal to \c true if the snapping went well. + */ + bool snap_to_bounds ( void ); + + /// Treat the periodic variables. + /** + \param new_dir A pointer to the modified direction used to generate + this point from the poll center; may be \c NULL if no + direction has been used -- \b OUT. + \return A boolean equal to \c true if the treatment went well. + */ + bool treat_periodic_variables ( NOMAD::Direction *& new_dir ); + + /// Comparison operator. + /** + \param x Right-hand side object -- \b IN. + \return A boolean equal to \c true if \c *this \c < \c x . + */ + bool operator < ( const Eval_Point & x ) const; + + /*---------------*/ + /* SET methods */ + /*---------------*/ + + /// Set the \c n and \c m. + /** + \param n Number of variables -- \b IN. + \param m Number of blackbox outputs -- \b IN. + */ + void set ( int n , int m ); + + /// Set the coordinates and \c m. + /** + \param x Coordinates of the point -- \b IN. + \param m Number of blackbox outputs -- \b IN. + */ + void set ( const NOMAD::Point & x , int m ); + + /// Set the tag. + /** + \param tag The tag -- \b IN. + */ + void set_tag ( int tag ); + + /// Set the real time. + /** + \param real_time The real time -- \b IN. + */ + void set_real_time ( int real_time ){_real_time=real_time;} + + /// increment sgte_bbe. + /** + */ + void increment_sgte_bbe (void); + + /// increment bbe. + /** + */ + void increment_bbe (void); + + /// Set the blackbox evaluation number. + /** + \param bbe the evaluation number + */ + void set_bbe (int bbe){_bbe=bbe;} + + /// Set the objective value \c f. + /** + \param f Objective value -- \b IN. + */ + void set_f ( const NOMAD::Double & f ) { _f = f; } + + /// Set the feasibility value \c h. + /** + \param h Feasibility value -- \b IN. + */ + void set_h ( const NOMAD::Double & h ) { _h = h; } + + /// Set the user evaluation priority. + /** + \param u User evaluation priority -- \b IN. + */ + void set_user_eval_priority ( const NOMAD::Double & u ) { _user_eval_priority = u; } + + /// Set the random evaluation priority. + /** + \param r Random evaluation priority -- \b IN. + */ + void set_rand_eval_priority ( const NOMAD::Double & r ) { _rand_eval_priority = r; } + + /// Set one blackbox output. + /** + \param i Index of the output to set -- \b IN. + \param v Value of the output -- \b IN. + */ + void set_bb_output ( int i , const NOMAD::Double & v ) { _bb_outputs[i]= v; } + + /// Set all blackbox outputs. + /** + \param b The \c m blackbox outputs -- \b IN. + */ + void set_bb_output ( const NOMAD::Point & b ) { _bb_outputs = b; } + + /// Set the evaluation status. + /** + \param e Evaluation status (failed, succeeded, or in progress) + -- \b IN. + */ + void set_eval_status ( const NOMAD::eval_status_type & e ) { _eval_status = e; } + + /// Set if the point respects the EB constraints. + /** + \param e A boolean equal to \c true if the point + respects the EB constraints. + */ + void set_EB_ok ( bool e ) { _EB_ok = e; } + + /// Set the evaluation type. + /** + \param e Evaluation type (true or surrogate) -- \b IN. + */ + void set_eval_type ( NOMAD::eval_type e ) { _eval_type = e; } + + /// Set the type of the poll center. + /** + \param p Type of the poll center (feasible or not) -- \b IN. + */ + void set_poll_center_type ( NOMAD::poll_center_type p ) { _poll_center_type = p; } + + /// Indicate if the point has been generated during the current run. + /** + \param c A boolean equal to \c true if the point + has been generated during the current run -- \b IN. + */ + void set_current_run ( bool c ) const { _current_run = c; } + + /// Indicate if the point is in cache. + /** + \param i A boolean equal to \c true if the point is in cache + -- \b IN. + */ + void set_in_cache ( bool i ) const { _in_cache = i; } + + + /// Set the direction used to create the point. + /** + \param d A pointer to the direction; may be \c NULL -- \b IN. + */ + void set_direction ( const NOMAD::Direction * d ); + + + /// Set the poll center used to create the point. + /** + \param d A pointer to the poll center; may be \c NULL -- \b IN. + */ + void set_poll_center ( const NOMAD::Eval_Point * d ); + + /// Set the signature. + /** + \param s A pointer to the signature -- \b IN. + */ + void set_signature ( NOMAD::Signature * s ); + + /// Check if there are nan's in the blackbox outputs: + /** + \return \c true if there is at least a nan. + */ + bool check_nan ( void ) const; + + + /// Reset the tags and bbes + /** + */ + static void reset_tags_and_bbes ( void ) {_current_tag = 0;_current_bbe = 0;_current_sgte_bbe = 0;} + #ifdef MODEL_STATS - - private: - - mutable int _mod_use; // 1: model search; 2: model eval sort - mutable int _nY; - mutable NOMAD::Double _cond , _Yw , _mh , _mf; - - public: - - void set_mod_use ( int mod_use ) const { _mod_use = mod_use; } - void set_nY ( int nY ) const { _nY = nY; } - void set_cond ( const NOMAD::Double & cond ) const { _cond = cond; } - void set_Yw ( const NOMAD::Double & Yw ) const { _Yw = Yw; } - void set_mh ( const NOMAD::Double & mh ) const { _mh = mh; } - void set_mf ( const NOMAD::Double & mf ) const { _mf = mf; } - - int get_mod_use ( void ) const { return _mod_use; } - int get_nY ( void ) const { return _nY; } - const NOMAD::Double & get_cond ( void ) const { return _cond; } - const NOMAD::Double & get_Yw ( void ) const { return _Yw; } - const NOMAD::Double & get_mh ( void ) const { return _mh; } - const NOMAD::Double & get_mf ( void ) const { return _mf; } - - void set_model_data ( const NOMAD::Eval_Point & x ) const; - void clear_model_data ( void ) const; - + + private: + + mutable int _mod_use; // 1: model search; 2: model eval sort + mutable int _nY; + mutable NOMAD::Double _cond , _Yw , _mh , _mf; + + public: + + void set_mod_use ( int mod_use ) const { _mod_use = mod_use; } + void set_nY ( int nY ) const { _nY = nY; } + void set_cond ( const NOMAD::Double & cond ) const { _cond = cond; } + void set_Yw ( const NOMAD::Double & Yw ) const { _Yw = Yw; } + void set_mh ( const NOMAD::Double & mh ) const { _mh = mh; } + void set_mf ( const NOMAD::Double & mf ) const { _mf = mf; } + + int get_mod_use ( void ) const { return _mod_use; } + int get_nY ( void ) const { return _nY; } + const NOMAD::Double & get_cond ( void ) const { return _cond; } + const NOMAD::Double & get_Yw ( void ) const { return _Yw; } + const NOMAD::Double & get_mh ( void ) const { return _mh; } + const NOMAD::Double & get_mf ( void ) const { return _mf; } + + void set_model_data ( const NOMAD::Eval_Point & x ) const; + void clear_model_data ( void ) const; + #endif - - /// Display the tag of the point. - /** - \param out The NOMAD::Display object -- \b IN. - */ - void display_tag ( const NOMAD::Display & out ) const; - - /// Display. + + /// Display the tag of the point. + /** + \param out The NOMAD::Display object -- \b IN. + */ + void display_tag ( const NOMAD::Display & out ) const; + + /// Display. + /** + \param out The NOMAD::Display object -- \b IN. + \param in_block If \c true, the point is displayed into an indented block + -- \b IN -- \b optional (default = \c true ). + */ + virtual void display_eval ( const NOMAD::Display & out , bool in_block = true ) const; + }; + + /// Display a NOMAD::Eval_Point object. /** - \param out The NOMAD::Display object -- \b IN. - \param in_block If \c true, the point is displayed into an indented block - -- \b IN -- \b optional (default = \c true ). - */ - virtual void display ( const NOMAD::Display & out , bool in_block = true ) const; - }; - - /// Display a NOMAD::Eval_Point object. - /** \param out The NOMAD::Display object -- \b IN. \param x The NOMAD::Eval_Point object to be displayed -- \b IN. \return The NOMAD::Display object. - */ - inline const NOMAD::Display & operator << ( const NOMAD::Display & out , - const NOMAD::Eval_Point & x ) - { - x.display ( out , true ); - return out; - } + */ + inline const NOMAD::Display & operator << ( const NOMAD::Display & out , + const NOMAD::Eval_Point & x ) + { + x.display_eval (out , true ); + return out; + } } #endif diff --git a/src/Evaluator.cpp b/src/Evaluator.cpp index 657a698..f0f8ca9 100644 --- a/src/Evaluator.cpp +++ b/src/Evaluator.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Evaluator.cpp - \brief Evaluation of blackbox functions (implementation) - \author Sebastien Le Digabel - \date 2010-04-14 - \see Evaluator.hpp -*/ + \file Evaluator.cpp + \brief Evaluation of blackbox functions (implementation) + \author Sebastien Le Digabel + \date 2010-04-14 + \see Evaluator.hpp + */ #include "Evaluator.hpp" /*-----------------------------------*/ @@ -56,473 +56,774 @@ bool NOMAD::Evaluator::_force_quit = false; /* . _bb_exe includes the blackbox path */ /*-----------------------------------------------------------------*/ NOMAD::Evaluator::Evaluator ( const NOMAD::Parameters & p ) - : _p ( p ) , - _is_multi_obj ( false ) +: _p ( p ) , +_is_multi_obj ( false ) , +_is_model_evaluator ( false ) { - NOMAD::Evaluator::_force_quit = false; - - if ( _p.get_bb_exe().empty() ) - return; - - // _bbe_exe and _bb_nbo construction: - std::list<std::string>::const_iterator it = _p.get_bb_exe().begin(); - _bb_exe.push_back(*it); - _bb_nbo.push_back(1); - ++it; - - std::list<std::string>::const_iterator end = _p.get_bb_exe().end(); - while ( it != end ) { - if ( *it != _bb_exe[_bb_exe.size()-1] ) { - _bb_exe.push_back(*it); - _bb_nbo.push_back(1); - } - else - ++_bb_nbo[_bb_exe.size()-1]; - ++it; - } - - // we check that _bb_exe contains unique names and we add the problem path: - size_t k , l , n = _bb_exe.size() , nm1 = n-1; - for ( k = 0 ; k < nm1 ; ++k ) { - for ( l = k+1 ; l < n ; ++l ) - if ( _bb_exe[k] == _bb_exe[l] ) - throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , - "problem with executable names" ); - } - - // construction of _sgte_exe: - bool has_sgte_exe = _p.has_sgte_exe(); - std::string err; - if ( has_sgte_exe ) { - for ( k = 0 ; k < n ; ++k ) { - - _sgte_exe.push_back ( _p.get_sgte_exe(_bb_exe[k]) ); - - if ( _sgte_exe[_sgte_exe.size()-1].empty() ) { - err = "blackbox executable \'" + _bb_exe[k] + "\' has no surrogate"; - throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err ); - } - } - } - - // process blakc-box executables (check and add problem path): - for ( k = 0 ; k < n ; ++k ) { - process_bb_exe_name ( _bb_exe[k] ); - if ( has_sgte_exe ) - process_bb_exe_name ( _sgte_exe[k] ); - } - - // blackbox names and indexes display: + NOMAD::Evaluator::_force_quit = false; + + if ( _p.get_bb_exe().empty() ) + return; + + // _bbe_exe and _bb_nbo construction: + std::list<std::string>::const_iterator it = _p.get_bb_exe().begin(); + _bb_exe.push_back(*it); + _bb_nbo.push_back(1); + ++it; + + std::list<std::string>::const_iterator end = _p.get_bb_exe().end(); + while ( it != end ) + { + if ( *it != _bb_exe[_bb_exe.size()-1] ) + { + _bb_exe.push_back(*it); + _bb_nbo.push_back(1); + } + else + ++_bb_nbo[_bb_exe.size()-1]; + ++it; + } + + // we check that _bb_exe contains unique names and we add the problem path: + size_t k , l , n = _bb_exe.size() , nm1 = n-1; + for ( k = 0 ; k < nm1 ; ++k ) + { + for ( l = k+1 ; l < n ; ++l ) + if ( _bb_exe[k] == _bb_exe[l] ) + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , + "problem with executable names" ); + } + + // construction of _sgte_exe: + bool has_sgte_exe = _p.has_sgte_exe(); + std::string err; + if ( has_sgte_exe ) + { + for ( k = 0 ; k < n ; ++k ) + { + + _sgte_exe.push_back ( _p.get_sgte_exe(_bb_exe[k]) ); + + if ( _sgte_exe[_sgte_exe.size()-1].empty() ) + { + err = "blackbox executable \'" + _bb_exe[k] + "\' has no surrogate"; + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err ); + } + } + } + + // process blakc-box executables (check and add problem path): + for ( k = 0 ; k < n ; ++k ) + { + process_bb_exe_name ( _bb_exe[k] ); + if ( has_sgte_exe ) + process_bb_exe_name ( _sgte_exe[k] ); + } + + // blackbox names and indexes display: #ifdef DEBUG #ifdef USE_MPI - int rank; - MPI_Comm_rank ( MPI_COMM_WORLD, &rank); - if ( rank == 0 ) { + int rank; + MPI_Comm_rank ( MPI_COMM_WORLD, &rank); + if ( rank == 0 ) + { #else - { + { #endif - const NOMAD::Display & out = _p.out(); - if ( !_bb_exe.empty() ) { - out << std::endl - << NOMAD::open_block ( "blackbox executables" ); - for ( k = 0 ; k < n ; ++k ) { - out << NOMAD::open_block ( "bb #" + NOMAD::itos(k) ) - << _bb_exe[k] << std::endl - << "number of outputs=" << _bb_nbo[k] << std::endl - << NOMAD::close_block(); - } - out.close_block(); - } - if ( !_sgte_exe.empty() ) { - out << std::endl - << NOMAD::open_block ( "surrogate executables" ); - for ( k = 0 ; k < n ; ++k ) - out << "sgte #" << static_cast<int>(k) << ": " - << _sgte_exe[k] << std::endl; - out.close_block(); - } - } + const NOMAD::Display & out = _p.out(); + if ( !_bb_exe.empty() ) + { + out << std::endl + << NOMAD::open_block ( "blackbox executables" ); + for ( k = 0 ; k < n ; ++k ) + { + out << NOMAD::open_block ( "bb #" + NOMAD::itos(k) ) + << _bb_exe[k] << std::endl + << "number of outputs=" << _bb_nbo[k] << std::endl + << NOMAD::close_block(); + } + out.close_block(); + } + if ( !_sgte_exe.empty() ) + { + out << std::endl + << NOMAD::open_block ( "surrogate executables" ); + for ( k = 0 ; k < n ; ++k ) + out << "sgte #" << static_cast<int>(k) << ": " + << _sgte_exe[k] << std::endl; + out.close_block(); + } + } #endif -} - -/*----------------------------------------------------------------*/ -/* process a blackbox executable name (private) */ -/*----------------------------------------------------------------*/ -void NOMAD::Evaluator::process_bb_exe_name ( std::string & bb_exe ) const -{ - std::string err; - std::list<std::string> bb_exe_words; - - NOMAD::get_words ( bb_exe , bb_exe_words ); - - if ( bb_exe_words.empty() ) { - err = "problem with executable \'" + bb_exe + "\'"; - throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err ); - } - - std::string problem_dir = _p.get_problem_dir(); - - // bb_exe is composed of several words (it is a command): - if ( bb_exe_words.size() > 1 ) { - - bb_exe.clear(); - - std::list<std::string>::const_iterator it = bb_exe_words.begin() , - end = bb_exe_words.end(); - while (true) { - - if ( (*it)[0] != '$' ) { - bb_exe += "\"" + problem_dir; - bb_exe += *it + "\""; - } - else - bb_exe += it->substr ( 1 , it->size()-1 ); - - ++it; - - if ( it == end ) - break; - - bb_exe += " "; - } - } - - // bb_exe is just composed of one name (it is an executable): - else { - if ( bb_exe[0] != '$' ) - bb_exe = problem_dir + bb_exe; - else - bb_exe = bb_exe.substr ( 1 , bb_exe.size()-1 ); - if ( !NOMAD::check_exe_file ( bb_exe ) ) { - err = "\'" + bb_exe + "\' is not a valid executable file"; - throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err ); } - if ( bb_exe[0] != '$' ) - bb_exe = "\"" + bb_exe + "\""; - } -} - -/*-----------------------------------------------------------------------*/ -/* check the constraints to decide if an evaluation have to be stopped */ -/*-----------------------------------------------------------------------*/ -/* . checked when h > h_max or if a 'EB' constraint is violated */ -/* . private method */ -/*-----------------------------------------------------------------------*/ -bool NOMAD::Evaluator::interrupt_evaluations ( const NOMAD::Eval_Point & x , - const NOMAD::Double & h_max ) const -{ - int nbo = _p.get_bb_nb_outputs(); - const NOMAD::Point & bbo = x.get_bb_outputs(); - const std::vector<NOMAD::bb_output_type> & bbot = _p.get_bb_output_type(); - NOMAD::Double h = 0.0; - bool check_h = h_max.is_defined(); - - for ( int i = 0 ; i < nbo ; ++i ) { - - if ( bbo[i].is_defined() && - ( bbot[i] == NOMAD::EB || bbot[i] == NOMAD::PEB_E ) && - bbo[i] > _p.get_h_min() ) - return true; - - if ( check_h && bbo[i].is_defined() && - (bbot[i] == NOMAD::FILTER || - bbot[i] == NOMAD::PB || - bbot[i] == NOMAD::PEB_P ) ) { - - if ( bbo[i] > _p.get_h_min() ) { - switch ( _p.get_h_norm() ) { - case NOMAD::L1: - h += bbo[i]; - break; - case NOMAD::L2: - h += bbo[i].pow2(); - break; - case NOMAD::LINF: - if ( bbo[i] > h ) - h = bbo[i]; - break; + + /*----------------------------------------------------------------*/ + /* process a blackbox executable name (private) */ + /*----------------------------------------------------------------*/ + void NOMAD::Evaluator::process_bb_exe_name ( std::string & bb_exe ) const + { + std::string err; + std::list<std::string> bb_exe_words; + + NOMAD::get_words ( bb_exe , bb_exe_words ); + + if ( bb_exe_words.empty() ) + { + err = "problem with executable \'" + bb_exe + "\'"; + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err ); + } + + std::string problem_dir = _p.get_problem_dir(); + + // bb_exe is composed of several words (it is a command): + if ( bb_exe_words.size() > 1 ) + { + + bb_exe.clear(); + + std::list<std::string>::const_iterator it = bb_exe_words.begin() , + end = bb_exe_words.end(); + while (true) + { + + if ( (*it)[0] != '$' ) + { + bb_exe += "\"" + problem_dir; + bb_exe += *it + "\""; + } + else + bb_exe += it->substr ( 1 , it->size()-1 ); + + ++it; + + if ( it == end ) + break; + + bb_exe += " "; + } + } + + // bb_exe is just composed of one name (it is an executable): + else { + if ( bb_exe[0] != '$' ) + bb_exe = problem_dir + bb_exe; + else + bb_exe = bb_exe.substr ( 1 , bb_exe.size()-1 ); + if ( !NOMAD::check_exe_file ( bb_exe ) ) + { + err = "\'" + bb_exe + "\' is not a valid executable file"; + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err ); + } + if ( bb_exe[0] != '$' ) + bb_exe = "\"" + bb_exe + "\""; + } } - - if ( _p.get_h_norm() == NOMAD::L2 ) { - if ( h > h_max.pow2() ) - return true; + + /*-----------------------------------------------------------------------*/ + /* check the constraints to decide if an evaluation have to be stopped */ + /*-----------------------------------------------------------------------*/ + /* . checked when h > h_max or if a 'EB' constraint is violated */ + /* . private method */ + /*-----------------------------------------------------------------------*/ + bool NOMAD::Evaluator::interrupt_evaluations ( const NOMAD::Eval_Point & x , + const NOMAD::Double & h_max ) const + { + int nbo = _p.get_bb_nb_outputs(); + const NOMAD::Point & bbo = x.get_bb_outputs(); + const std::vector<NOMAD::bb_output_type> & bbot = _p.get_bb_output_type(); + NOMAD::Double h = 0.0; + bool check_h = h_max.is_defined(); + + for ( int i = 0 ; i < nbo ; ++i ) { + + if ( bbo[i].is_defined() && + ( bbot[i] == NOMAD::EB || bbot[i] == NOMAD::PEB_E ) && + bbo[i] > _p.get_h_min() ) + return true; + + if ( check_h && bbo[i].is_defined() && + (bbot[i] == NOMAD::FILTER || + bbot[i] == NOMAD::PB || + bbot[i] == NOMAD::PEB_P ) ) { + + if ( bbo[i] > _p.get_h_min() ) { + switch ( _p.get_h_norm() ) { + case NOMAD::L1: + h += bbo[i]; + break; + case NOMAD::L2: + h += bbo[i].pow2(); + break; + case NOMAD::LINF: + if ( bbo[i] > h ) + h = bbo[i]; + break; + } + + if ( _p.get_h_norm() == NOMAD::L2 ) { + if ( h > h_max.pow2() ) + return true; + } + else if ( h > h_max ) + return true; + } + } + } + return false; } - else if ( h > h_max ) - return true; - } - } - } - return false; -} - -/*--------------------------------------------------------*/ -/* compute f(x) from the blackbox outputs of a point */ -/* (define a Multi_Obj_Evaluator to treat more than */ -/* one objective) */ -/*--------------------------------------------------------*/ -void NOMAD::Evaluator::compute_f ( NOMAD::Eval_Point & x ) const -{ - if ( x.get_bb_outputs().size() != _p.get_bb_nb_outputs() ) { - std::ostringstream err; - err << "Evaluator::compute_f(x): x has a wrong number of blackbox outputs (" - << x.get_bb_outputs().size() << " != " - << _p.get_bb_nb_outputs() << ")"; - throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err.str() ); - } - - x.set_f ( x.get_bb_outputs()[*(_p.get_index_obj().begin())] ); -} - -/*--------------------------------------------------------*/ -/* compute h(x) from the blackbox outputs of a point */ -/* set also the flag 'EB_ok' of the point */ -/*--------------------------------------------------------*/ -void NOMAD::Evaluator::compute_h ( NOMAD::Eval_Point & x ) const -{ - if ( x.get_bb_outputs().size() != _p.get_bb_nb_outputs() ) { - std::ostringstream err; - err << "Evaluator::compute_h(x): x has a wrong number of blackbox outputs (" - << x.get_bb_outputs().size() << " != " - << _p.get_bb_nb_outputs() << ")"; - throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err.str() ); - } - - int nbo = _p.get_bb_nb_outputs(); - const std::vector<NOMAD::bb_output_type> & bbot = _p.get_bb_output_type(); - const NOMAD::Point & bbo = x.get_bb_outputs(); - NOMAD::Double h = 0.0 , bboi; - - x.set_EB_ok ( true ); - - for ( int i = 0 ; i < nbo ; ++i ) { - - bboi = bbo[i]; - - if ( bboi.is_defined() && - (bbot[i] == NOMAD::EB || bbot[i] == NOMAD::PEB_E ) && - bboi > _p.get_h_min() ) { - h.clear(); - x.set_h ( h ); - x.set_EB_ok ( false ); - return; - } - - if ( bboi.is_defined() && - ( bbot[i] == NOMAD::FILTER || - bbot[i] == NOMAD::PB || - bbot[i] == NOMAD::PEB_P ) ) { - if ( bboi > _p.get_h_min() ) { - switch ( _p.get_h_norm() ) { - case NOMAD::L1: - h += bboi; - break; - case NOMAD::L2: - h += bboi * bboi; - break; - case NOMAD::LINF: - if ( bboi > h ) - h = bboi; - break; + + /*--------------------------------------------------------*/ + /* compute f(x) from the blackbox outputs of a point */ + /* (define a Multi_Obj_Evaluator to treat more than */ + /* one objective) */ + /*--------------------------------------------------------*/ + void NOMAD::Evaluator::compute_f ( NOMAD::Eval_Point & x ) const + { + if ( x.get_bb_outputs().size() != _p.get_bb_nb_outputs() ) { + std::ostringstream err; + err << "Evaluator::compute_f(x): x has a wrong number of blackbox outputs (" + << x.get_bb_outputs().size() << " != " + << _p.get_bb_nb_outputs() << ")"; + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err.str() ); + } + + x.set_f ( x.get_bb_outputs()[*(_p.get_index_obj().begin())] ); } - } - } - } - - if ( _p.get_h_norm() == NOMAD::L2 ) - h = h.sqrt(); - - x.set_h ( h ); -} - -/*-------------------------------------------------------------------*/ -/* . evaluate the black boxes at a given Eval_Point */ -/* . the function returns true if the evaluation did not fail */ -/* . set count_eval=true to count the evaluation */ -/* (unless the output value CNT_EVAL is defined and set to 1 */ -/* by the blackbox) */ -/*-------------------------------------------------------------------*/ -bool NOMAD::Evaluator::eval_x ( NOMAD::Eval_Point & x , - const NOMAD::Double & h_max , - bool & count_eval ) const -{ - count_eval = false; - - if ( _bb_exe.empty() || !x.is_complete() ) - throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , - "Evaluator: no BB_EXE is defined (blackbox executable names)" ); - - bool sgte = x.get_eval_type() == NOMAD::SGTE; - if ( sgte && _sgte_exe.empty() ) - throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , - "Evaluator: no SGTE_EXE is defined (surrogate executable names)" ); - - int pid = NOMAD::get_pid(); - int seed = _p.get_seed(); - std::string tmp_dir = _p.get_tmp_dir(); - - std::ostringstream oss; - oss << "." << seed; - if ( pid != seed ) - oss << "." << pid; - oss << "." << x.get_tag() << "."; - const std::string & sint = oss.str(); - - // for the parallel version: no need to include the process rank in the names - // as the point tags are unique for all the processes: each process creates - // its own points and uses Eval_Point::set_tag() - - // blackbox input file writing: - // ---------------------------- - std::string bb_input_file_name = - tmp_dir + NOMAD::BLACKBOX_INPUT_FILE_PREFIX - + sint + NOMAD::BLACKBOX_INPUT_FILE_EXT; - - std::string bb_output_file_name = - tmp_dir + NOMAD::BLACKBOX_OUTPUT_FILE_PREFIX - + sint + NOMAD::BLACKBOX_OUTPUT_FILE_EXT; - - std::ofstream fout ( bb_input_file_name.c_str() ); - if ( fout.fail() ) { - std::string err = "could not open file blackbox input file " + bb_input_file_name; - throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err ); - } - - // include seed: - if ( _p.get_bb_input_include_seed() ) - fout << seed << " "; - - // include tag: - if ( _p.get_bb_input_include_tag() ) - fout << x.get_tag() << " "; - - fout.setf ( std::ios::fixed ); - fout.precision ( NOMAD::DISPLAY_PRECISION_BB ); - x.Point::display ( fout , " " , -1 , -1 ); - fout << std::endl; - - fout.close(); - - if ( fout.fail() ) - return false; - - x.set_eval_status ( NOMAD::EVAL_IN_PROGRESS ); - - std::string cmd , bb_exe; - std::ifstream fin; - bool failed; - NOMAD::Double d; - int j , nbbok; - int ibbo = 0; - - // system call to evaluate the blackbox: - // ------------------------------------- - size_t bn = _bb_exe.size(); - for ( size_t k = 0 ; k < bn ; ++k ) + + /*--------------------------------------------------------*/ + /* compute h(x) from the blackbox outputs of a point */ + /* set also the flag 'EB_ok' of the point */ + /*--------------------------------------------------------*/ + void NOMAD::Evaluator::compute_h ( NOMAD::Eval_Point & x ) const { + if ( x.get_bb_outputs().size() != _p.get_bb_nb_outputs() ) + { + std::ostringstream err; + err << "Evaluator::compute_h(x): x has a wrong number of blackbox outputs (" + << x.get_bb_outputs().size() << " != " + << _p.get_bb_nb_outputs() << ")"; + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err.str() ); + } - // executable name: - bb_exe = ( sgte ) ? _sgte_exe[k] : _bb_exe[k]; + int nbo = _p.get_bb_nb_outputs(); + const std::vector<NOMAD::bb_output_type> & bbot = _p.get_bb_output_type(); + const NOMAD::Point & bbo = x.get_bb_outputs(); + NOMAD::Double h = 0.0 , bboi; - // system command: - cmd = bb_exe + " " + bb_input_file_name; + x.set_EB_ok ( true ); - // redirection ? if no, the blackbox has to create - // the output file 'bb_output_file_name': - if ( _p.get_bb_redirection() ) - cmd += " > " + bb_output_file_name; + for ( int i = 0 ; i < nbo ; ++i ) + { + + bboi = bbo[i]; + + if ( bboi.is_defined() && + (bbot[i] == NOMAD::EB || bbot[i] == NOMAD::PEB_E ) && + bboi > _p.get_h_min() ) + { + h.clear(); + x.set_h ( h ); + x.set_EB_ok ( false ); + return; + } + + if ( bboi.is_defined() && + ( bbot[i] == NOMAD::FILTER || + bbot[i] == NOMAD::PB || + bbot[i] == NOMAD::PEB_P ) ) + { + if ( bboi > _p.get_h_min() ) + { + switch ( _p.get_h_norm() ) + { + case NOMAD::L1: + h += bboi; + break; + case NOMAD::L2: + h += bboi * bboi; + break; + case NOMAD::LINF: + if ( bboi > h ) + h = bboi; + break; + } + } + } + } + if ( _p.get_h_norm() == NOMAD::L2 ) + h = h.sqrt(); + + x.set_h ( h ); + } + + /*-------------------------------------------------------------------*/ + /* . evaluate the black boxes at a given Eval_Point */ + /* . the function returns true if the evaluation did not fail */ + /* . set count_eval=true to count the evaluation */ + /* (unless the output value CNT_EVAL is defined and set to 1 */ + /* by the blackbox) */ + /*-------------------------------------------------------------------*/ + bool NOMAD::Evaluator::eval_x ( NOMAD::Eval_Point & x , + const NOMAD::Double & h_max , + bool & count_eval ) const + { + count_eval = false; + + if ( _bb_exe.empty() || !x.is_complete() ) + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , + "Evaluator: no BB_EXE is defined (blackbox executable names)" ); + + bool sgte = x.get_eval_type() == NOMAD::SGTE; + if ( sgte && _sgte_exe.empty() ) + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , + "Evaluator: no SGTE_EXE is defined (surrogate executable names)" ); + + int pid = NOMAD::get_pid(); + int seed = _p.get_seed(); + std::string tmp_dir = _p.get_tmp_dir(); + + std::ostringstream oss; + oss << "." << seed; + if ( pid != seed ) + oss << "." << pid; + oss << "." << x.get_tag() << "."; + const std::string & sint = oss.str(); + + // for the parallel version: no need to include the process rank in the names + // as the point tags are unique for all the processes: each process creates + // its own points and uses Eval_Point::set_tag() + + // blackbox input file writing: + // ---------------------------- + std::string bb_input_file_name = + tmp_dir + NOMAD::BLACKBOX_INPUT_FILE_PREFIX + + sint + NOMAD::BLACKBOX_INPUT_FILE_EXT; + + std::string bb_output_file_name = + tmp_dir + NOMAD::BLACKBOX_OUTPUT_FILE_PREFIX + + sint + NOMAD::BLACKBOX_OUTPUT_FILE_EXT; + + std::ofstream fout ( bb_input_file_name.c_str() ); + if ( fout.fail() ) + { + std::string err = "could not create file blackbox input file " + bb_input_file_name + ". \n \n #### Please check that write permission are granted for the working directory. #### "; + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err ); + } + + // include seed: + if ( _p.get_bb_input_include_seed() ) + fout << seed << " "; + + // include tag: + if ( _p.get_bb_input_include_tag() ) + fout << x.get_tag() << " "; + + fout.setf ( std::ios::fixed ); + fout.precision ( NOMAD::DISPLAY_PRECISION_BB ); + x.Point::display ( fout , " " , -1 , -1 ); + fout << std::endl; + + fout.close(); + + if ( fout.fail() ) + return false; + + x.set_eval_status ( NOMAD::EVAL_IN_PROGRESS ); + + std::string cmd , bb_exe; + std::ifstream fin; + bool failed; + NOMAD::Double d; + int j , nbbok; + int ibbo = 0; + + // system call to evaluate the blackbox: + // ------------------------------------- + size_t bn = _bb_exe.size(); + for ( size_t k = 0 ; k < bn ; ++k ) + { + + // executable name: + bb_exe = ( sgte ) ? _sgte_exe[k] : _bb_exe[k]; + + // system command: + cmd = bb_exe + " " + bb_input_file_name; + + // redirection ? if no, the blackbox has to create + // the output file 'bb_output_file_name': + if ( _p.get_bb_redirection() ) + cmd += " > " + bb_output_file_name; + #ifdef DEBUG #ifdef USE_MPI - int rank; - MPI_Comm_rank ( MPI_COMM_WORLD, &rank); - _p.out() << "command(rank=" << rank - << ") = \'" << cmd << "\'" << std::endl; + int rank; + MPI_Comm_rank ( MPI_COMM_WORLD, &rank); + _p.out() << "command(rank=" << rank + << ") = \'" << cmd << "\'" << std::endl; #else - _p.out() << "command=\'" << cmd << "\'" << std::endl; + _p.out() << "command=\'" << cmd << "\'" << std::endl; #endif #endif - - // the evaluation: - { - int signal = system ( cmd.c_str() ); - // catch the ctrl-c signal: - if ( signal == SIGINT ) - raise ( SIGINT ); + // the evaluation: + { + int signal = system ( cmd.c_str() ); + + // catch the ctrl-c signal: + if ( signal == SIGINT ) + raise ( SIGINT ); + + // other evaluation error: + failed = ( signal != 0 ); + count_eval = true; + } - // other evaluation error: - failed = ( signal != 0 ); - count_eval = true; + // the evaluation failed (we stop the evaluations): + if ( failed ) + { + x.set_eval_status ( NOMAD::EVAL_FAIL ); + break; + } + + // reading of the blackbox output file: + // ------------------------------------ + else + { + + // bb-output file reading: + fin.open ( bb_output_file_name.c_str() ); + + failed = false; + bool is_defined = true; + bool is_inf = false; + + // loop on the number of outputs for this blackbox: + nbbok = _bb_nbo[k]; + for ( j = 0 ; j < nbbok ; ++j ) + { + + fin >> d; + + if ( !d.is_defined() ) + { + is_defined = false; + break; + } + + if ( fin.fail() ) + { + failed = true; + break; + } + + if ( d.value() >= NOMAD::INF ) + { + is_inf = true; + break; + } + + x.set_bb_output ( ibbo++ , d ); + } + + fin.close(); + + // the evaluation failed: + if ( failed || !is_defined || is_inf ) + { + x.set_eval_status ( NOMAD::EVAL_FAIL ); + break; + } + + // stop the evaluations if h > h_max or if a 'EB' constraint is violated: + if ( k < _bb_exe.size() - 1 && interrupt_evaluations ( x , h_max ) ) + break; + } } - // the evaluation failed (we stop the evaluations): - if ( failed ) { - x.set_eval_status ( NOMAD::EVAL_FAIL ); - break; + if ( x.get_eval_status() == NOMAD::EVAL_IN_PROGRESS ) + x.set_eval_status ( NOMAD::EVAL_OK ); + + // delete the blackbox input and output files: + // ------------------------------------------- + remove ( bb_input_file_name.c_str () ); + remove ( bb_output_file_name.c_str() ); + + // check the CNT_EVAL output: + // -------------------------- + int index_cnt_eval = _p.get_index_cnt_eval(); + if ( index_cnt_eval >= 0 && x.get_bb_outputs()[index_cnt_eval] == 0.0 ) + count_eval = false; + + return x.is_eval_ok(); + + + } + + + /*-------------------------------------------------------------------*/ + /* . evaluate the black boxes at a list of given Eval_Points */ + /*-------------------------------------------------------------------*/ + bool NOMAD::Evaluator::eval_x ( std::list<NOMAD::Eval_Point *> & list_eval, + const NOMAD::Double & h_max , + std::list<bool> & list_count_eval) const + { + + std::list<NOMAD::Eval_Point *>::iterator it; + std::list<NOMAD::Eval_Point *>::iterator it_begin=list_eval.begin(); + std::list<NOMAD::Eval_Point *>::iterator it_end=list_eval.end(); + std::list<bool>::iterator it_count=list_count_eval.begin(); + + if ( list_eval.size() !=list_count_eval.size()) + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , + "Evaluator: inconsistent size of list" ); + + if ( _bb_exe.empty()) + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , + "Evaluator: no BB_EXE is defined (blackbox executable names)" ); + + bool sgte = ((*it_begin)->get_eval_type() == NOMAD::SGTE); + if ( sgte && _sgte_exe.empty() ) + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , + "Evaluator: no SGTE_EXE is defined (surrogate executable names)" ); + + + + int pid = NOMAD::get_pid(); + int seed = _p.get_seed(); + std::string tmp_dir = _p.get_tmp_dir(); + + std::ostringstream oss; + oss << "." << seed; + if ( pid != seed ) + oss << "." << pid; + + for (it=it_begin;it!=it_end;++it) + { + if (!(*it)->is_complete() ) + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , + "Evaluator: points provided for evaluations are incomplete " ); + } + // add the tag of the first point + oss << "." << (*it_begin)->get_tag(); - // reading of the blackbox output file: - // ------------------------------------ - else { + oss << "." ; + const std::string & sint = oss.str(); + + // for the parallel version: no need to include the process rank in the names + // as the point tags are unique for all the processes: each process creates + // its own points and uses Eval_Point::set_tag() + + // blackbox input file writing: + // ---------------------------- + std::string bb_input_file_name = + tmp_dir + NOMAD::BLACKBOX_INPUT_FILE_PREFIX + + sint + NOMAD::BLACKBOX_INPUT_FILE_EXT; + + std::string bb_output_file_name = + tmp_dir + NOMAD::BLACKBOX_OUTPUT_FILE_PREFIX + + sint + NOMAD::BLACKBOX_OUTPUT_FILE_EXT; + + std::ofstream fout ( bb_input_file_name.c_str() ); + if ( fout.fail() ) { + std::string err = "could not create file blackbox input file " + bb_input_file_name + ". \n \n #### Please check that write permission are granted for the working directory. #### "; + throw NOMAD::Exception ( "Evaluator.cpp" , __LINE__ , err ); + } + + + for (it=it_begin;it!=it_end;++it) + { + // include seed: + if ( _p.get_bb_input_include_seed() ) + fout << seed << " "; + + // include tag: + if ( _p.get_bb_input_include_tag() ) + fout << (*it)->get_tag() << " "; - // bb-output file reading: - fin.open ( bb_output_file_name.c_str() ); + fout.setf ( std::ios::fixed ); + fout.precision ( NOMAD::DISPLAY_PRECISION_BB ); + (*it)->Point::display ( fout , " " , -1 , -1 ); + fout << std::endl; + } + + fout.close(); + + if ( fout.fail() ) + return false; + + for (it=it_begin;it!=it_end;++it) + (*it)->set_eval_status ( NOMAD::EVAL_IN_PROGRESS ); + + + std::string cmd , bb_exe; + std::ifstream fin; + bool failed; + NOMAD::Double d; + int j , nbbok; + int ibbo = 0; + + // system call to evaluate the blackboxes: + // ------------------------------------- + size_t bn = _bb_exe.size(); + for ( size_t k = 0 ; k < bn ; ++k ) + { + + // executable name: + bb_exe = ( sgte ) ? _sgte_exe[k] : _bb_exe[k]; - failed = false; - bool is_defined = true; - bool is_inf = false; + // system command: + cmd = bb_exe + " " + bb_input_file_name; - // loop on the number of outputs for this blackbox: - nbbok = _bb_nbo[k]; - for ( j = 0 ; j < nbbok ; ++j ) { + // redirection ? if no, the blackbox has to create + // the output file 'bb_output_file_name': + if ( _p.get_bb_redirection() ) + cmd += " > " + bb_output_file_name; + + + // the evaluation: + { + int signal = system ( cmd.c_str() ); - fin >> d; + // catch the ctrl-c signal: + if ( signal == SIGINT ) + raise ( SIGINT ); - if ( !d.is_defined() ) { - is_defined = false; - break; + // other evaluation error: + failed = ( signal != 0 ); + } + + // the evaluation failed (we stop the evaluations): + if ( failed ) + { + it_count=list_count_eval.begin(); + for (it=it_begin;it!=it_end;++it,++it_count) + { + (*it)->set_eval_status ( NOMAD::EVAL_FAIL ); + (*it_count)=true; // } + break; + } + + // reading of the blackbox output file: + // ------------------------------------ + else + { - if ( fin.fail() ) { - failed = true; - break; + // bb-output file reading: + fin.open ( bb_output_file_name.c_str() ); + + string s; + bool is_defined,is_inf; + + bool list_all_failed_eval=true; + bool list_all_interrupt=true; + + // loop on the points + it_count=list_count_eval.begin(); + for (it=it_begin;it!=it_end;++it,++it_count) + { + failed = false; + is_defined = true; + is_inf = false; + + // loop on the number of outputs for this blackbox: + nbbok = _bb_nbo[k]; + ibbo=0; + for ( j = 0 ; j < nbbok ; ++j ) + { + fin >> s; + + if ( fin.fail() ) + { + failed = true; + break; + } + + toupper(s); + if (s.compare("REJECT")==0) + { + *it_count=false; // Rejected points are not counted + (*it)->set_eval_status(NOMAD::EVAL_USER_REJECT); + break; + } + else + { + d.atof(s); + (*it_count)=true; + } + // + + if (s.compare("FAIL")==0) + { + failed = true; + break; + } + + + if ( !d.is_defined() ) + { + is_defined = false; + break; + } + + + if ( d.value() >= NOMAD::INF ) { + is_inf = true; + break; + } + + (*it)->set_bb_output ( ibbo++ , d ); + } + + + // the evaluation failed: + if ( failed || !is_defined || is_inf ) + { + (*it)->set_eval_status ( NOMAD::EVAL_FAIL ); + + } else + list_all_failed_eval=false; + + + // stop the evaluations if h > h_max or if a 'EB' constraint is violated: + if ( !( k < _bb_exe.size() - 1 && interrupt_evaluations ( *(*it) , h_max ) && list_all_interrupt )) + list_all_interrupt=false; } - if ( d.value() >= NOMAD::INF ) { - is_inf = true; + fin.close(); + if (list_all_failed_eval || list_all_interrupt) break; - } - x.set_bb_output ( ibbo++ , d ); } + } + + + // delete the blackbox input and output files: + // ------------------------------------------- + remove ( bb_input_file_name.c_str () ); + remove ( bb_output_file_name.c_str() ); + + bool at_least_one_eval_ok=false; + int index_cnt_eval = _p.get_index_cnt_eval(); + + + // update eval status and check that at least one was ok + it_count=list_count_eval.begin(); + for (it=it_begin;it!=it_end;++it,++it_count) + { + if ( (*it)->get_eval_status() == NOMAD::EVAL_IN_PROGRESS ) + (*it)->set_eval_status ( NOMAD::EVAL_OK ); - fin.close(); - - // the evaluation failed: - if ( failed || !is_defined || is_inf ) { - x.set_eval_status ( NOMAD::EVAL_FAIL ); - break; - } + if (!at_least_one_eval_ok && (*it)->is_eval_ok()) + at_least_one_eval_ok=true; - // stop the evaluations if h > h_max or if a 'EB' constraint is violated: - if ( k < _bb_exe.size() - 1 && interrupt_evaluations ( x , h_max ) ) - break; + // count_eval from bb_outputs: + // -------------------------- + if ( index_cnt_eval >= 0 && (*it)->get_bb_outputs()[index_cnt_eval]==0) + *it_count=false; } + + return at_least_one_eval_ok; } - - if ( x.get_eval_status() == NOMAD::EVAL_IN_PROGRESS ) - x.set_eval_status ( NOMAD::EVAL_OK ); - - // delete the blackbox input and output files: - // ------------------------------------------- - remove ( bb_input_file_name.c_str () ); - remove ( bb_output_file_name.c_str() ); - - // check the CNT_EVAL output: - // -------------------------- - int index_cnt_eval = _p.get_index_cnt_eval(); - if ( index_cnt_eval >= 0 && x.get_bb_outputs()[index_cnt_eval] == 0.0 ) - count_eval = false; - - return x.is_eval_ok(); -} diff --git a/src/Evaluator.hpp b/src/Evaluator.hpp index f637e7b..80119df 100644 --- a/src/Evaluator.hpp +++ b/src/Evaluator.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,187 +34,250 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Evaluator.hpp - \brief Evaluation of blackbox functions (headers) - \author Sebastien Le Digabel - \date 2010-04-14 - \see Evaluator.cpp -*/ + \file Evaluator.hpp + \brief Evaluation of blackbox functions (headers) + \author Sebastien Le Digabel + \date 2010-04-14 + \see Evaluator.cpp + */ #ifndef __EVALUATOR__ #define __EVALUATOR__ #include <csignal> #include "Priority_Eval_Point.hpp" #include "Stats.hpp" +#include <list> namespace NOMAD { - - // forward declarations: - class Barrier; - class Pareto_Front; - class Evaluator_Control; - - /// Evaluation of blackbox functions. - /** + + // forward declarations: + class Barrier; + class Pareto_Front; + class Evaluator_Control; + + /// Evaluation of blackbox functions. + /** This class allows the evaluation of one trial point. - */ - class Evaluator : private NOMAD::Uncopyable { - - protected: - - /// Parameters. - const NOMAD::Parameters & _p; - - /// Multi-objective flag. - /** - Identifies if a NOMAD::Evaluator object refers to - a NOMAD::Multi_Obj_Evaluator for more than one - objective function. - */ - bool _is_multi_obj; + */ + class Evaluator : private NOMAD::Uncopyable { + + protected: + + /// Parameters. + const NOMAD::Parameters & _p; + + /// Multi-objective flag. + /** + Identifies if a NOMAD::Evaluator object refers to + a NOMAD::Multi_Obj_Evaluator for more than one + objective function. + */ + bool _is_multi_obj; - private: - - /// Blackbox executable names. - /** - - Not the same as Parameters::_bb_exe. - - NOMAD::Evaluator::_bb_exe is constructed from + /// Model flag. + /** + Identifies if a NOMAD::Evaluator object refers to + a NOMAD::***_Model_Evaluator + */ + bool _is_model_evaluator; + + private: + + /// Blackbox executable names. + /** + - Not the same as Parameters::_bb_exe. + - NOMAD::Evaluator::_bb_exe is constructed from NOMAD::Parameters::_bb_exe. - */ - std::vector<std::string> _bb_exe; - - std::vector<std::string> _sgte_exe; ///< Surrogate executable names. - - /// Number of outputs for each blackbox executable. - std::vector<int> _bb_nbo; - - static bool _force_quit; ///< Flag equal to \c true if ctrl-c is pressed. - - /// Check the constraints to decide if the evaluations have to be stopped. - /** - \param x Point at which the constraints are checked -- \b IN. - \param h_max Maximal feasibility value \c h_max -- \b IN. - \return A boolean equal to \c true if - the evaluations have to be stopped. - */ - bool interrupt_evaluations ( const NOMAD::Eval_Point & x , - const NOMAD::Double & h_max ) const; - - /// Process a blackbox executable name. - /** - \param bb_exe Executable name -- \b IN/OUT. - */ - void process_bb_exe_name ( std::string & bb_exe ) const; + */ + std::vector<std::string> _bb_exe; + + std::vector<std::string> _sgte_exe; ///< Surrogate executable names. + + /// Number of outputs for each blackbox executable. + std::vector<int> _bb_nbo; + + static bool _force_quit; ///< Flag equal to \c true if ctrl-c is pressed. + + /// Check the constraints to decide if the evaluations have to be stopped. + /** + \param x Point at which the constraints are checked -- \b IN. + \param h_max Maximal feasibility value \c h_max -- \b IN. + \return A boolean equal to \c true if + the evaluations have to be stopped. + */ + bool interrupt_evaluations ( const NOMAD::Eval_Point & x , + const NOMAD::Double & h_max ) const; + + /// Process a blackbox executable name. + /** + \param bb_exe Executable name -- \b IN/OUT. + */ + void process_bb_exe_name ( std::string & bb_exe ) const; + + public: + + /// Constructor. + /** + \param p Parameters -- \b IN. + */ + Evaluator ( const NOMAD::Parameters & p ); + + /// Destructor. + virtual ~Evaluator ( void ) {} + + /// Force quit (called by pressing ctrl-c). + static void force_quit ( void ) + { + NOMAD::Evaluator::_force_quit = true; + } + + /// Access to the \c force_quit flag. + /** + \return The \c force_quit flag. + */ + static bool get_force_quit ( void ) + { + return NOMAD::Evaluator::_force_quit; + } + + /// Access to the multi-objective flag. + /** + \return The multi-objective flag. + */ + bool is_multi_obj ( void ) const + { + return _is_multi_obj; + } - public: - - /// Constructor. - /** - \param p Parameters -- \b IN. - */ - Evaluator ( const NOMAD::Parameters & p ); - - /// Destructor. - virtual ~Evaluator ( void ) {} - - /// Force quit (called by pressing ctrl-c). - static void force_quit ( void ) { NOMAD::Evaluator::_force_quit = true; } - - /// Access to the \c force_quit flag. - /** - \return The \c force_quit flag. - */ - static bool get_force_quit ( void ) { return NOMAD::Evaluator::_force_quit; } - - /// Access to the multi-objective flag. - /** - \return The multi-objective flag. - */ - bool is_multi_obj ( void ) const { return _is_multi_obj; } - - /// User pre-processing of a list of points. - /** - - This virtual method is called before the evaluation of a list + /// Access to the model evaluator flag. + /** + \return The model evaluator flag. + */ + virtual bool is_model_evaluator ( void ) const + { + return _is_model_evaluator; + } + + /// User pre-processing of a list of points. + /** + - This virtual method is called before the evaluation of a list of points. - - It allows the user to pre-process the points to be evaluated. - \param pts The list of points -- \b IN/OUT. - */ - virtual void list_of_points_preprocessing - ( std::set<Priority_Eval_Point> & pts ) const {} - - /// User updates after a success. - /** - This virtual method is called every time a new (full) success is made. - \param stats Stats -- \b IN. - \param x Last successful point -- \b IN. - */ - virtual void update_success ( const NOMAD::Stats & stats , - const NOMAD::Eval_Point & x ) {} - - /// User updates after an iteration. - /** - This virtual method is called every time a MADS iteration is terminated. - \param success Success of the iteration -- \b IN. - \param stats Stats -- \b IN. - \param ev_control The NOMAD::Evaluator_Control object -- \b IN. - \param true_barrier Barrier for true evaluations -- \b IN. - \param sgte_barrier Barrier for surrogate evaluations -- \b IN. - \param pareto_front Pareto front -- \b IN. - \param stop Allows the user to stop the algorithm -- \b OUT. - */ - virtual void update_iteration ( NOMAD::success_type success , - const NOMAD::Stats & stats , - const NOMAD::Evaluator_Control & ev_control , - const NOMAD::Barrier & true_barrier , - const NOMAD::Barrier & sgte_barrier , - const NOMAD::Pareto_Front & pareto_front , - bool & stop ) {} - - /// Evaluate the blackbox functions at a given trial point (#1). - /** - - Const version. - - May be user-defined. - - Surrogate or true evaluation depending on the value of \c x.is_surrogate(). - \param x The trial point -- \b IN/OUT. - \param h_max Maximal feasibility value \c h_max -- \b IN. - \param count_eval Flag indicating if the evaluation has to be counted - or not -- \b OUT. - \return A boolean equal to \c false if the evaluation failed. - */ - virtual bool eval_x ( NOMAD::Eval_Point & x , - const NOMAD::Double & h_max , - bool & count_eval ) const; - - /// Evaluate the blackbox functions at a given trial point (#2). - /** - - Non-const version. - - Calls the const version by default. - - May be user-defined. - - Surrogate or true evaluation depending on the value of \c x.is_surrogate(). - \param x The trial point -- \b IN/OUT. - \param h_max Maximal feasibility value \c h_max -- \b IN. - \param count_eval Flag indicating if the evaluation has to be counted - or not -- \b OUT. - \return A boolean equal to \c false if the evaluation failed. - */ - virtual bool eval_x ( NOMAD::Eval_Point & x , - const NOMAD::Double & h_max , - bool & count_eval ) { - return static_cast<const Evaluator *>(this)->eval_x ( x , h_max , count_eval ); - } + - It allows the user to pre-process the points to be evaluated. + \param pts The list of points -- \b IN/OUT. + */ + virtual void list_of_points_preprocessing + ( std::set<Priority_Eval_Point> & pts ) const {} + + /// User updates after a success. + /** + This virtual method is called every time a new (full) success is made. + \param stats Stats -- \b IN. + \param x Last successful point -- \b IN. + */ + virtual void update_success ( const NOMAD::Stats & stats , + const NOMAD::Eval_Point & x ) {} + + /// User updates after an iteration. + /** + This virtual method is called every time a MADS iteration is terminated. + \param success Success of the iteration -- \b IN. + \param stats Stats -- \b IN. + \param ev_control The NOMAD::Evaluator_Control object -- \b IN. + \param true_barrier Barrier for true evaluations -- \b IN. + \param sgte_barrier Barrier for surrogate evaluations -- \b IN. + \param pareto_front Pareto front -- \b IN. + \param stop Allows the user to stop the algorithm -- \b OUT. + */ + virtual void update_iteration ( NOMAD::success_type success , + const NOMAD::Stats & stats , + const NOMAD::Evaluator_Control & ev_control , + const NOMAD::Barrier & true_barrier , + const NOMAD::Barrier & sgte_barrier , + const NOMAD::Pareto_Front & pareto_front , + bool & stop ) {} + + /// Evaluate the blackbox functions at a given trial point (#1). + /** + - Const version. + - May be user-defined. + - Surrogate or true evaluation depending on the value of \c x.is_surrogate(). + \param x The trial point -- \b IN/OUT. + \param h_max Maximal feasibility value \c h_max -- \b IN. + \param count_eval Flag indicating if the evaluation has to be counted + or not -- \b OUT. + \return A boolean equal to \c false if the evaluation failed. + */ + virtual bool eval_x ( NOMAD::Eval_Point & x , + const NOMAD::Double & h_max , + bool & count_eval ) const; + + /// Evaluate the blackbox functions at a given trial point (#2). + /** + - Non-const version. + - Calls the const version by default. + - May be user-defined. + - Surrogate or true evaluation depending on the value of \c x.is_surrogate(). + \param x The trial point -- \b IN/OUT. + \param h_max Maximal feasibility value \c h_max -- \b IN. + \param count_eval Flag indicating if the evaluation has to be counted + or not -- \b OUT. + \return A boolean equal to \c false if the evaluation failed. + */ + virtual bool eval_x ( NOMAD::Eval_Point & x , + const NOMAD::Double & h_max , + bool & count_eval ) + { + return static_cast<const Evaluator *>(this)->eval_x ( x , h_max , count_eval ); + } + + + + /// Evaluate the blackbox functions at a given list of trial points (#1). + /** + - Const version. + - May be user-defined. + - Surrogate or true evaluation depending on the value of \c x.is_surrogate(). + \param x The list of trial points -- \b IN/OUT. + \param h_max Maximal feasibility value \c h_max -- \b IN. + \param count_eval Number of evaluations that are counted -- \b OUT. + \return A boolean equal to \c false if the evaluation failed. + */ + virtual bool eval_x ( std::list<NOMAD::Eval_Point *> &x , + const NOMAD::Double & h_max, + std::list<bool> & count_eval ) const; + + + /// Evaluate the blackbox functions at a given list of trial points (#2). + /** + - Non-Const version. + - May be user-defined. + - Surrogate or true evaluation depending on the value of \c x.is_surrogate(). + \param x The list of trial points -- \b IN/OUT. + \param h_max Maximal feasibility value \c h_max -- \b IN. + \param count_eval Number of evaluations that are counted -- \b OUT. + \return A boolean equal to \c false if the evaluation failed. + */ + virtual bool eval_x ( std::list<NOMAD::Eval_Point *> &x , + const NOMAD::Double & h_max, + std::list<bool> & count_eval ) + { + return static_cast<const Evaluator *>(this)->eval_x ( x , h_max , count_eval ); + } - /// Compute the objective value \c f(x) from the blackbox outputs of a point. - /** - \param x The point -- \b IN/OUT. - */ - virtual void compute_f ( NOMAD::Eval_Point & x ) const; - - /// Compute the feasibility value \c h(x) from the blackbox outputs of a point. - /** - \param x The point -- \b IN/OUT. - */ - void compute_h ( NOMAD::Eval_Point & x ) const; - }; + + + /// Compute the objective value \c f(x) from the blackbox outputs of a point. + /** + \param x The point -- \b IN/OUT. + */ + virtual void compute_f ( NOMAD::Eval_Point & x ) const; + + /// Compute the feasibility value \c h(x) from the blackbox outputs of a point. + /** + \param x The point -- \b IN/OUT. + */ + void compute_h ( NOMAD::Eval_Point & x ) const; + }; } #endif diff --git a/src/Evaluator_Control.cpp b/src/Evaluator_Control.cpp index 56f3302..77b5c10 100644 --- a/src/Evaluator_Control.cpp +++ b/src/Evaluator_Control.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -48,6 +48,7 @@ /* static members initialization */ /*-----------------------------------*/ bool NOMAD::Evaluator_Control::_force_quit = false; +bool NOMAD::Evaluator_Control::_force_evaluation_failure = false; /*---------------------------------------------------------*/ @@ -255,16 +256,18 @@ void NOMAD::Evaluator_Control::process_eval_point // insertion of the Eval_Point in the barriers: barrier.insert(x); - if ( x.get_eval_type() == NOMAD::TRUTH || _p.get_opt_only_sgte() ) { + if ( x.get_eval_type() == NOMAD::TRUTH || _p.get_opt_only_sgte() ) + { // multi-objective: - if ( pareto_front ) { + if ( pareto_front ) + { // insertion of the Eval_Point in the Pareto front: if ( x.is_feasible ( _p.get_h_min() ) && - pareto_front->insert ( x ) && - _p.get_user_calls_enabled() ) - _ev->update_success ( _stats , x ); + pareto_front->insert ( x ) && + _p.get_user_calls_enabled() ) + _ev->update_success ( _stats , x ); } @@ -286,55 +289,47 @@ NOMAD::success_type NOMAD::Evaluator_Control::process_barrier_points NOMAD::dd_type display_degree , NOMAD::search_type search ) const { - b1.reset_success(); - - NOMAD::Eval_Point * modifiable_x; - NOMAD::success_type one_eval_succ; - bool opt_only_sgte = _p.get_opt_only_sgte(); - const std::string & his_file = _p.get_history_file(); - const NOMAD::Eval_Point * last_success = NULL; - const std::list<const NOMAD::Eval_Point *> - & all_inserted = b2.get_all_inserted(); - std::list<const NOMAD::Eval_Point *>::const_iterator - it , end = all_inserted.end(); - for ( it = all_inserted.begin() ; it != end ; ++it ) { - - // insertion in barrier: - modifiable_x = &NOMAD::Cache::get_modifiable_point ( **it ); - - modifiable_x->set_direction ( NULL ); - modifiable_x->set_mesh_index ( NULL ); - modifiable_x->set_poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ); - modifiable_x->set_user_eval_priority ( NOMAD::Double() ); - modifiable_x->set_rand_eval_priority ( NOMAD::Double() ); - - // process evaluation point: - process_eval_point ( **it , b1 , pareto_front ); - - one_eval_succ = b1.get_one_eval_succ(); - if ( one_eval_succ != NOMAD::UNSUCCESSFUL && one_eval_succ >= b1.get_success() ) - last_success = *it; - - // update the history file: - if ( !his_file.empty() && ( opt_only_sgte || - (*it)->get_eval_type() == NOMAD::TRUTH ) ) - write_sol_or_his_file ( _p.get_problem_dir() + his_file , **it , false ); - } - - NOMAD::success_type success = b1.get_success(); - - // display and save only the last success: - if ( last_success ) - display_eval_result ( *last_success , - display_degree , - search , - success , - success ); - - // barrier update: - b1.update_and_reset_success(); + b1.reset_success(); + + NOMAD::Eval_Point * modifiable_x; + NOMAD::success_type one_eval_succ; + const NOMAD::Eval_Point * last_success = NULL; + const std::list<const NOMAD::Eval_Point *> & all_inserted = b2.get_all_inserted(); + std::list<const NOMAD::Eval_Point *>::const_iterator it , end = all_inserted.end(); + for ( it = all_inserted.begin() ; it != end ; ++it ) + { + + // insertion in barrier: + modifiable_x = &NOMAD::Cache::get_modifiable_point ( **it ); + + modifiable_x->set_direction ( NULL ); + modifiable_x->set_poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ); + modifiable_x->set_user_eval_priority ( NOMAD::Double() ); + modifiable_x->set_rand_eval_priority ( NOMAD::Double() ); + + // process evaluation point: + process_eval_point ( **it , b1 , pareto_front ); + + one_eval_succ = b1.get_one_eval_succ(); + if ( one_eval_succ != NOMAD::UNSUCCESSFUL && one_eval_succ >= b1.get_success() ) + last_success = *it; - return success; + } + + NOMAD::success_type success = b1.get_success(); + + // display and save only the last success: + if ( last_success && display_degree == NOMAD::FULL_DISPLAY) + display_eval_result ( *last_success , + display_degree , + search , + success , + success ); + + // barrier update: + b1.update_and_reset_success(); + + return success; } /*---------------------------------------------------------*/ @@ -367,12 +362,14 @@ void NOMAD::Evaluator_Control::stats_file ( const std::string & file_name std::string fn = _p.get_problem_dir() + file_name; std::ofstream fout ( fn.c_str() , std::ios::app ); - if ( !fout.fail() ) { + if ( !fout.fail() ) + { fout.setf ( std::ios::fixed ); fout.precision ( NOMAD::DISPLAY_PRECISION_BB ); display_stats ( false , fout , _p.get_stats_file() , x , feasible , multi_obj ); } - else { + else + { const NOMAD::Display & out = _p.out(); if ( out.get_gen_dd() != NOMAD::NO_DISPLAY && out.get_gen_dd() != NOMAD::MINIMAL_DISPLAY) out << std::endl @@ -394,207 +391,236 @@ void NOMAD::Evaluator_Control::display_stats bool feasible , const NOMAD::Point * multi_obj ) const { - if ( stats.empty() ) { + if ( stats.empty() ) + { #ifndef R_VERSION - out << std::endl; + out << std::endl; #endif - return; - } - - if ( header ) { + return; + } + + if ( header ) + { #ifndef R_VERSION - out << std::endl; + out << std::endl; #endif - } - - NOMAD::Double f; - const NOMAD::Point * sol = NULL; - const NOMAD::Point * bbo = NULL; - const NOMAD::Signature * signature = NULL; - int bbe = _stats.get_bb_eval(); - int real_time = _stats.get_real_time(); - int i; - - // this integer is used for the default width display - // of the various stats on the number of evaluations: - int max_bbe = _p.get_max_bb_eval(); - if ( _p.get_max_sgte_eval() > max_bbe ) - max_bbe = _p.get_max_sgte_eval(); - if ( _p.get_max_sim_bb_eval() > max_bbe ) - max_bbe = _p.get_max_sim_bb_eval(); - if ( _p.get_max_eval() > max_bbe ) - max_bbe = _p.get_max_eval(); - - if ( x ) - { - signature = x->get_signature(); - f = (feasible) ? x->get_f() : NOMAD::INF; - sol = x; - bbo = &(x->get_bb_outputs()); - _last_stats_tag = x->get_tag(); - _last_stats_bbe = bbe; - } + } + + NOMAD::Double f; + const NOMAD::Point * sol = NULL; + const NOMAD::Point * bbo = NULL; + const NOMAD::Signature * signature = NULL; + int bbe = _stats.get_bb_eval(); + int real_time = _stats.get_real_time(); + int blk_bbe = _stats.get_block_eval(); + int i; + + // this integer is used for the default width display + // of the various stats on the number of evaluations: + int max_bbe = _p.get_max_bb_eval(); + if ( _p.get_max_sgte_eval() > max_bbe ) + max_bbe = _p.get_max_sgte_eval(); + if ( _p.get_max_sim_bb_eval() > max_bbe ) + max_bbe = _p.get_max_sim_bb_eval(); + if ( _p.get_max_eval() > max_bbe ) + max_bbe = _p.get_max_eval(); + + if ( x ) + { + signature = x->get_signature(); + f = (feasible) ? x->get_f() : NOMAD::INF; + sol = x; + bbo = &(x->get_bb_outputs()); + + if (bbe < _last_stats_bbe && ! multi_obj) + return; - std::string s1 , format; - std::list<std::string>::const_iterator it , end = stats.end(); - for ( it = stats.begin() ; it != end ; ++it ) { + _last_stats_tag = x->get_tag(); + _last_stats_bbe = bbe; + } + - if ( it->empty() ) { + + std::string s1 , format; + std::list<std::string>::const_iterator it , end = stats.end(); + for ( it = stats.begin() ; it != end ; ++it ) + { + + if ( it->empty() ) + { #ifndef R_VERSION - out << "\t"; + out << "\t"; #endif - } - else { - - if ( header ) { + } + else { + + if ( header ) + { #ifndef R_VERSION - s1 = *it; - NOMAD::Display::extract_display_format ( s1 , format ); - out << s1; + s1 = *it; + NOMAD::Display::extract_display_format ( s1 , format ); + out << s1; #endif - } - - else { - - // get the stats type: - NOMAD::display_stats_type dst - = NOMAD::Display::get_display_stats_type ( *it ); - - // some stats types are disables in the multi-objective case: - if ( multi_obj && - ( dst == NOMAD::DS_SIM_BBE || - dst == NOMAD::DS_BBE || - dst == NOMAD::DS_SGTE || - dst == NOMAD::DS_EVAL || - dst == NOMAD::DS_TIME || - dst == NOMAD::DS_STAT_SUM || - dst == NOMAD::DS_STAT_AVG ) ) - dst = NOMAD::DS_UNDEFINED; - - // display the stats: - switch ( dst ) { - case NOMAD::DS_UNDEFINED: - s1 = *it; - NOMAD::Display::extract_display_format ( s1 , format ); - out << s1; - break; - case NOMAD::DS_OBJ: - if ( multi_obj ) - display_stats_point ( out , stats , it , multi_obj ); - else { + } + + else + { + + // get the stats type: + NOMAD::display_stats_type dst + = NOMAD::Display::get_display_stats_type ( *it ); + + // some stats types are disables in the multi-objective case: + if ( multi_obj && + ( dst == NOMAD::DS_SIM_BBE || + dst == NOMAD::DS_BBE || + dst == NOMAD::DS_SGTE || + dst == NOMAD::DS_EVAL || + dst == NOMAD::DS_TIME || + dst == NOMAD::DS_STAT_SUM || + dst == NOMAD::DS_STAT_AVG ) ) + dst = NOMAD::DS_UNDEFINED; + + // display the stats: + switch ( dst ) + { + case NOMAD::DS_UNDEFINED: + s1 = *it; + NOMAD::Display::extract_display_format ( s1 , format ); + out << s1; + break; + case NOMAD::DS_OBJ: + if ( multi_obj ) + display_stats_point ( out , stats , it , multi_obj ); + else + { #ifdef R_VERSION - { - std::ostringstream oss; - display_stats_real ( oss , f , format ); - Rprintf ( "%s" , oss.str().c_str() ); - } + { + std::ostringstream oss; + display_stats_real ( oss , f , format ); + Rprintf ( "%s" , oss.str().c_str() ); + } #else - display_stats_real ( out , f , format ); + display_stats_real ( out , f , format ); #endif - format.clear(); - } - break; - case NOMAD::DS_MESH_INDEX: - display_stats_int ( out , - NOMAD::Mesh::get_mesh_index() , - 10*L_LIMITS , - format ); - format.clear(); - break; - case NOMAD::DS_DELTA_M: - case NOMAD::DS_MESH_SIZE: - { - if ( signature ) { - NOMAD::Point delta_m; - signature->get_mesh().get_delta_m ( delta_m , - NOMAD::Mesh::get_mesh_index() ); - display_stats_point ( out , stats , it , &delta_m ); - } - else - out << "-"; - } - break; - case NOMAD::DS_DELTA_P: - case NOMAD::DS_POLL_SIZE: - { - if ( signature ) { - NOMAD::Point delta_p; - signature->get_mesh().get_delta_p ( delta_p , - NOMAD::Mesh::get_mesh_index() ); - display_stats_point ( out , stats , it , &delta_p ); - } - else - out << "-"; - } - break; - case NOMAD::DS_SIM_BBE: - display_stats_int ( out , _stats.get_sim_bb_eval() , max_bbe , format ); - format.clear(); - break; - case NOMAD::DS_BBE: - + format.clear(); + } + break; + case NOMAD::DS_MESH_INDEX: + { + if ( signature ) + { + NOMAD::Point mesh_indices=signature->get_mesh()->get_mesh_indices(); + display_stats_point ( out , stats , it , &mesh_indices ); + } + else + out << "-"; + + + break; + } + case NOMAD::DS_DELTA_M: + case NOMAD::DS_MESH_SIZE: + { + if ( signature ) + { + NOMAD::Point delta; + signature->get_mesh()->get_delta ( delta ); + display_stats_point ( out , stats , it , &delta ); + } + else + out << "-"; + } + break; + case NOMAD::DS_DELTA_P: + case NOMAD::DS_POLL_SIZE: + { + if ( signature ) + { + NOMAD::Point Delta; + signature->get_mesh()->get_Delta ( Delta ); + display_stats_point ( out , stats , it , &Delta ); + + } + else + out << "-"; + } + break; + case NOMAD::DS_SIM_BBE: + display_stats_int ( out , _stats.get_sim_bb_eval() , max_bbe , format ); + format.clear(); + break; + case NOMAD::DS_BBE: + #ifdef R_VERSION - { - std::ostringstream oss; - display_stats_int ( oss , bbe , max_bbe , format ); - Rprintf ( "\t%s " , oss.str().c_str() ); - } + { + std::ostringstream oss; + display_stats_int ( oss , bbe , max_bbe , format ); + Rprintf ( "\t%s " , oss.str().c_str() ); + } #else - { - - display_stats_int ( out , bbe , max_bbe , format ); - } + { + display_stats_int ( out , bbe , max_bbe , format ); + } #endif - format.clear(); - break; - case NOMAD::DS_SGTE: - display_stats_int ( out , _stats.get_sgte_eval() , max_bbe , format ); - format.clear(); - break; - case NOMAD::DS_EVAL: - display_stats_int ( out , _stats.get_eval() , max_bbe , format ); - format.clear(); - break; - case NOMAD::DS_TIME: - display_stats_int ( out , real_time , 3600 , format ); - format.clear(); - break; - case NOMAD::DS_STAT_SUM: - display_stats_real ( out , _stats.get_stat_sum() , format ); - format.clear(); - break; - case NOMAD::DS_STAT_AVG: - display_stats_real ( out , _stats.get_stat_avg() , format ); - format.clear(); - break; - case NOMAD::DS_BBO: - display_stats_point ( out , stats , it , bbo ); - break; - case NOMAD::DS_SOL: - display_stats_point ( out , stats , it , sol , signature->get_input_type() ); - break; - case NOMAD::DS_VAR: - ++it; - NOMAD::atoi ( *it , i ); - if ( sol ) - if (format.empty()) - display_stats_type ( out , (*sol)[i] , (signature->get_input_type())[i] ); - else - display_stats_real ( out , (*sol)[i] , format ); - else - out << "-"; - format.clear(); - break; + format.clear(); + break; + case NOMAD::DS_BLK_EVA: + { + display_stats_int ( out , blk_bbe , max_bbe , format ); + } + format.clear(); + break; + + case NOMAD::DS_SGTE: + //display_stats_int ( out , sgte_bbe , max_bbe , format ); + display_stats_int ( out , _stats.get_sgte_eval() , max_bbe , format ); + format.clear(); + break; + case NOMAD::DS_EVAL: + display_stats_int ( out , _stats.get_eval() , max_bbe , format ); + format.clear(); + break; + case NOMAD::DS_TIME: + display_stats_int ( out , real_time , 3600 , format ); + format.clear(); + break; + case NOMAD::DS_STAT_SUM: + display_stats_real ( out , _stats.get_stat_sum() , format ); + format.clear(); + break; + case NOMAD::DS_STAT_AVG: + display_stats_real ( out , _stats.get_stat_avg() , format ); + format.clear(); + break; + case NOMAD::DS_BBO: + display_stats_point ( out , stats , it , bbo ); + break; + case NOMAD::DS_SOL: + display_stats_point ( out , stats , it , sol , signature->get_input_type() ); + break; + case NOMAD::DS_VAR: + ++it; + NOMAD::atoi ( *it , i ); + if ( sol ) + if (format.empty()) + display_stats_type ( out , (*sol)[i] , (signature->get_input_type())[i] ); + else + display_stats_real ( out , (*sol)[i] , format ); + else + out << "-"; + format.clear(); + break; + } + } + } } - } - } - } - - if ( !header ) + + if ( !header ) #ifdef R_VERSION - Rprintf("\n"); + Rprintf("\n"); #else - out << std::endl; + out << std::endl; #endif } @@ -713,11 +739,11 @@ void NOMAD::Evaluator_Control::display_stats_point if ( !s1.empty() ) out << s1; - if ( !s2.empty() && i < n-1 && s2.find("(VNS)")==std::string::npos && s2.find("(PhaseOne)")==std::string::npos && s2.find("(LH)")==std::string::npos && s2.find("(ExtendedPoll)")==std::string::npos ) + if ( !s2.empty() && i < n-1 && s2.find("(VNS)")==std::string::npos && s2.find("(PhaseOne)")==std::string::npos && s2.find("(LH)")==std::string::npos && s2.find("(ExtendedPoll)")==std::string::npos ) out << " " << s2; out << " "; } - if ( !s2.empty() && (s2.find("(VNS)")!=std::string::npos || s2.find("(PhaseOne)")!=std::string::npos || s2.find("(LH)")!=std::string::npos || s2.find("(ExtendedPoll)")!=std::string::npos)) + if ( !s2.empty() && (s2.find("(VNS)")!=std::string::npos || s2.find("(PhaseOne)")!=std::string::npos || s2.find("(LH)")!=std::string::npos || s2.find("(ExtendedPoll)")!=std::string::npos)) out << s2; } } @@ -798,15 +824,16 @@ void NOMAD::Evaluator_Control::write_sol_or_his_file << file_name << "\'" << std::endl << std::endl; } + /*---------------------------------------------------------*/ /* display evaluation result (private) */ /*---------------------------------------------------------*/ void NOMAD::Evaluator_Control::display_eval_result ( const NOMAD::Eval_Point & x , - NOMAD::dd_type display_degree , - NOMAD::search_type search , - NOMAD::success_type one_eval_success , - NOMAD::success_type success ) const + NOMAD::dd_type display_degree , + NOMAD::search_type search , + NOMAD::success_type one_eval_success , + NOMAD::success_type success ) const { const NOMAD::Display & out = _p.out(); int cur_bbe; @@ -833,10 +860,10 @@ void NOMAD::Evaluator_Control::display_eval_result if ( !_p.get_opt_only_sgte() ) return; - cur_bbe = _sgte_cache->size(); + cur_bbe = _stats.get_sgte_eval(); } else - cur_bbe = _cache->size(); + cur_bbe = _stats.get_eval(); const std::string & stats_file_name = _p.get_stats_file_name(); bool feas_x = x.is_feasible ( _p.get_h_min() ); @@ -844,7 +871,7 @@ void NOMAD::Evaluator_Control::display_eval_result // update the history file: // (contains surrogate evaluations if opt_only_sgte==true) const std::string & his_file = _p.get_history_file(); - if ( !his_file.empty() && cur_bbe > _last_history_bbe ) + if ( !his_file.empty() && cur_bbe > _last_history_bbe) { write_sol_or_his_file ( _p.get_problem_dir() + his_file , x , false ); _last_history_bbe = cur_bbe; @@ -858,12 +885,12 @@ void NOMAD::Evaluator_Control::display_eval_result // save the current solution in file: write_solution_file ( x ); - bool ds_ok = ( cur_bbe > _last_stats_bbe ) && - ( _p.get_display_all_eval() || - ( one_eval_success == NOMAD::FULL_SUCCESS && feas_x ) ); + bool ds_ok = ( cur_bbe > _last_stats_bbe) && + ( _p.get_display_all_eval() || + ( one_eval_success == NOMAD::FULL_SUCCESS && feas_x ) ); // normal display and minimal: - if ( (display_degree == NOMAD::NORMAL_DISPLAY || display_degree == NOMAD::MINIMAL_DISPLAY )&& ds_ok ) + if ( (display_degree == NOMAD::NORMAL_DISPLAY || display_degree == NOMAD::MINIMAL_DISPLAY ) && ds_ok ) display_stats ( false , out , _p.get_display_stats() , &x , feas_x , NULL ); // detailed display: else if ( display_degree == NOMAD::FULL_DISPLAY ) @@ -885,11 +912,13 @@ void NOMAD::Evaluator_Control::display_eval_result if ( x.is_eval_ok() ) out << " [ h=" << x.get_h() << " f=" << x.get_f() << " ]" << std::endl; + else if (x.check_rejected()) + out << ": evaluation rejected by user (this may alter convergence properties!)" << std::endl; else - out << ": evaluation failed" << std::endl; + out << ": evaluation failed (you may need to check the source of the problem)." << std::endl; } - if ( _p.get_display_all_eval() && cur_bbe > _last_stats_bbe ) + if ( _p.get_display_all_eval() && cur_bbe > _last_stats_bbe ) { if ( display_degree == NOMAD::NORMAL_DISPLAY || display_degree == NOMAD::MINIMAL_DISPLAY ) @@ -901,6 +930,7 @@ void NOMAD::Evaluator_Control::display_eval_result } } + /*-------------------------------------------*/ /* search a point in the cache */ /*-------------------------------------------*/ @@ -916,98 +946,100 @@ bool NOMAD::Evaluator_Control::cache_check const NOMAD::Double & h_max , NOMAD::dd_type display_degree ) const { - NOMAD::eval_type x_eval_type = x->get_eval_type(); - const NOMAD::Eval_Point * cache_x = NULL; - - // first cache check: - if ( x->is_in_cache() ) - cache_x = x; - - // second cache check: - else - cache_x = ( ( x->get_eval_type() == NOMAD::TRUTH ) ? - _cache : _sgte_cache )->find ( *x ); - - // cache hit: transfer some data from x to cache_x: - if ( cache_x ) { - - if ( x_eval_type != cache_x->get_eval_type() ) - throw NOMAD::Exception ( "Evaluator_Control.cpp" , __LINE__ , - "Evaluator_Control::cache_check(): eval and cache pts have different eval_type" ); - - if ( cache_x->is_eval_ok() ) { - - NOMAD::Eval_Point * modifiable_cache_x - = &NOMAD::Cache::get_modifiable_point ( *cache_x ); - - // if wrong number of outputs, reset cache_x._bb_outputs: - { - int m = _p.get_bb_nb_outputs(); - if ( cache_x->get_bb_outputs().size() != m ) - modifiable_cache_x->set_bb_output ( NOMAD::Point ( m ) ); - } - - modifiable_cache_x->set_signature ( x->get_signature () ); - modifiable_cache_x->set_direction ( x->get_direction () ); - modifiable_cache_x->set_mesh_index ( x->get_mesh_index () ); - // The point in cache is updated for the poll center to correspond to the new poll center of x (important for poll reduction) - modifiable_cache_x->set_poll_center ( x->get_poll_center () ); - modifiable_cache_x->set_poll_center_type ( x->get_poll_center_type () ); - modifiable_cache_x->set_user_eval_priority ( x->get_user_eval_priority() ); - modifiable_cache_x->set_rand_eval_priority ( x->get_rand_eval_priority() ); - + NOMAD::eval_type x_eval_type = x->get_eval_type(); + const NOMAD::Eval_Point * cache_x = NULL; + + // first cache check: + if ( x->is_in_cache() ) + cache_x = x; + // second cache check: + else + cache_x = ( ( x->get_eval_type() == NOMAD::TRUTH ) ? + _cache : _sgte_cache )->find ( *x ); + + // cache hit: transfer some data from x to cache_x: + if ( cache_x ) + { + + if ( x_eval_type != cache_x->get_eval_type() ) + throw NOMAD::Exception ( "Evaluator_Control.cpp" , __LINE__ , + "Evaluator_Control::cache_check(): eval and cache pts have different eval_type" ); + + if ( cache_x->is_eval_ok() ) + { + + NOMAD::Eval_Point * modifiable_cache_x + = &NOMAD::Cache::get_modifiable_point ( *cache_x ); + + // if wrong number of outputs, reset cache_x._bb_outputs: + { + int m = _p.get_bb_nb_outputs(); + if ( cache_x->get_bb_outputs().size() != m ) + modifiable_cache_x->set_bb_output ( NOMAD::Point ( m ) ); + } + + modifiable_cache_x->set_signature ( x->get_signature () ); + modifiable_cache_x->set_direction ( x->get_direction () ); + modifiable_cache_x->set_poll_center ( x->get_poll_center () ); + modifiable_cache_x->set_poll_center_type ( x->get_poll_center_type () ); + modifiable_cache_x->set_user_eval_priority ( x->get_user_eval_priority() ); + modifiable_cache_x->set_rand_eval_priority ( x->get_rand_eval_priority() ); + #ifdef MODEL_STATS - modifiable_cache_x->set_model_data ( *x ); + modifiable_cache_x->set_model_data ( *x ); #endif - - // set_f, set_h, and set_EB_ok: - _ev->compute_f ( *modifiable_cache_x ); - _ev->compute_h ( *modifiable_cache_x ); + + // set_f, set_h, and set_EB_ok: + _ev->compute_f ( *modifiable_cache_x ); + _ev->compute_h ( *modifiable_cache_x ); + } } - } - - // point in cache but evaluation is to be made again: - if ( cache_x && cache_x->is_eval_ok() && - ( !cache_x->get_f().is_defined() || - ( cache_x->is_EB_ok() && - !cache_x->get_bb_outputs().is_complete() && - cache_x->get_h().is_defined() && - cache_x->get_h() < h_max ) ) ) { - x = cache_x; - cache_x = NULL; - } - - // point in cache: - if ( cache_x ) { - - _stats.add_cache_hit(); - - // displays: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - const NOMAD::Display & out = _p.out(); - if ( cache_x->get_eval_type() == NOMAD::SGTE ) - out << "surrogate "; - out << "cache hit: #" << x->get_tag() - << " --> #" << cache_x->get_tag() << std::endl; + + // point in cache but evaluation is to be made again: + if ( cache_x && cache_x->is_eval_ok() && + ( !cache_x->get_f().is_defined() || + ( cache_x->is_EB_ok() && + !cache_x->get_bb_outputs().is_complete() && + cache_x->get_h().is_defined() && + cache_x->get_h() < h_max ) ) ) + { + x = cache_x; + cache_x = NULL; + } + + // point in cache: + if ( cache_x ) + { + + _stats.add_cache_hit(); + + // displays: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + const NOMAD::Display & out = _p.out(); + if ( cache_x->get_eval_type() == NOMAD::SGTE ) + out << "surrogate "; + out << "cache hit: #" << x->get_tag() + << " --> #" << cache_x->get_tag() << std::endl; + } + + // process the Eval_Point taken in cache: + process_eval_point ( *cache_x , + ( cache_x->get_eval_type() == NOMAD::TRUTH ) ? + true_barrier : sgte_barrier , + pareto_front ); + + // count the (simulated) bb eval ? + int index_cnt_eval = _p.get_index_cnt_eval(); + if ( index_cnt_eval >= 0 && cache_x->get_bb_outputs()[index_cnt_eval] == 0.0 ) + count_eval = false; + + x = cache_x; + + return true; } - - // process the Eval_Point taken in cache: - process_eval_point ( *cache_x , - ( cache_x->get_eval_type() == NOMAD::TRUTH ) ? - true_barrier : sgte_barrier , - pareto_front ); - - // count the (simulated) bb eval ? - int index_cnt_eval = _p.get_index_cnt_eval(); - if ( index_cnt_eval >= 0 && cache_x->get_bb_outputs()[index_cnt_eval] == 0.0 ) - count_eval = false; - - x = cache_x; - - return true; - } - - return false; + + return false; } /*----------------------------------------------------*/ @@ -1041,6 +1073,8 @@ void NOMAD::Evaluator_Control::eval_point ( NOMAD::Eval_Point & x // evaluation of the point: // ------------------------ bool eval_ok = true; + + NOMAD::Evaluator_Control::_force_evaluation_failure=false; { // 1. scaling: @@ -1049,23 +1083,31 @@ void NOMAD::Evaluator_Control::eval_point ( NOMAD::Eval_Point & x eval_x->scale(); // 2.1. evaluation: - try { + try + { eval_ok = _ev->eval_x ( *eval_x , h_max , count_eval ); + } - catch ( ... ) { - eval_ok = false; - } + catch ( exception & e ) + { + throw NOMAD::Exception ( "Evaluator_control.cpp" , __LINE__ , e.what() ); + } + // 2.2. check the nan's: if ( eval_ok && eval_x->check_nan() ) eval_ok = false; + + if ( _force_evaluation_failure ) + eval_ok = false; // 3. unscaling: if ( do_scaling ) eval_x->unscale(); } - if ( eval_ok ) { + if ( eval_ok ) + { eval_x->set_eval_status ( NOMAD::EVAL_OK ); @@ -1074,7 +1116,8 @@ void NOMAD::Evaluator_Control::eval_point ( NOMAD::Eval_Point & x _ev->compute_h ( *eval_x ); } - else { + else + { eval_x->set_eval_status ( NOMAD::EVAL_FAIL ); _stats.add_failed_eval(); } @@ -1100,57 +1143,142 @@ void NOMAD::Evaluator_Control::eval_point ( NOMAD::Eval_Point & x x.set_in_cache ( false ); } - // process the evaluated point: - if ( eval_ok && x.is_in_cache() ) - process_eval_point ( *eval_x , - ( eval_x->get_eval_type() == NOMAD::TRUTH ) ? - true_barrier : sgte_barrier , - pareto_front ); + } + +} + + +/*----------------------------------------------------*/ +/* eval points in a list (private) */ +/*----------------------------------------------------*/ +void NOMAD::Evaluator_Control::eval_points ( std::list<NOMAD::Eval_Point *> & list_eval , + NOMAD::Barrier & true_barrier , + NOMAD::Barrier & sgte_barrier , + NOMAD::Pareto_Front * pareto_front , + std::list<bool> & count_list_eval, + bool & stop , + NOMAD::stop_type & stop_reason , + const NOMAD::Double & h_max ) +{ + int max_bb_eval = _p.get_max_bb_eval(); + int max_sgte_eval = _p.get_max_sgte_eval(); + + std::list<NOMAD::Eval_Point*>::iterator it_begin=list_eval.begin(); + + if ( ( (*it_begin)->get_eval_type() == NOMAD::TRUTH && max_bb_eval != 0 ) || + ( (*it_begin)->get_eval_type() == NOMAD::SGTE && max_sgte_eval != 0 ) ) + { + + // 1. Pre-evaluation tests and scaling + for ( std::list<NOMAD::Eval_Point*>::iterator it=it_begin;it!=list_eval.end();++it) + { + // get the signature: + NOMAD::Signature * signature = (*it)->get_signature(); + if ( !signature ) + throw NOMAD::Exception ( "Evaluator_Control.cpp" , __LINE__ , + "Evaluator_Control::eval_points(): the point has no signature" ); + + // Scaling before evaluation of the points: + bool do_scaling = signature->get_scaling().is_defined(); + if ( do_scaling ) + (*it)->scale(); + + } - // count the bb evaluation: - if ( count_eval ) + // 2. list evaluation: + bool eval_list_ok = true; + NOMAD::Evaluator_Control::_force_evaluation_failure=false; + + try { - if ( x.get_eval_type() == NOMAD::SGTE ) - _stats.add_sgte_eval(); - else - { - // current mads bbe evaluation - _stats.add_bb_eval(); - - } + eval_list_ok=_ev->eval_x ( list_eval , h_max,count_list_eval ); } + catch ( exception & e ) + { + throw NOMAD::Exception ( "Evaluator_control.cpp" , __LINE__ , e.what() ); + } + + if ( _force_evaluation_failure ) + eval_list_ok = false; + + + // One block of evaluations is counted + if ( eval_list_ok ) + _stats.add_one_block_eval(); + + - // count the output stats (STAT_SUM and STAT_AVG): - if ( _p.check_stat_sum() || _p.check_stat_avg() ) + // 3. Post list evaluation checks and operation + std::list<bool>::iterator it_count=count_list_eval.begin(); + for ( std::list<NOMAD::Eval_Point*>::iterator it=it_begin;it!=list_eval.end();++it,++it_count) { + bool eval_ok=true; + bool eval_rejected=false; - count_output_stats(x); + // 3.1. check the nan's and list evaluation failure: + if ( !eval_list_ok || (*it)->check_nan() ) + eval_ok = false; - // check STAT_SUM_TARGET: - NOMAD::Double sum_target = _p.get_stat_sum_target(); - if ( sum_target.is_defined() ) { - NOMAD::Double sum = _stats.get_stat_sum(); - if ( !stop && sum.is_defined() && sum >= sum_target ) { - stop = true; - stop_reason = NOMAD::STAT_SUM_TARGET_REACHED; + if ((*it)->check_rejected()) + { + eval_rejected=true; + eval_ok=false; + } + + // 3.2 unscaling: + if ( (*it)->get_signature()->get_scaling().is_defined() ) + (*it)->unscale(); + + + if ( eval_ok && (*it)->get_eval_status()!=NOMAD::EVAL_FAIL ) + { + (*it)->set_eval_status ( NOMAD::EVAL_OK ); + + // set_f, set_h and set_EB_ok: + _ev->compute_f ( *(*it) ); + _ev->compute_h ( *(*it)); + + } + else if (!eval_rejected) + { + (*it)->set_eval_status ( NOMAD::EVAL_FAIL ); + _stats.add_failed_eval(); + } // Do nothing if eval has been rejected + + // insertion in cache even if is_eval_ok == false. Exception: a point that has been rejected by user is not put in the cache. + if ( !(*it)->is_in_cache() && !eval_rejected ) + { + + int size_before , size_after; + + if ( (*it)->get_eval_type() == NOMAD::SGTE ) + { + size_before = _sgte_cache->size(); + _sgte_cache->insert(*(*it)); + size_after = _sgte_cache->size(); + } + else + { + size_before = _cache->size(); + _cache->insert(*(*it)); + size_after = _cache->size(); } + + if ( size_after == size_before ) + (*it)->set_in_cache ( false ); } + + + // count the output stats (STAT_SUM and STAT_AVG): + if ( (_p.check_stat_sum() || _p.check_stat_avg()) && !eval_rejected) + count_output_stats(*(*it)); + } } - - // check the number of blackbox evaluations: - if ( !stop ) { - if ( max_bb_eval > 0 && _stats.get_bb_eval() >= max_bb_eval ) { - stop = true; - stop_reason = NOMAD::MAX_BB_EVAL_REACHED; - } - if ( max_sgte_eval > 0 && _stats.get_sgte_eval() >= max_sgte_eval ) { - stop = true; - stop_reason = NOMAD::MAX_SGTE_EVAL_REACHED; - } - } } + + /*-------------------------------------------*/ /* check stopping criteria (private) */ /*-------------------------------------------*/ @@ -1161,86 +1289,132 @@ void NOMAD::Evaluator_Control::check_stopping_criteria bool & stop , NOMAD::stop_type & stop_reason ) const { - // check the time: - if ( !stop && - _p.get_max_time() > 0 && - _stats.get_real_time() >= _p.get_max_time() ) { - stop = true; - stop_reason = NOMAD::MAX_TIME_REACHED; - } - - // count an evaluation or a simulated blackbox evaluation: - if ( x.get_eval_type() == NOMAD::TRUTH ) { - _stats.add_eval(); - if ( count_eval && !x.get_current_run() ) - _stats.add_sim_bb_eval(); - } + // check the time: + if ( !stop && + _p.get_max_time() > 0 && + _stats.get_real_time() >= _p.get_max_time() ) + { + stop = true; + stop_reason = NOMAD::MAX_TIME_REACHED; + } + + // count an evaluation or a simulated blackbox evaluation: + if ( x.get_eval_type() == NOMAD::TRUTH ) + { + _stats.add_eval(); + if ( count_eval && !x.get_current_run() ) + _stats.add_sim_bb_eval(); + } + + + // check STAT_SUM_TARGET: + if ( !stop && + (_p.check_stat_sum() || _p.check_stat_avg())) + { + + NOMAD::Double sum_target = _p.get_stat_sum_target(); + if ( sum_target.is_defined() ) + { + NOMAD::Double sum = _stats.get_stat_sum(); + if ( sum.is_defined() && sum >= sum_target ) + { + stop = true; + stop_reason = NOMAD::STAT_SUM_TARGET_REACHED; + } + } + } + + // check the number of blackbox evaluations: + if ( !stop ) + { + int max_bb_eval = _p.get_max_bb_eval(); + int max_sgte_eval = _p.get_max_sgte_eval(); + if ( max_bb_eval > 0 && _stats.get_bb_eval() >= max_bb_eval ) + { + stop = true; + stop_reason = NOMAD::MAX_BB_EVAL_REACHED; + } + if ( max_sgte_eval > 0 && _stats.get_sgte_eval() >= max_sgte_eval ) + { + stop = true; + stop_reason = NOMAD::MAX_SGTE_EVAL_REACHED; + } + } - // check the stopping condition MAX_EVAL: - if ( !stop && - _p.get_max_eval() > 0 && - _stats.get_eval() >= _p.get_max_eval() ) { - stop = true; - stop_reason = NOMAD::MAX_EVAL_REACHED; - } - - // check the stopping condition MAX_SIM_BB_EVAL: - if ( !stop && - _p.get_max_sim_bb_eval() > 0 && - _stats.get_sim_bb_eval() >= _p.get_max_sim_bb_eval() ) { - stop = true; - stop_reason = NOMAD::MAX_SIM_BB_EVAL_REACHED; - } - - // check the stopping conditions F_TARGET and FEAS_REACHED - // (for phase one: the evaluations must stop if all EB - // constraints are satisfied, but some PB constraints can - // be violated) - if ( !stop && - x.is_eval_ok() && - ( _p.get_opt_only_sgte() || - x.get_eval_type() == NOMAD::TRUTH ) ) { - - bool feasible = x.is_feasible ( _p.get_h_min() ); - - // check FEAS_REACHED: - if ( feasible && _p.get_stop_if_feasible() ) { - stop = true; - stop_reason = NOMAD::FEAS_REACHED; - } - - // check F_TARGET: - { - const NOMAD::Point & f_target = _p.get_f_target(); - const std::list<int> & index_obj = _p.get_index_obj(); - std::list<int>::const_iterator index_obj_end = index_obj.end(); - bool check_f_target = f_target.is_defined(); - int nb_to_check = (check_f_target) ? - f_target.nb_defined() : 0; - - if ( check_f_target && ( feasible || search == NOMAD::LH_SEARCH_P1 ) ) { - const NOMAD::Point & bbo = x.get_bb_outputs(); - bool chk = true; - int k = 0; - int cnt = 0; - for ( std::list<int>::const_iterator it = index_obj.begin(); - it != index_obj_end ; ++it , ++k ) { - if ( bbo[*it].is_defined() && f_target[k].is_defined() ) { - if ( f_target[k] < bbo[*it] ) { - chk = false; - break; - } - cnt++; - } + // check the stopping condition MAX_EVAL: + if ( !stop && + _p.get_max_eval() > 0 && + _stats.get_eval() >= _p.get_max_eval() ) + { + stop = true; + stop_reason = NOMAD::MAX_EVAL_REACHED; } - if ( chk && cnt == nb_to_check ) { - stop = true; - stop_reason = NOMAD::F_TARGET_REACHED; + // check the stopping condition MAX_SIM_BB_EVAL: + if ( !stop && + _p.get_max_sim_bb_eval() > 0 && + _stats.get_sim_bb_eval() >= _p.get_max_sim_bb_eval() ) + { + stop = true; + stop_reason = NOMAD::MAX_SIM_BB_EVAL_REACHED; + } + + // check the stopping conditions F_TARGET and FEAS_REACHED + // (for phase one: the evaluations must stop if all EB + // constraints are satisfied, but some PB constraints can + // be violated) + if ( !stop && + x.is_eval_ok() && + ( _p.get_opt_only_sgte() || + x.get_eval_type() == NOMAD::TRUTH ) ) + { + + bool feasible = x.is_feasible ( _p.get_h_min() ); + + // check FEAS_REACHED: + if ( feasible && _p.get_stop_if_feasible() ) + { + stop = true; + stop_reason = NOMAD::FEAS_REACHED; + } + + // check F_TARGET: + { + const NOMAD::Point & f_target = _p.get_f_target(); + const std::list<int> & index_obj = _p.get_index_obj(); + std::list<int>::const_iterator index_obj_end = index_obj.end(); + bool check_f_target = f_target.is_defined(); + int nb_to_check = (check_f_target) ? + f_target.nb_defined() : 0; + + if ( check_f_target && ( feasible || search == NOMAD::LH_SEARCH_P1 ) ) + { + const NOMAD::Point & bbo = x.get_bb_outputs(); + bool chk = true; + int k = 0; + int cnt = 0; + for ( std::list<int>::const_iterator it = index_obj.begin(); + it != index_obj_end ; ++it , ++k ) + { + if ( bbo[*it].is_defined() && f_target[k].is_defined() ) + { + if ( f_target[k] < bbo[*it] ) + { + chk = false; + break; + } + cnt++; + } + } + + if ( chk && cnt == nb_to_check ) + { + stop = true; + stop_reason = NOMAD::F_TARGET_REACHED; + } + } + } } - } - } - } } /*-------------------------------------------------------*/ @@ -1342,87 +1516,90 @@ void NOMAD::Evaluator_Control::wait_for_evaluations NOMAD::success_type & success , std::list<const NOMAD::Eval_Point *> & evaluated_pts ) { - if ( _nb_in_progress == 0 ) - return; - - // display degree: - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_display_degree ( search ); - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl - << NOMAD::open_block ( "wait for evaluations" ); - - NOMAD::Barrier & barrier = ( _p.get_opt_only_sgte() ) ? - sgte_barrier : true_barrier; - char signal; - int source; - NOMAD::Eval_Point * eval_x; - NOMAD::success_type one_eval_success; - - while ( _nb_in_progress > 0 ) { - - source = NOMAD::Slave::receive_signal ( signal ); - eval_x = _eval_in_progress[source]; - - if ( eval_x ) { - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << "receive eval point #" << eval_x->get_tag() - << " from slave " << source << std::endl << std::endl; - - receive_eval_result ( search , - eval_x , - true_barrier , - sgte_barrier , - pareto_front , - source , - stop , - stop_reason ); - - // list of processed points: - if ( eval_x->is_in_cache() ) - evaluated_pts.push_back ( eval_x ); - - // success: - one_eval_success = barrier.get_one_eval_succ(); - success = barrier.get_success(); - - // asynchronous success count: - if ( success == NOMAD::FULL_SUCCESS && - _elop_tag != _slaves_elop_tags[source] ) - _stats.add_asynchronous_success(); - - // displays: - display_eval_result ( *eval_x , - display_degree , - search , - one_eval_success , - success ); - - if ( !_eval_in_progress[source]->is_in_cache() ) - delete _eval_in_progress[source]; - _eval_in_progress[source] = NULL; - _slaves_elop_tags[source] = -1; - --_nb_in_progress; - - // force quit (by pressing ctrl-c): - if ( !stop && NOMAD::Evaluator_Control::_force_quit ) { - stop = true; - stop_reason = NOMAD::CTRL_C; - break; - } - - if ( stop && ( stop_reason==NOMAD::ERROR || - stop_reason==NOMAD::UNKNOWN_STOP_REASON ) ) - break; - } - else - NOMAD::Slave::send_signal ( NOMAD::WAIT_SIGNAL , source ); - } - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out.close_block(); + if ( _nb_in_progress == 0 ) + return; + + // display degree: + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_display_degree ( search ); + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl + << NOMAD::open_block ( "wait for evaluations" ); + + NOMAD::Barrier & barrier = ( _p.get_opt_only_sgte() ) ? + sgte_barrier : true_barrier; + char signal; + int source; + NOMAD::Eval_Point * eval_x; + NOMAD::success_type one_eval_success; + + while ( _nb_in_progress > 0 ) + { + + source = NOMAD::Slave::receive_signal ( signal ); + eval_x = _eval_in_progress[source]; + + if ( eval_x ) + { + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << "receive eval point #" << eval_x->get_tag() + << " from slave " << source << std::endl << std::endl; + + receive_eval_result ( search , + eval_x , + true_barrier , + sgte_barrier , + pareto_front , + source , + stop , + stop_reason ); + + // list of processed points: + if ( eval_x->is_in_cache() ) + evaluated_pts.push_back ( eval_x ); + + // success: + one_eval_success = barrier.get_one_eval_succ(); + success = barrier.get_success(); + + // asynchronous success count: + if ( success == NOMAD::FULL_SUCCESS && + _elop_tag != _slaves_elop_tags[source] ) + _stats.add_asynchronous_success(); + + // displays: + display_eval_result ( *eval_x , + display_degree , + search , + one_eval_success , + success ); + + if ( !_eval_in_progress[source]->is_in_cache() ) + delete _eval_in_progress[source]; + _eval_in_progress[source] = NULL; + _slaves_elop_tags[source] = -1; + --_nb_in_progress; + + // force quit (by pressing ctrl-c): + if ( !stop && ( NOMAD::Evaluator_Control::_force_quit || NOMAD::Evaluator::get_force_quit() ) ) + { + stop = true; + stop_reason = NOMAD::CTRL_C; + break; + } + + if ( stop && ( stop_reason==NOMAD::ERROR || + stop_reason==NOMAD::UNKNOWN_STOP_REASON ) ) + break; + } + else + NOMAD::Slave::send_signal ( NOMAD::WAIT_SIGNAL , source ); + } + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out.close_block(); } #endif @@ -1467,7 +1644,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points std::list<const NOMAD::Eval_Point *> & evaluated_pts ) // OUT : list of processed pts { - if ( stop || _eval_lop.empty() ) { + if ( stop || _eval_lop.empty() ) + { stop_reason = NOMAD::UNKNOWN_STOP_REASON; ++_elop_tag; return; @@ -1480,7 +1658,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points const NOMAD::Display & out = _p.out(); NOMAD::dd_type display_degree = out.get_display_degree ( search ); - if ( display_degree == NOMAD::FULL_DISPLAY ) { + if ( display_degree == NOMAD::FULL_DISPLAY ) + { std::ostringstream msg; msg << "list of points evaluation (" << search << ")"; out << std::endl << NOMAD::open_block ( msg.str() ); @@ -1529,14 +1708,16 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points std::set<NOMAD::Priority_Eval_Point>::iterator it = _eval_lop.begin() , end = _eval_lop.end(); - while ( !stop && !opp_stop && it != end ) { + while ( !stop && !opp_stop && it != end ) + { x = it->get_point(); x->set_current_run ( true ); // displays: - if ( display_degree == NOMAD::FULL_DISPLAY ) { + if ( display_degree == NOMAD::FULL_DISPLAY ) + { // open the evaluation block: { @@ -1547,20 +1728,31 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points out << std::endl << NOMAD::open_block ( oss.str() ); } - out << std::endl << "point #" << x->get_tag() << " ( "; - x->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - if ( x->get_direction() ) - out << "direction : " << *x->get_direction() << std::endl; - if ( x->get_mesh_index() ) - out << "mesh index : " << *x->get_mesh_index() << std::endl; + out << std::endl << "point #" << x->get_tag() << " ( "; + x->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + if ( x->get_direction() ) + { + out << "direction : " << *x->get_direction() << std::endl; + NOMAD::Point delta; + x->get_signature()->get_mesh()->get_delta(delta); + out << "direction d : ( " << *x->get_direction()/delta << " )" << std::endl; + } + if ( x->get_signature() ) + out << "mesh indices: ( " << x->get_signature()->get_mesh()->get_mesh_indices() << " )" << std::endl; + out << std::endl; + + + } // check if the evaluation at this point is already in progress: - if ( !already_in_progress ( *x ) ) { + if ( !already_in_progress ( *x ) ) + { // current point check (# of bb outputs, bounds, integer values, fixed-vars): - if ( x->check ( _p.get_bb_nb_outputs() , check_failed_reason ) ) { + if ( x->check ( _p.get_bb_nb_outputs() , check_failed_reason ) ) + { count_eval = true; @@ -1571,7 +1763,9 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points pareto_front , count_eval , barrier.get_h_max() , - display_degree ) ) { + display_degree ) ) + + { // list of processed points: evaluated_pts.push_back ( x ); @@ -1603,7 +1797,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points f0 , barrier , nb_success , - one_for_luck ) ) { + one_for_luck ) ) + { _stats.add_interrupted_eval(); opp_stop = true; // will break loop #1 } @@ -1614,7 +1809,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points } // point not in cache (the point is saved for loop #2): - else { + else + { // blackbox or surrogate evaluations are allowed: if ( ( x->get_eval_type() == NOMAD::TRUTH && max_bb_eval != 0 ) || @@ -1628,7 +1824,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points } // points[k]->check() failed (close the evaluation block): - else if ( display_degree == NOMAD::FULL_DISPLAY ) { + else if ( display_degree == NOMAD::FULL_DISPLAY ) + { std::ostringstream oss; oss << "check failed (" << check_failed_reason << ")"; out.close_block ( oss.str() ); @@ -1636,7 +1833,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points } // evaluation already in progress (close the evaluation block): - else if ( display_degree == NOMAD::FULL_DISPLAY ) { + else if ( display_degree == NOMAD::FULL_DISPLAY ) + { std::ostringstream oss; oss << "evaluation of point #" << x->get_tag() << " already in progress"; @@ -1647,7 +1845,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points ++k; // force quit (by pressing ctrl-c): - if ( !stop && NOMAD::Evaluator_Control::_force_quit ) { + if ( !stop && (NOMAD::Evaluator_Control::_force_quit || NOMAD::Evaluator::get_force_quit()) ) + { stop = true; stop_reason = NOMAD::CTRL_C; } @@ -1664,14 +1863,16 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points char signal; NOMAD::Eval_Point * eval_x; - while ( !stop && !opp_stop && nb_evaluated < nb_to_evaluate ) { + while ( !stop && !opp_stop && nb_evaluated < nb_to_evaluate ) + { source = NOMAD::Slave::receive_signal ( signal ); // 2.1: send the RESULT signal, receive and process the evaluation result: // ----------------------------------------------------------------------- eval_x = _eval_in_progress[source]; - if ( eval_x ) { + if ( eval_x ) + { if ( display_degree == NOMAD::FULL_DISPLAY ) out << std::endl << "receive eval point #" << eval_x->get_tag() @@ -1720,7 +1921,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points f0 , barrier , nb_success , - one_for_luck ) ) { + one_for_luck ) ) + { _stats.add_interrupted_eval(); opp_stop = true; // will break loop #2 } @@ -1733,7 +1935,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points // 2.2: send the EVAL signal and launch a new evaluation: // ------------------------------------------------------ - else { + else + { // do not launch a new evaluation if... @@ -1744,19 +1947,22 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points // or if bbe+_nb_in_progress >= max_bb_eval: else if ( to_be_evaluated[cur]->get_eval_type() == NOMAD::TRUTH && max_bb_eval > 0 && - _stats.get_bb_eval() + _nb_in_progress >= max_bb_eval ) { + _stats.get_bb_eval() + _nb_in_progress >= max_bb_eval ) + { stop = true; stop_reason = NOMAD::MAX_BB_EVAL_REACHED; NOMAD::Slave::send_signal ( NOMAD::WAIT_SIGNAL , source ); } - else { + else + { // get the signature: NOMAD::Signature * signature = to_be_evaluated[cur]->get_signature(); // there is no signature (error): - if ( !signature ) { + if ( !signature ) + { stop = true; stop_reason = NOMAD::ERROR; if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) @@ -1767,7 +1973,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points NOMAD::Slave::send_signal ( NOMAD::WAIT_SIGNAL , source ); } - else { + else + { NOMAD::Slave::send_signal ( NOMAD::EVAL_SIGNAL , source ); @@ -1800,7 +2007,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points } // force quit (by pressing ctrl-c): - if ( !stop && NOMAD::Evaluator_Control::_force_quit ) { + if ( !stop && ( NOMAD::Evaluator_Control::_force_quit || NOMAD::Evaluator::get_force_quit() )) + { stop = true; stop_reason = NOMAD::CTRL_C; } @@ -1827,7 +2035,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points evaluated_pts ); // barriers update: - if ( !stop ) { + if ( !stop ) + { true_barrier.update_and_reset_success(); sgte_barrier.update_and_reset_success(); } @@ -1851,6 +2060,7 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points } // end of eval_lop() parallel version +// C. Tribes may 28, 2014 --- method for points block evaluation of a given max size /*----------------------------------------------------------------*/ /* eval_list_of_points, private version (scalar version) */ /*----------------------------------------------------------------*/ @@ -1881,6 +2091,7 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points const NOMAD::Display & out = _p.out(); NOMAD::dd_type display_degree = out.get_display_degree ( search ); + if ( display_degree == NOMAD::FULL_DISPLAY ) { std::ostringstream oss; @@ -1913,79 +2124,207 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points const NOMAD::Eval_Point * x; NOMAD::check_failed_type check_failed_reason; - bool count_eval; bool one_for_luck = false; bool stop_evals = false; int init_nb_eval = _stats.get_eval(); int nb_success = 0; int k = 0; + int k_block = 0; int nb_points = get_nb_eval_points(); + int block_size = _p.get_bb_max_block_size(); + int block_nb = 1; // main loop (on the list of points): // ---------------------------------- std::set<NOMAD::Priority_Eval_Point>::iterator it = _eval_lop.begin() , end = _eval_lop.end(); + std::list<NOMAD::Eval_Point *> list_x,list_eval; + std::list<bool> count_list_eval; while ( !stop_evals && !stop && it != end ) { - x = it->get_point(); - x->set_current_run ( true ); + if ( block_size > 1 && display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "Block of evaluations (" << block_nb <<")"; + out << std::endl << NOMAD::open_block ( oss.str() ); + } - // displays: - if ( display_degree == NOMAD::FULL_DISPLAY ) + // Creation of a block of evaluations from the list + //---------------------- + k_block=k; + bool opportunistic_success_from_cache_point=false; + while (list_eval.size()!=static_cast<size_t>(block_size) && it != end && ! stop_evals) { + + x = it->get_point(); + x->set_current_run ( true ); + + // displays: + if ( display_degree == NOMAD::FULL_DISPLAY ) { - // open the evaluation block: - std::ostringstream oss; - if ( x->get_eval_type() == NOMAD::SGTE ) - oss << "surrogate "; - oss << "evaluation " << k+1 << "/" << nb_points; - out << std::endl << NOMAD::open_block ( oss.str() ); + { + // open the evaluation block: + std::ostringstream oss; + oss << "submitted "; + if ( x->get_eval_type() == NOMAD::SGTE ) + oss << "surrogate "; + oss << "evaluation " << k+1 << "/" << nb_points; + out << std::endl << NOMAD::open_block ( oss.str() ); + } + + out << std::endl << "point #" << x->get_tag() << " ( "; + x->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + if ( x->get_direction() ) + { + out << "direction : " << *x->get_direction() << std::endl; + NOMAD::Point delta; + x->get_signature()->get_mesh()->get_delta(delta); + out << "direction d : ( " << *x->get_direction()/delta << " )" << std::endl; + } + if ( x->get_signature() ) + out << "mesh indices: ( " << x->get_signature()->get_mesh()->get_mesh_indices() << " )" << std::endl; + out << std::endl; + } - out << std::endl << "point #" << x->get_tag() << " ( "; - x->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - if ( x->get_direction() ) - out << "direction : " << *x->get_direction() << std::endl; - if ( x->get_mesh_index() ) - out << "mesh index : " << *x->get_mesh_index() << std::endl; - out << std::endl; + // current point check (# of bb outputs, bounds, integer values, fixed-vars): + if ( x->check ( _p.get_bb_nb_outputs() , check_failed_reason ) ) + { + bool count_eval = true; + bool has_been_in_cache=cache_check ( x , + true_barrier , + sgte_barrier , + pareto_front , + count_eval , + barrier.get_h_max() , + display_degree ); + + + // put the point in a block list for evaluation: + if ( !has_been_in_cache ) + list_eval.push_back(&NOMAD::Cache::get_modifiable_point ( *x )); + else + { + // check stopping criteria for points in cache + check_stopping_criteria ( search , count_eval , *x , stop , stop_reason ); + + // process the evaluated point: + process_eval_point ( *x , + ( x->get_eval_type() == NOMAD::TRUTH ) ? true_barrier : sgte_barrier , + pareto_front ); + + + // success: + NOMAD::success_type one_eval_success = barrier.get_one_eval_succ(); + success = barrier.get_success(); + + + opportunistic_success_from_cache_point = stop_evaluations ( *x , + search , + k , + nb_points , + stop , + display_degree , + one_eval_success , + success , + init_nb_eval , + f0 , + barrier , + nb_success , + one_for_luck ); + + + } + + if (!stop) + list_x.push_back(&NOMAD::Cache::get_modifiable_point ( *x )); + + if ( opportunistic_success_from_cache_point ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << NOMAD::close_block(); + + if ( block_size > 1 && display_degree == NOMAD::FULL_DISPLAY ) + out << NOMAD::close_block (); + + stop_evals = true; + break; + } + + } + // points[k]->check() failed: + else if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "check failed (" << check_failed_reason << ")" << std::endl; + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << NOMAD::close_block(); + + + ++it; + ++k; } - - // current point check (# of bb outputs, bounds, integer values, fixed-vars): - if ( x->check ( _p.get_bb_nb_outputs() , check_failed_reason ) ) + if (list_eval.size()!=0) { - count_eval = true; - - bool has_been_in_cache=cache_check ( x , - true_barrier , - sgte_barrier , - pareto_front , - count_eval , - barrier.get_h_max() , - display_degree ); + count_list_eval.assign(list_eval.size(), false); - // search in cache or eval the point: - if ( !has_been_in_cache ) + if (_p.eval_points_as_block()) { - eval_point ( NOMAD::Cache::get_modifiable_point ( *x ) , - true_barrier , - sgte_barrier , - pareto_front , - count_eval , - stop , - stop_reason , - barrier.get_h_max() ); + eval_points ( list_eval , + true_barrier , + sgte_barrier , + pareto_front , + count_list_eval , + stop , + stop_reason , + barrier.get_h_max() ); + // check stopping criteria for points NOT in cache + std::list<NOMAD::Eval_Point *>::iterator it_eval; + } + else + { + // bool count_eval=false; + x=*(list_eval.begin()); + eval_point ( NOMAD::Cache::get_modifiable_point ( *x ) , + true_barrier , + sgte_barrier , + pareto_front , + count_list_eval.front() , + stop , + stop_reason , + barrier.get_h_max() ); } - // check stopping criteria: - check_stopping_criteria ( search , count_eval , *x , stop , stop_reason ); + } + + // Stop evals and exit the loop + if ( stop_evals ) + break; + + // Check all the points in the evaluation block + std::list<NOMAD::Eval_Point *>::iterator it_x,it_eval; + k=k_block; + it_eval=list_eval.begin(); + for(it_x=list_x.begin();it_x!=list_x.end();++it_x) + { + + x=(*it_x); + + // process the evaluated point: + if ( x->is_eval_ok() && x->is_in_cache() ) + process_eval_point ( *x , + ( x->get_eval_type() == NOMAD::TRUTH ) ? + true_barrier : sgte_barrier , + pareto_front ); + + + // success: NOMAD::success_type one_eval_success = barrier.get_one_eval_succ(); success = barrier.get_success(); @@ -2002,50 +2341,95 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points } // displays: - if ( ! has_been_in_cache || display_degree!=NOMAD::MINIMAL_DISPLAY) - display_eval_result ( *x, display_degree, search, one_eval_success, success ); + if ( block_size > 0 && display_degree == NOMAD::FULL_DISPLAY ) + { + // open the evaluation block: + std::ostringstream oss; + if ( x->get_eval_type() == NOMAD::SGTE ) + oss << "surrogate "; + oss << "evaluation " << k+1 << "/" << nb_points; + out << std::endl << NOMAD::open_block ( oss.str() ); + out << std::endl << "point #" << x->get_tag() << std::endl; + } + + std::list<bool>::iterator it_count=count_list_eval.begin(); + for(it_eval=list_eval.begin();it_eval!=list_eval.end();++it_eval,++it_count) + { + if ((*it_eval)==x) + { + + // count the bb evaluation: + if ( *it_count ) + { + if ( (*it_eval)->get_eval_type() == NOMAD::SGTE ) + _stats.add_sgte_eval(); + else + { + // current mads bbe evaluation + _stats.add_bb_eval(); + } + + // count the output stats (STAT_SUM and STAT_AVG): + if ( _p.check_stat_sum() || _p.check_stat_avg() ) + count_output_stats(*(*it_eval)); + } + + check_stopping_criteria ( search , *it_count ,*(*it_eval) , stop , stop_reason ); + + if ( *it_count ) + display_eval_result ( *x, display_degree, search, one_eval_success, success ); + + break; + } + } + + // close the evaluation block: + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << NOMAD::close_block (); + // stop the evaluations (opportunistic strategy) ? - if ( stop_evaluations ( *x , - search , - k , - nb_points , - stop , - display_degree , - one_eval_success , - success , - init_nb_eval , - f0 , - barrier , - nb_success , - one_for_luck ) ) + if ( !stop_evals && stop_evaluations ( *x , + search , + k , + nb_points , + stop , + display_degree , + one_eval_success , + success , + init_nb_eval , + f0 , + barrier , + nb_success , + one_for_luck ) ) { _stats.add_interrupted_eval(); stop_evals = true; } + + + ++k; + } - // points[k]->check() failed: - else if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "check failed (" << check_failed_reason << ")" << std::endl; - - // close the evaluation block: - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << NOMAD::close_block(); - - ++it; - ++k; + if ( block_size > 1 && display_degree == NOMAD::FULL_DISPLAY ) + out << NOMAD::close_block (); + // force quit (by pressing ctrl-c): - if ( !stop && NOMAD::Evaluator_Control::_force_quit ) + if ( !stop && ( NOMAD::Evaluator_Control::_force_quit || NOMAD::Evaluator::get_force_quit()) ) { stop = true; stop_reason = NOMAD::CTRL_C; } - } // end of main loop - // ---------------- + list_x.clear(); + list_eval.clear(); + + ++block_nb; + + }// end of test for list evaluation // barriers update: if ( !stop ) @@ -2070,6 +2454,8 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points clear_eval_lop(); } // end of eval_lop() scalar version + + #endif /*-------------------------------------------------*/ @@ -2077,21 +2463,21 @@ void NOMAD::Evaluator_Control::private_eval_list_of_points /*-------------------------------------------------*/ void NOMAD::Evaluator_Control::reduce_eval_lop ( int n ) { - int nb_eval_pts = get_nb_eval_points(); - - if ( n < 0 || n >= nb_eval_pts ) - return; - - const NOMAD::Eval_Point * x; - std::set<NOMAD::Priority_Eval_Point>::iterator it = _eval_lop.end(); - --it; - - while ( get_nb_eval_points() > n ) { - x = it->get_point(); - if ( x && !x->is_in_cache() && x->get_eval_status() != NOMAD::EVAL_IN_PROGRESS ) - delete x; - _eval_lop.erase ( it-- ); - } + int nb_eval_pts = get_nb_eval_points(); + + if ( n < 0 || n >= nb_eval_pts ) + return; + + const NOMAD::Eval_Point * x; + std::set<NOMAD::Priority_Eval_Point>::iterator it = _eval_lop.end(); + for( int i=0;i<nb_eval_pts-n;i++) + { + --it; + x = it->get_point(); + if ( x && !x->is_in_cache() && x->get_eval_status() != NOMAD::EVAL_IN_PROGRESS ) + delete x; + } + _eval_lop.erase( it,_eval_lop.end()); } /*-------------------------------------------------*/ @@ -2844,7 +3230,6 @@ void NOMAD::Evaluator_Control::eval_list_of_points x->set ( (*it2)->size() , _p.get_bb_nb_outputs() ); x->set_signature ( (*it2)->get_signature () ); x->set_direction ( (*it2)->get_direction () ); - x->set_mesh_index ( (*it2)->get_mesh_index() ); x->Point::operator = ( **it2 ); modified_list = true; @@ -2868,11 +3253,13 @@ void NOMAD::Evaluator_Control::eval_list_of_points // model ordering: // --------------- - if ( !modified_list && _model_eval_sort && _eval_lop.size() > 1 ) { + if ( !modified_list && _model_eval_sort && _eval_lop.size() > 1 ) + { switch ( _p.get_model_eval_sort() ) { case NOMAD::TGP_MODEL: TGP_model_ordering ( display_degree , modified_list ); - if ( NOMAD::Evaluator_Control::_force_quit ) { + if ( NOMAD::Evaluator_Control::_force_quit || NOMAD::Evaluator::get_force_quit() ) + { stop = true; stop_reason = NOMAD::CTRL_C; } @@ -2940,12 +3327,14 @@ void NOMAD::Evaluator_Control::eval_list_of_points /*------------------------------------------------------------------------------------*/ /* ordering of a list of points based on surrogate (1st) or model (2nd) evaluations */ /*------------------------------------------------------------------------------------*/ + void NOMAD::Evaluator_Control::ordering_lop ( NOMAD::search_type search , // IN : search type bool & stop , // IN/OUT: stopping criterion NOMAD::stop_type & stop_reason , // OUT : stopping reason NOMAD::Barrier & true_barrier , // IN/OUT: truth barrier NOMAD::Barrier & sgte_barrier // IN/OUT: surrogate barrier ) + { std::list<const NOMAD::Eval_Point *> * evaluated_pts = new std::list<const NOMAD::Eval_Point *>; @@ -3008,7 +3397,6 @@ void NOMAD::Evaluator_Control::ordering_lop ( NOMAD::search_type sea x->set_direction ( (*it2)->get_direction () ); x->set_poll_center( (*it2)->get_poll_center () ); // Poll center is needed for further testing (not needed when evaluating points) x->set_poll_center_type ( (*it2)->get_poll_center_type () ); - x->set_mesh_index ( (*it2)->get_mesh_index() ); x->Point::operator = ( **it2 ); modified_list = true; @@ -3038,7 +3426,7 @@ void NOMAD::Evaluator_Control::ordering_lop ( NOMAD::search_type sea } } - if ( NOMAD::Evaluator_Control::_force_quit ) + if ( NOMAD::Evaluator_Control::_force_quit || NOMAD::Evaluator::get_force_quit() ) { stop = true; stop_reason = NOMAD::CTRL_C; @@ -3089,37 +3477,39 @@ bool NOMAD::Evaluator_Control::stop_evaluations int & nb_success , bool & one_for_luck ) const { - // opportunistic evaluation ? - bool opportunistic = is_opportunistic ( search ); - - if ( k < nb_points - 1 ) { + // opportunistic evaluation ? + bool opportunistic = is_opportunistic ( search ); - if ( stop ) - return true; - - if ( opportunistic && - ( x.get_eval_type() == NOMAD::TRUTH || _p.get_opt_only_sgte() ) ) { - - if ( one_for_luck && one_eval_success != NOMAD::FULL_SUCCESS ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) - _p.out() << std::endl - << "opportunistic termination of evaluations (lucky eval)" - << std::endl; - return true; - } - - if ( success == NOMAD::FULL_SUCCESS && - check_opportunistic_criterion ( display_degree , - one_eval_success , - init_nb_eval , - f0 , - barrier , - nb_success , - one_for_luck ) ) - return true; - } - } - return false; + if ( k < nb_points - 1 ) { + + if ( stop ) + return true; + + if ( opportunistic && + ( x.get_eval_type() == NOMAD::TRUTH || _p.get_opt_only_sgte() ) ) + { + + if ( one_for_luck && one_eval_success != NOMAD::FULL_SUCCESS ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + _p.out() << std::endl + << "opportunistic termination of evaluations (lucky eval)" + << std::endl; + return true; + } + + if ( success == NOMAD::FULL_SUCCESS && + check_opportunistic_criterion ( display_degree , + one_eval_success , + init_nb_eval , + f0 , + barrier , + nb_success , + one_for_luck ) ) + return true; + } + } + return false; } /*-----------------------------------------------------------------*/ @@ -3136,91 +3526,105 @@ bool NOMAD::Evaluator_Control::check_opportunistic_criterion int & nb_success , bool & one_for_luck ) const { - int min_nb_success = _p.get_opportunistic_min_nb_success(); - int min_eval = _p.get_opportunistic_min_eval(); - NOMAD::Double min_f_imprvmt = _p.get_opportunistic_min_f_imprvmt(); - bool lucky_eval = _p.get_opportunistic_lucky_eval(); - const NOMAD::Display & out = _p.out(); - - // min_nb_success: - if ( min_nb_success > 0 ) { - - if ( one_eval_success == NOMAD::FULL_SUCCESS ) - ++nb_success; - - if ( nb_success < min_nb_success ) { - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl - << "opport. strategy (nb_success=" << nb_success - << " < min_nb_success=" << min_nb_success - << "): continue evaluations" - << std::endl; - - return false; - } - } - - // min_eval: - if ( min_eval > 0 ) { - - int eval = _stats.get_eval() - init_nb_eval; - - if ( eval < min_eval ) { - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl - << "opport. strategy (eval=" << eval - << " < min_eval=" << min_eval - << "): continue evaluations" << std::endl; - return false; - } - } - - // min_f_imprvmt: - if ( min_f_imprvmt.is_defined() ) { - - const NOMAD::Eval_Point * bf = barrier.get_best_feasible(); - - if ( f0.is_defined() && bf ) { - - NOMAD::Double f = bf->get_f(); - - if ( f.is_defined() ) { - - NOMAD::Double f_imprvmt = f0.rel_err(f) * 100.0; - if ( f_imprvmt < min_f_imprvmt ) { - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl - << "opport. strategy (f_improvement=" - << f_imprvmt << " < min_f_imprvmt=" << min_f_imprvmt - << "): continue evaluations" << std::endl; - - return false; + int min_nb_success = _p.get_opportunistic_min_nb_success(); + int min_eval = _p.get_opportunistic_min_eval(); + NOMAD::Double min_f_imprvmt = _p.get_opportunistic_min_f_imprvmt(); + bool lucky_eval = _p.get_opportunistic_lucky_eval(); + const NOMAD::Display & out = _p.out(); + + // min_nb_success: + if ( min_nb_success > 0 ) + { + + if ( one_eval_success == NOMAD::FULL_SUCCESS ) + ++nb_success; + + if ( nb_success < min_nb_success ) + { + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl + << "opport. strategy (nb_success=" << nb_success + << " < min_nb_success=" << min_nb_success + << "): continue evaluations" + << std::endl; + + return false; + } } - } - } - } - - // lucky_eval: - if ( lucky_eval && one_eval_success == NOMAD::FULL_SUCCESS ) { - one_for_luck = true; - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl - << "opport. strategy: one more evaluation for luck" - << std::endl; - - return false; - } - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << "opport. strategy: stop evaluations" - << std::endl; - - return true; + + // min_eval: + if ( min_eval > 0 ) + { + + int eval = _stats.get_eval() - init_nb_eval; + + if ( eval < min_eval ) + { + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl + << "opport. strategy (eval=" << eval + << " < min_eval=" << min_eval + << "): continue evaluations" << std::endl; + return false; + } + } + + // min_f_imprvmt: + if ( min_f_imprvmt.is_defined() ) + { + + const NOMAD::Eval_Point * bf = barrier.get_best_feasible(); + + if ( f0.is_defined() && bf ) + { + + NOMAD::Double f = bf->get_f(); + + if ( f.is_defined() ) + { + + NOMAD::Double f_imprvmt = f0.rel_err(f) * 100.0; + + if ( f_imprvmt < min_f_imprvmt ) + { + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl + << "opport. strategy (f_improvement=" + << f_imprvmt << " < min_f_imprvmt=" << min_f_imprvmt + << "): continue evaluations" << std::endl; + + return false; + } + } + } + } + + // lucky_eval: + if ( lucky_eval && one_eval_success == NOMAD::FULL_SUCCESS ) + { + one_for_luck = true; + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl + << "opport. strategy: one more evaluation for luck" + << std::endl; + + return false; + } + + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + out << std::endl << "opport. strategy: stop evaluations" ; + if (_p.get_bb_max_block_size() > 1) + out << " at the end of the block evaluation"; + out << std::endl; + } + + return true; } /*---------------------------------------------------------------*/ @@ -3287,9 +3691,11 @@ void NOMAD::Evaluator_Control::add_eval_point( NOMAD::Eval_Point *& x NOMAD::Direction * new_dir = NULL; if ( _p.has_periodic_variables() && - x->treat_periodic_variables ( new_dir ) ) { + x->treat_periodic_variables ( new_dir ) ) + { - if ( new_dir && new_dir->norm() == 0.0 ) { + if ( new_dir && new_dir->norm() == 0.0 ) + { if ( display_degree == NOMAD::FULL_DISPLAY ) out << "point #" << x->get_tag() @@ -3306,16 +3712,19 @@ void NOMAD::Evaluator_Control::add_eval_point( NOMAD::Eval_Point *& x } delete new_dir; - if ( snap_to_bounds && x->snap_to_bounds() ) { + if ( snap_to_bounds && x->snap_to_bounds() ) + { - if ( display_degree == NOMAD::FULL_DISPLAY ) { + if ( display_degree == NOMAD::FULL_DISPLAY ) + { out << std::endl << "point #" << x->get_tag() << " "; if ( x->get_direction() && x->get_direction()->get_index() >= 0 ) out << "(dir " << x->get_direction()->get_index() << ") "; out << "has been snapped to bounds" << std::endl; } - if ( x->get_direction() && x->get_direction()->norm() == 0.0 ) { + if ( x->get_direction() && x->get_direction()->norm() == 0.0 ) + { if ( display_degree == NOMAD::FULL_DISPLAY ) out << "point #" << x->get_tag() @@ -3350,7 +3759,7 @@ void NOMAD::Evaluator_Control::add_eval_point( NOMAD::Eval_Point *& x if ( !signature ) throw NOMAD::Exception ( "Evaluator_Control.cpp" , __LINE__ , "Evaluator_Control::add_eval_point(): the point has no signature" ); - + // angle with last successful directions (feasible) const NOMAD::Direction & feas_success_dir = signature->get_feas_success_dir(); if ( feas_success_dir.is_defined() && @@ -3362,7 +3771,7 @@ void NOMAD::Evaluator_Control::add_eval_point( NOMAD::Eval_Point *& x if ( infeas_success_dir.is_defined() && x->get_poll_center_type() == NOMAD::INFEASIBLE ) pep.set_angle_success_dir ( infeas_success_dir.get_angle ( *x->get_direction() ) ); - + } diff --git a/src/Evaluator_Control.hpp b/src/Evaluator_Control.hpp index 09ab63b..d0bfb6f 100644 --- a/src/Evaluator_Control.hpp +++ b/src/Evaluator_Control.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Evaluator_Control.hpp - \brief Control of the blackbox evaluations (headers) - \author Sebastien Le Digabel - \date 2010-04-15 - \see Evaluator_Control.cpp -*/ + \file Evaluator_Control.hpp + \brief Control of the blackbox evaluations (headers) + \author Sebastien Le Digabel + \date 2010-04-15 + \see Evaluator_Control.cpp + */ #ifndef __EVALUATOR_CONTROL__ #define __EVALUATOR_CONTROL__ @@ -54,682 +54,720 @@ #ifdef R_VERSION extern "C" { - #include <Rinternals.h> +#include <Rinternals.h> } #endif namespace NOMAD { - - /// Control of the blackbox evaluations. - /** + + /// Control of the blackbox evaluations. + /** This class allows the evaluation of a list of trial point. - */ - class Evaluator_Control : private NOMAD::Uncopyable { - - private: - - static bool _force_quit; ///< Forces NOMAD to terminate if Ctrl-C is pressed. - const NOMAD::Parameters & _p; ///< Parameters. - NOMAD::Evaluator * _ev; ///< The evaluator. - - NOMAD::Cache * _cache; ///< Cache for true function evaluations. - NOMAD::Cache * _sgte_cache; ///< Cache for surrogate evaluations. - - /// List of points to be evaluated. - std::set<NOMAD::Priority_Eval_Point> _eval_lop; - - /// Flag to enable or disable the model ordering. - bool _model_eval_sort; - - /// Flag equal to \c true if the destructor has to delete \c this->_ev. - bool _del_ev; - - /// Flag equal to \c true if the destructor has to erase the cache. - bool _del_cache; - - /// Flag equal to \c true if the destructor has to erase the cache for surrogates. - bool _del_sgte_cache; - + */ + class Evaluator_Control : private NOMAD::Uncopyable { + + private: + + static bool _force_quit; ///< Forces NOMAD to terminate if Ctrl-C is pressed. + static bool _force_evaluation_failure; ///< Forces an evaluation failure. + + const NOMAD::Parameters & _p; ///< Parameters. + NOMAD::Evaluator * _ev; ///< The evaluator. + + NOMAD::Cache * _cache; ///< Cache for true function evaluations. + NOMAD::Cache * _sgte_cache; ///< Cache for surrogate evaluations. + + /// List of points to be evaluated. + std::set<NOMAD::Priority_Eval_Point> _eval_lop; + + /// Flag to enable or disable the model ordering. + bool _model_eval_sort; + + /// Flag equal to \c true if the destructor has to delete \c this->_ev. + bool _del_ev; + + /// Flag equal to \c true if the destructor has to erase the cache. + bool _del_cache; + + /// Flag equal to \c true if the destructor has to erase the cache for surrogates. + bool _del_sgte_cache; + #ifdef USE_MPI - NOMAD::Eval_Point ** _eval_in_progress; ///< List of evaluations in progress. - int _nb_in_progress; ///< Number of evaluations in progress. - - /// Elop tag. - /** - Unique tag associated to \c this->eval_lop(). - */ - int _elop_tag; - - /// Elop tag for each slave. - /** - _slaves_elop_tags[k] corresponds to the Elop tag for slave \c k. - */ - int * _slaves_elop_tags; - - NOMAD::Slave * _slave; // Slave object for master process + NOMAD::Eval_Point ** _eval_in_progress; ///< List of evaluations in progress. + int _nb_in_progress; ///< Number of evaluations in progress. + + /// Elop tag. + /** + Unique tag associated to \c this->eval_lop(). + */ + int _elop_tag; + + /// Elop tag for each slave. + /** + _slaves_elop_tags[k] corresponds to the Elop tag for slave \c k. + */ + int * _slaves_elop_tags; + + NOMAD::Slave * _slave; // Slave object for master process #endif - + #ifdef USE_TGP - NOMAD::TGP_Model * _last_TGP_model; ///< Last TGP model from the model search. + NOMAD::TGP_Model * _last_TGP_model; ///< Last TGP model from the model search. #endif - - NOMAD::Model_Stats _model_ordering_stats; ///< Model ordering stats. - NOMAD::Stats & _stats; ///< Algorithm stats. - - /** - - Lattest tag of a point that has been written for \c display_stats + + NOMAD::Model_Stats _model_ordering_stats; ///< Model ordering stats. + NOMAD::Stats & _stats; ///< Algorithm stats. + + /** + - Lattest tag of a point that has been written for \c display_stats or \c stats_file. - - It is used to avoid any double display at the end of a run. - */ - mutable int _last_stats_tag; - - /// Same as \c this->_last_stats_bbe for the number of blackbox evaluations. - mutable int _last_stats_bbe; - - /// Last entry in the history file to avoid cache hits. - mutable int _last_history_bbe; - - /// Process an already evaluated Eval_Point. - /** - \param x The point -- \b IN. - \param barrier The barrier -- \b IN/OUT. - \param pareto_front The Pareto front -- \b IN/OUT - (may be NULL). - */ - void process_eval_point ( const NOMAD::Eval_Point & x , - NOMAD::Barrier & barrier , - NOMAD::Pareto_Front * pareto_front ) const; - - /// Save the solution file or update the history file. - /** - \param file_name Name of the file -- \b IN. - \param x Lattest solution -- \b IN. - \param is_sol Flag equal to \c true if the file is - a solution file; otherwise it is a history file. -- \b IN. - \param display_bimv Display best infeasible (min. viol.) if \c true -- \b IN. - */ - void write_sol_or_his_file ( const std::string & file_name , - const NOMAD::Eval_Point & x , - bool is_sol , - bool display_bimv=false) const; - - /// Display evaluation result. - /** - \param x Lattest evaluation -- \b IN. - \param display_degree Display degree -- \b IN. - \param search Search type -- \b IN. - \param one_eval_success Success for one evaluation -- \b IN. - \param success Success for a series of evaluations -- \b IN. - */ - void display_eval_result ( const NOMAD::Eval_Point & x , - NOMAD::dd_type display_degree , - NOMAD::search_type search , - NOMAD::success_type one_eval_success , - NOMAD::success_type success ) const; - - /// Check if evaluations have to be stopped. - /** - Checks the opportunistic strategy stopping criterion. - \param x The lattest evaluation -- \b IN. - \param search Search type -- \b IN. - \param k Evaluation index -- \b IN. - \param nb_points Number of points to evaluate -- \b IN. - \param stop \c true if the algorithm has to be stopped -- \b IN. - \param display_degree Display degree -- \b IN. - \param one_eval_success Success for one evaluation -- \b IN. - \param success Success for a series of evaluations -- \b IN. - \param init_nb_eval Initial number of evaluations -- \b IN. - \param f0 Initial value of the objective function -- \b IN - (may be undefined). - \param barrier Barrier -- \b IN. - \param nb_success Number of successes -- \b IN/OUT. - \param one_for_luck \c true if one additional evaluation is made - according to parameter \c OPPORTUNISTIC_LUCKY_EVAL - -- \b IN/OUT. - */ - bool stop_evaluations ( const NOMAD::Eval_Point & x , - NOMAD::search_type search , - int k , - int nb_points , - bool stop , - NOMAD::dd_type display_degree , - NOMAD::success_type one_eval_success , - NOMAD::success_type success , - int init_nb_eval , - const NOMAD::Double & f0 , - const NOMAD::Barrier & barrier , - int & nb_success , - bool & one_for_luck ) const; - - /// Check the opportunistic strategy stopping criterion. - /** - \param display_degree Display degree -- \b IN. - \param one_eval_success Success for one evaluation -- \b IN. - \param init_nb_eval Initial number of evaluations -- \b IN. - \param f0 Initial value of the objective function -- \b IN - (may be undefined). - \param barrier Barrier -- \b IN. - \param nb_success Number of successes -- \b IN/OUT. - \param one_for_luck \c true if one additional evaluation is made - according to parameter OPPORTUNISTIC_LUCKY_EVAL - -- \b IN/OUT. - \return A boolean equal to \c true to stop the evaluations; - Otherwise, continue the evaluations. - */ - bool check_opportunistic_criterion ( NOMAD::dd_type display_degree , - NOMAD::success_type one_eval_success , - int init_nb_eval , - const NOMAD::Double & f0 , - const NOMAD::Barrier & barrier , - int & nb_success , - bool & one_for_luck ) const; - - /// Quadratic model ordering (parameter \c MODEL_EVAL_SORT). - /** - \param display_degree Display degree -- \b IN. - \param modified_list To indicate a change in the evaluation list -- \b OUT. - */ - void quad_model_ordering ( NOMAD::dd_type display_degree , - bool & modified_list ); - - /// TGP model ordering (parameter \c MODEL_EVAL_SORT). - /** - \param display_degree Display degree -- \b IN. - \param modified_list To indicate a change in the evaluation list -- \b OUT. - */ - void TGP_model_ordering ( NOMAD::dd_type display_degree , - bool & modified_list ); - - /// Count the output stats (STAT_SUM and STAT_AVG). - /** - \param x Lattest evaluation -- \b IN. - */ - void count_output_stats ( const NOMAD::Eval_Point & x ); - - /// Search a point in the cache. - /** - \param x The point -- \b IN/OUT. - \param true_barrier Barrier for true evaluations -- \b IN/OUT. - \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. - \param pareto_front A pointer to the Pareto front -- \b IN/OUT - (may be \c NULL). - \param count_eval Count or not a simulated evaluation -- \b OUT. - \param h_max Maximal feasibility value -- \b IN. - \param display_degree Display degree -- \b IN. - \return A boolean equal to \c true if the point is in cache. - */ - bool cache_check ( const NOMAD::Eval_Point *& x , - NOMAD::Barrier & true_barrier , - NOMAD::Barrier & sgte_barrier , - NOMAD::Pareto_Front * pareto_front , - bool & count_eval , - const NOMAD::Double & h_max , - NOMAD::dd_type display_degree ) const; - - /// Evaluate a point. - /* - \param x The point -- \b IN/OUT. - \param true_barrier Barrier for true evaluations -- \b IN/OUT. - \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. - \param pareto_front A pointer to the Pareto front -- \b IN/OUT - (may be \c NULL). - \param count_eval Count or not the evaluation -- \b OUT. - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - \param h_max Maximal feasibility value -- \b IN. - */ - void eval_point ( NOMAD::Eval_Point & x , - NOMAD::Barrier & true_barrier , - NOMAD::Barrier & sgte_barrier , - NOMAD::Pareto_Front * pareto_front , - bool & count_eval , - bool & stop , - NOMAD::stop_type & stop_reason , - const NOMAD::Double & h_max ); - - /// Check if a search is opportunistic or not. - /** - \param t Search type -- \b IN. - \return A boolean equal to \c true if the search is opportunistic. - */ - bool is_opportunistic ( NOMAD::search_type t ) const; - - /// Check stopping criteria. - /** - \param search Search type -- \b IN. - \param count_eval Count or not the evaluation -- \b IN. - \param x Lattest evaluation -- \b IN/OUT. - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - */ - void check_stopping_criteria ( NOMAD::search_type search , - bool count_eval , - const NOMAD::Eval_Point & x , - bool & stop , - NOMAD::stop_type & stop_reason ) const; - + - It is used to avoid any double display at the end of a run. + */ + mutable int _last_stats_tag; + + /// Same as \c this->_last_stats_bbe for the number of blackbox evaluations. + mutable int _last_stats_bbe; + + /// Last entry in the history file to avoid cache hits. + mutable int _last_history_bbe; + + /// Process an already evaluated Eval_Point. + /** + \param x The point -- \b IN. + \param barrier The barrier -- \b IN/OUT. + \param pareto_front The Pareto front -- \b IN/OUT + (may be NULL). + */ + void process_eval_point ( const NOMAD::Eval_Point & x , + NOMAD::Barrier & barrier , + NOMAD::Pareto_Front * pareto_front ) const; + + /// Save the solution file or update the history file. + /** + \param file_name Name of the file -- \b IN. + \param x Lattest solution -- \b IN. + \param is_sol Flag equal to \c true if the file is + a solution file; otherwise it is a history file. + \param display_bimv Display best infeasible (min. viol.) if \c true + */ + void write_sol_or_his_file ( const std::string & file_name , + const NOMAD::Eval_Point & x , + bool is_sol , + bool display_bimv=false) const; + + /// Display evaluation result. + /** + \param x Lattest evaluation -- \b IN. + \param display_degree Display degree -- \b IN. + \param search Search type -- \b IN. + \param one_eval_success Success for one evaluation -- \b IN. + \param success Success for a series of evaluations -- \b IN. + */ + void display_eval_result ( const NOMAD::Eval_Point & x , + NOMAD::dd_type display_degree , + NOMAD::search_type search , + NOMAD::success_type one_eval_success , + NOMAD::success_type success ) const; + + /// Check if evaluations have to be stopped. + /** + Checks the opportunistic strategy stopping criterion. + \param x The lattest evaluation -- \b IN. + \param search Search type -- \b IN. + \param k Evaluation index -- \b IN. + \param nb_points Number of points to evaluate -- \b IN. + \param stop \c true if the algorithm has to be stopped -- \b IN. + \param display_degree Display degree -- \b IN. + \param one_eval_success Success for one evaluation -- \b IN. + \param success Success for a series of evaluations -- \b IN. + \param init_nb_eval Initial number of evaluations -- \b IN. + \param f0 Initial value of the objective function -- \b IN + (may be undefined). + \param barrier Barrier -- \b IN. + \param nb_success Number of successes -- \b IN/OUT. + \param one_for_luck \c true if one additional evaluation is made + according to parameter \c OPPORTUNISTIC_LUCKY_EVAL + -- \b IN/OUT. + */ + bool stop_evaluations ( const NOMAD::Eval_Point & x , + NOMAD::search_type search , + int k , + int nb_points , + bool stop , + NOMAD::dd_type display_degree , + NOMAD::success_type one_eval_success , + NOMAD::success_type success , + int init_nb_eval , + const NOMAD::Double & f0 , + const NOMAD::Barrier & barrier , + int & nb_success , + bool & one_for_luck ) const; + + /// Check the opportunistic strategy stopping criterion. + /** + \param display_degree Display degree -- \b IN. + \param one_eval_success Success for one evaluation -- \b IN. + \param init_nb_eval Initial number of evaluations -- \b IN. + \param f0 Initial value of the objective function -- \b IN + (may be undefined). + \param barrier Barrier -- \b IN. + \param nb_success Number of successes -- \b IN/OUT. + \param one_for_luck \c true if one additional evaluation is made + according to parameter OPPORTUNISTIC_LUCKY_EVAL + -- \b IN/OUT. + \return A boolean equal to \c true to stop the evaluations; + Otherwise, continue the evaluations. + */ + bool check_opportunistic_criterion ( NOMAD::dd_type display_degree , + NOMAD::success_type one_eval_success , + int init_nb_eval , + const NOMAD::Double & f0 , + const NOMAD::Barrier & barrier , + int & nb_success , + bool & one_for_luck ) const; + + /// Quadratic model ordering (parameter \c MODEL_EVAL_SORT). + /** + \param display_degree Display degree -- \b IN. + \param modified_list To indicate a change in the evaluation list -- \b OUT. + */ + void quad_model_ordering ( NOMAD::dd_type display_degree , + bool & modified_list ); + + /// TGP model ordering (parameter \c MODEL_EVAL_SORT). + /** + \param display_degree Display degree -- \b IN. + \param modified_list To indicate a change in the evaluation list -- \b OUT. + */ + void TGP_model_ordering ( NOMAD::dd_type display_degree , + bool & modified_list ); + + /// Count the output stats (STAT_SUM and STAT_AVG). + /** + \param x Lattest evaluation -- \b IN. + */ + void count_output_stats ( const NOMAD::Eval_Point & x ); + + /// Search a point in the cache. + /** + \param x The point -- \b IN/OUT. + \param true_barrier Barrier for true evaluations -- \b IN/OUT. + \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. + \param pareto_front A pointer to the Pareto front -- \b IN/OUT + (may be \c NULL). + \param count_eval Count or not a simulated evaluation -- \b OUT. + \param h_max Maximal feasibility value -- \b IN. + \param display_degree Display degree -- \b IN. + \return A boolean equal to \c true if the point is in cache. + */ + bool cache_check ( const NOMAD::Eval_Point *& x , + NOMAD::Barrier & true_barrier , + NOMAD::Barrier & sgte_barrier , + NOMAD::Pareto_Front * pareto_front , + bool & count_eval , + const NOMAD::Double & h_max , + NOMAD::dd_type display_degree ) const; + + /// Evaluate a point. + /* + \param x The point -- \b IN/OUT. + \param true_barrier Barrier for true evaluations -- \b IN/OUT. + \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. + \param pareto_front A pointer to the Pareto front -- \b IN/OUT + (may be \c NULL). + \param count_eval Count or not the evaluation -- \b OUT. + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + \param h_max Maximal feasibility value -- \b IN. + */ + void eval_point ( NOMAD::Eval_Point & x , + NOMAD::Barrier & true_barrier , + NOMAD::Barrier & sgte_barrier , + NOMAD::Pareto_Front * pareto_front , + bool & count_eval , + bool & stop , + NOMAD::stop_type & stop_reason , + const NOMAD::Double & h_max ); + + + + /// Evaluate points. + /* + \param list_x The list of points -- \b IN/OUT. + \param true_barrier Barrier for true evaluations -- \b IN/OUT. + \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. + \param pareto_front A pointer to the Pareto front -- \b IN/OUT + (may be \c NULL). + \param list_count_eval A list of bool for counted evaluations -- \b OUT. + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + \param h_max Maximal feasibility value -- \b IN. + */ + void eval_points ( std::list<NOMAD::Eval_Point *> & list_x , + NOMAD::Barrier & true_barrier , + NOMAD::Barrier & sgte_barrier , + NOMAD::Pareto_Front * pareto_front , + std::list<bool> & list_count_eval , + bool & stop , + NOMAD::stop_type & stop_reason , + const NOMAD::Double & h_max ); + + + + + /// Check if a search is opportunistic or not. + /** + \param t Search type -- \b IN. + \return A boolean equal to \c true if the search is opportunistic. + */ + bool is_opportunistic ( NOMAD::search_type t ) const; + + /// Check stopping criteria. + /** + \param search Search type -- \b IN. + \param count_eval Count or not the evaluation -- \b IN. + \param x Lattest evaluation -- \b IN/OUT. + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + */ + void check_stopping_criteria ( NOMAD::search_type search , + bool count_eval , + const NOMAD::Eval_Point & x , + bool & stop , + NOMAD::stop_type & stop_reason ) const; + #ifdef USE_MPI - - /// Receive an evaluation result from a slave. - /** - \param search Search type -- \b IN. - \param x A pointer to the evaluation -- \b OUT. - \param true_barrier Barrier for true evaluations -- \b IN/OUT. - \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. - \param pareto_front A pointer to the Pareto front -- \b IN/OUT - (may be \c NULL). - \param slave_rank Slave rank -- \b IN. - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - */ - void receive_eval_result ( NOMAD::search_type search , - NOMAD::Eval_Point * x , - NOMAD::Barrier & true_barrier , - NOMAD::Barrier & sgte_barrier , - NOMAD::Pareto_Front * pareto_front , - int slave_rank , - bool & stop , - NOMAD::stop_type & stop_reason ); - - /// Check if the evaluation of a point is already in progress. - /** - \param x The point -- \b IN. - \return A boolean equal to \c true if the evaluation - of the point is already in progress. - */ - bool already_in_progress ( const NOMAD::Eval_Point & x ) const; - + + /// Receive an evaluation result from a slave. + /** + \param search Search type -- \b IN. + \param x A pointer to the evaluation -- \b OUT. + \param true_barrier Barrier for true evaluations -- \b IN/OUT. + \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. + \param pareto_front A pointer to the Pareto front -- \b IN/OUT + (may be \c NULL). + \param slave_rank Slave rank -- \b IN. + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + */ + void receive_eval_result ( NOMAD::search_type search , + NOMAD::Eval_Point * x , + NOMAD::Barrier & true_barrier , + NOMAD::Barrier & sgte_barrier , + NOMAD::Pareto_Front * pareto_front , + int slave_rank , + bool & stop , + NOMAD::stop_type & stop_reason ); + + /// Check if the evaluation of a point is already in progress. + /** + \param x The point -- \b IN. + \return A boolean equal to \c true if the evaluation + of the point is already in progress. + */ + bool already_in_progress ( const NOMAD::Eval_Point & x ) const; + #endif - - /// Evaluate a list of points. - /** - - "Evaluate a list of points" is abbreviated with "eval_lop". - - This method is private and is called by the public eval_lop method. - - This method is defined twice in the .cpp for scalar and parallel versions. - - The method clears the list of points \c this->_eval_lop. - \param search Search type -- \b IN. - \param true_barrier Barrier for true evaluations -- \b IN/OUT. - \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. - \param pareto_front A pointer to the Pareto front -- \b IN/OUT - (may be \c NULL). - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - \param new_feas_inc Pointer to the new feasible incumbent -- \b OUT. - \param new_infeas_inc Pointer to the new infeasible incumbent -- \b OUT. - \param success Success for these evaluations -- \b OUT. - \param evaluated_pts List of processed points -- \b OUT. - */ - void private_eval_list_of_points - ( NOMAD::search_type search , - NOMAD::Barrier & true_barrier , - NOMAD::Barrier & sgte_barrier , - NOMAD::Pareto_Front * pareto_front , - bool & stop , - NOMAD::stop_type & stop_reason , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc , - NOMAD::success_type & success , - std::list<const NOMAD::Eval_Point *> & evaluated_pts ); - + + /// Evaluate a list of points. + /** + - "Evaluate a list of points" is abbreviated with "eval_lop". + - This method is private and is called by the public eval_lop method. + - This method is defined twice in the .cpp for scalar and parallel versions. + - The method clears the list of points \c this->_eval_lop. + \param search Search type -- \b IN. + \param true_barrier Barrier for true evaluations -- \b IN/OUT. + \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. + \param pareto_front A pointer to the Pareto front -- \b IN/OUT + (may be \c NULL). + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + \param new_feas_inc Pointer to the new feasible incumbent -- \b OUT. + \param new_infeas_inc Pointer to the new infeasible incumbent -- \b OUT. + \param success Success for these evaluations -- \b OUT. + \param evaluated_pts List of processed points -- \b OUT. + */ + void private_eval_list_of_points + ( NOMAD::search_type search , + NOMAD::Barrier & true_barrier , + NOMAD::Barrier & sgte_barrier , + NOMAD::Pareto_Front * pareto_front , + bool & stop , + NOMAD::stop_type & stop_reason , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc , + NOMAD::success_type & success , + std::list<const NOMAD::Eval_Point *> & evaluated_pts ); + + #ifdef MODEL_STATS - /// Display stats on an evaluation for which a model has been used. - /** - \param evaluated_pts List of evaluated points -- \b IN. - */ - void display_model_stats - ( const std::list<const NOMAD::Eval_Point *> & evaluated_pts ) const; + /// Display stats on an evaluation for which a model has been used. + /** + \param evaluated_pts List of evaluated points -- \b IN. + */ + void display_model_stats + ( const std::list<const NOMAD::Eval_Point *> & evaluated_pts ) const; #endif - - public: - - /// Constructor. - /** - \param p Parameters -- \b IN. - \param stats Stats -- \b IN/OUT. - \param ev Pointer to the Evaluator -- \b IN (may be \c NULL). - \param cache Pointer to the cache -- \b IN/OUT (may be \c NULL). - \param sgte_cache Pointer to the surrogate cache -- \b IN/OUT (may be \c NULL). - */ - Evaluator_Control ( const NOMAD::Parameters & p , - NOMAD::Stats & stats , - NOMAD::Evaluator * ev , - NOMAD::Cache * cache , - NOMAD::Cache * sgte_cache ); - - /// Destructor. - virtual ~Evaluator_Control ( void ); - - /// Force quit (called by pressing Ctrl-C). - static void force_quit ( void ) { Evaluator_Control::_force_quit = true; } - - - /// Display in stats file according to parameter \c STATS_FILE. - /** - \param file_name Name of the output file -- \b IN. - \param x Pointer to the lattest evaluation -- \b IN (may be \c NULL). - \param feasible Equal to \c true if \c x is feasible -- \b IN. - \param multi_obj Pointer to several objective values -- \b IN (may be \c NULL). - */ - void stats_file ( const std::string & file_name , - const NOMAD::Eval_Point * x , - bool feasible , - const NOMAD::Point * multi_obj ) const; - - /// Display stats during NOMAD::Mads::run() for minimal and normal display. - /** - \param header Boolean equal to \c true if a header has to be displayed - -- \b IN. - \param out Display -- \b IN. - \param stats List of stats to display -- \b IN. - \param x Pointer to the lattest evaluation -- \b IN (may be \c NULL). - \param feasible Equal to \c true if \c x is feasible -- \b IN. - \param multi_obj Pointer to several objective values -- \b IN (may be \c NULL). - */ - void display_stats ( bool header , - const NOMAD::Display & out , - const std::list<std::string> & stats , - const NOMAD::Eval_Point * x , - bool feasible , - const NOMAD::Point * multi_obj ) const; - - /// Display a real according to parameter \c DISPLAY_STATS. - /** - \param out Display -- \b IN. - \param d The real to display -- \b IN. - \param format The format - -- \b IN -- \b optional (default = empty string). - */ - void display_stats_real ( const NOMAD::Display & out , - const NOMAD::Double & d , - const std::string & format = "" ) const; - - /// Display a number according to its type \c DISPLAY_STATS. - /** - \param out Display -- \b IN. - \param d The number to display -- \b IN. - \param bbType The type to display -- \b IN. - */ - void display_stats_type ( const NOMAD::Display & out , - const NOMAD::Double & d , - const NOMAD::bb_input_type & bbType ) const; - - /// Display an integer according to parameter \c DISPLAY_STATS. - /** - \param out Display -- \b IN. - \param i The integer to display -- \b IN. - \param max_i Maximal value of \c i used to determine the display width - -- \b IN -- \b optional (default = \c -1). - \param format The format - -- \b IN -- \b optional (default = empty string). - */ - void display_stats_int ( const NOMAD::Display & out , - int i , - int max_i = -1 , - const std::string & format = "" ) const; - - /// Display a point according to parameter \c DISPLAY_STATS. - /** - \param out Display -- \b IN. - \param display_stats List of stats to display -- \b IN. - \param it Iterator for the list \c stats -- \b IN/OUT. - \param x Pointer to the point -- \b IN (may be \c NULL). - \param bbType Vector of input type -- \b IN -- \b optional (default = \c empty vector). - */ - void display_stats_point ( const NOMAD::Display & out , - const std::list<std::string> & display_stats , - std::list<std::string>::const_iterator & it , - const NOMAD::Point * x , - const std::vector<NOMAD::bb_input_type> & bbType = std::vector<NOMAD::bb_input_type> (0) ) const; - - /// Display model ordering stats ( parameter \c MODEL_EVAL_SORT ). - /** - \param out Display -- \b IN. - */ - void display_model_ordering_stats ( const NOMAD::Display & out ) const - { - out << _model_ordering_stats << std::endl; - } - - /// Save the caches. - /** - \param overwrite A boolean equal to \c true if the cache files - may be overwritten -- \b IN. - \return A boolean equal to \c true if the caches could be saved. - */ - bool save_caches ( bool overwrite ); - - /// Update the solution file. - /** - \param x The lattest solution -- \b IN. - \param display_bimv Required to display least infeasible (default=false) -- \b IN - */ - void write_solution_file ( const NOMAD::Eval_Point & x , bool display_bimv=false) const; - - /// Update a barrier from another barrier. - /** - Update barrier \c b1 from points in barrier \c b2 and treat - these points as evaluations (used in VNS search). - \param b1 First barrier -- \b IN/OUT. - \param b2 Second barrier -- \b IN. - \param pareto_front A pointer to the Pareto front -- \b IN/OUT - (may be \c NULL). - \param display_degree Display degree -- \b IN. - \param search Search type -- \b IN. - \return Success for these simulated evaluations. - */ - NOMAD::success_type process_barrier_points ( NOMAD::Barrier & b1 , - const NOMAD::Barrier & b2 , - NOMAD::Pareto_Front * pareto_front , - NOMAD::dd_type display_degree , - NOMAD::search_type search ) const; - /// Access to the cache (#1). - /** - Non-const version. - \return The cache. - */ - NOMAD::Cache & get_cache ( void ) { return *_cache; } - - /// Access to the cache (#2). - /** - Const version. - \return The cache. - */ - const NOMAD::Cache & get_cache ( void ) const { return *_cache; } - - /// Access to the surrogate cache (#1). - /** - Non-const version. - \return The surrogate cache. - */ - NOMAD::Cache & get_sgte_cache ( void ) { return *_sgte_cache; } - - /// Access to the surrogate cache (#2). - /** - Const version. - \return The surrogate cache. - */ - const NOMAD::Cache & get_sgte_cache ( void ) const { return *_sgte_cache; } - - /// Access to the evaluator. - /** - \return The evaluator. - */ - NOMAD::Evaluator * get_evaluator ( void ) const { return _ev; } - - /// Access to \c _last_stats_tag. - /** - \return \c _last_stats_tag. - */ - int get_last_stats_tag ( void ) const { return _last_stats_tag; } - - /// Access to _last_stats_bbe. - /** - \return _last_stats_bbe. - */ - int get_last_stats_bbe ( void ) const { return _last_stats_bbe; } - - /// Set the evaluator. - /** - \param e A pointer to the evaluator -- \b IN. - */ - void set_evaluator ( NOMAD::Evaluator * e ) { _ev = e; } - -#ifdef USE_TGP - /// Set the last TGP model from the model search. - /** - \param m The last TGP model -- \b IN. - */ - void set_last_TGP_model ( NOMAD::TGP_Model * m ) { _last_TGP_model = m; } + + public: + + /// Constructor. + /** + \param p Parameters -- \b IN. + \param stats Stats -- \b IN/OUT. + \param ev Pointer to the Evaluator -- \b IN (may be \c NULL). + \param cache Pointer to the cache -- \b IN/OUT (may be \c NULL). + \param sgte_cache Pointer to the surrogate cache -- \b IN/OUT (may be \c NULL). + */ + Evaluator_Control ( const NOMAD::Parameters & p , + NOMAD::Stats & stats , + NOMAD::Evaluator * ev , + NOMAD::Cache * cache , + NOMAD::Cache * sgte_cache ); + + /// Destructor. + virtual ~Evaluator_Control ( void ); + + /// Force quit (called by pressing Ctrl-C). + static void force_quit ( void ) + { + Evaluator_Control::_force_quit = true; + } + + /// Force evaluation failure. + static void force_evaluation_failure ( void ) + { + Evaluator_Control::_force_evaluation_failure = true; + } + + + /// Display in stats file according to parameter \c STATS_FILE. + /** + \param file_name Name of the output file -- \b IN. + \param x Pointer to the lattest evaluation -- \b IN (may be \c NULL). + \param feasible Equal to \c true if \c x is feasible -- \b IN. + \param multi_obj Pointer to several objective values -- \b IN (may be \c NULL). + */ + void stats_file ( const std::string & file_name , + const NOMAD::Eval_Point * x , + bool feasible , + const NOMAD::Point * multi_obj ) const; + + /// Display stats during NOMAD::Mads::run() for minimal and normal display. + /** + \param header Boolean equal to \c true if a header has to be displayed + -- \b IN. + \param out Display -- \b IN. + \param stats List of stats to display -- \b IN. + \param x Pointer to the lattest evaluation -- \b IN (may be \c NULL). + \param feasible Equal to \c true if \c x is feasible -- \b IN. + \param multi_obj Pointer to several objective values -- \b IN (may be \c NULL). + */ + void display_stats ( bool header , + const NOMAD::Display & out , + const std::list<std::string> & stats , + const NOMAD::Eval_Point * x , + bool feasible , + const NOMAD::Point * multi_obj ) const; + + /// Display a real according to parameter \c DISPLAY_STATS. + /** + \param out Display -- \b IN. + \param d The real to display -- \b IN. + \param format The format + -- \b IN -- \b optional (default = empty string). + */ + void display_stats_real ( const NOMAD::Display & out , + const NOMAD::Double & d , + const std::string & format = "" ) const; + + /// Display a number according to its type \c DISPLAY_STATS. + /** + \param out Display -- \b IN. + \param d The number to display -- \b IN. + \param bbType The type to display -- \b IN. + */ + void display_stats_type ( const NOMAD::Display & out , + const NOMAD::Double & d , + const NOMAD::bb_input_type & bbType ) const; + + /// Display an integer according to parameter \c DISPLAY_STATS. + /** + \param out Display -- \b IN. + \param i The integer to display -- \b IN. + \param max_i Maximal value of \c i used to determine the display width + -- \b IN -- \b optional (default = \c -1). + \param format The format + -- \b IN -- \b optional (default = empty string). + */ + void display_stats_int ( const NOMAD::Display & out , + int i , + int max_i = -1 , + const std::string & format = "" ) const; + + /// Display a point according to parameter \c DISPLAY_STATS. + /** + \param out Display -- \b IN. + \param display_stats List of stats to display -- \b IN. + \param it Iterator for the list \c stats -- \b IN/OUT. + \param x Pointer to the point -- \b IN (may be \c NULL). + \param bbType Vector of input type -- \b IN -- \b optional (default = \c empty vector). + */ + void display_stats_point ( const NOMAD::Display & out , + const std::list<std::string> & display_stats , + std::list<std::string>::const_iterator & it , + const NOMAD::Point * x , + const std::vector<NOMAD::bb_input_type> & bbType = std::vector<NOMAD::bb_input_type> (0) ) const; + + /// Display model ordering stats ( parameter \c MODEL_EVAL_SORT ). + /** + \param out Display -- \b IN. + */ + void display_model_ordering_stats ( const NOMAD::Display & out ) const + { + out << _model_ordering_stats << std::endl; + } + + /// Save the caches. + /** + \param overwrite A boolean equal to \c true if the cache files + may be overwritten -- \b IN. + \return A boolean equal to \c true if the caches could be saved. + */ + bool save_caches ( bool overwrite ); + + /// Update the solution file. + /** + \param x The lattest solution -- \b IN. + \param display_bimv Required to display least infeasible (default=false) -- \b IN + */ + void write_solution_file ( const NOMAD::Eval_Point & x , bool display_bimv=false) const; + + /// Update a barrier from another barrier. + /** + Update barrier \c b1 from points in barrier \c b2 and treat + these points as evaluations (used in VNS search). + \param b1 First barrier -- \b IN/OUT. + \param b2 Second barrier -- \b IN. + \param pareto_front A pointer to the Pareto front -- \b IN/OUT + (may be \c NULL). + \param display_degree Display degree -- \b IN. + \param search Search type -- \b IN. + \return Success for these simulated evaluations. + */ + NOMAD::success_type process_barrier_points ( NOMAD::Barrier & b1 , + const NOMAD::Barrier & b2 , + NOMAD::Pareto_Front * pareto_front , + NOMAD::dd_type display_degree , + NOMAD::search_type search ) const; + /// Access to the cache (#1). + /** + Non-const version. + \return The cache. + */ + NOMAD::Cache & get_cache ( void ) { return *_cache; } + + /// Access to the cache (#2). + /** + Const version. + \return The cache. + */ + const NOMAD::Cache & get_cache ( void ) const { return *_cache; } + + /// Access to the surrogate cache (#1). + /** + Non-const version. + \return The surrogate cache. + */ + NOMAD::Cache & get_sgte_cache ( void ) { return *_sgte_cache; } + + /// Access to the surrogate cache (#2). + /** + Const version. + \return The surrogate cache. + */ + const NOMAD::Cache & get_sgte_cache ( void ) const { return *_sgte_cache; } + + /// Access to the evaluator. + /** + \return The evaluator. + */ + NOMAD::Evaluator * get_evaluator ( void ) const { return _ev; } + + /// Access to \c _last_stats_tag. + /** + \return \c _last_stats_tag. + */ + int get_last_stats_tag ( void ) const { return _last_stats_tag; } + + /// Access to _last_stats_bbe. + /** + \return _last_stats_bbe. + */ + int get_last_stats_bbe ( void ) const { return _last_stats_bbe; } + + /// Set the evaluator. + /** + \param e A pointer to the evaluator -- \b IN. + */ + void set_evaluator ( NOMAD::Evaluator * e ) { _ev = e; } + +#ifdef USE_TGP + /// Set the last TGP model from the model search. + /** + \param m The last TGP model -- \b IN. + */ + void set_last_TGP_model ( NOMAD::TGP_Model * m ) { _last_TGP_model = m; } #endif - - /// Reset. - void reset ( void ); - - - /// Order eval list of points based on surrogate (1st) or model (2nd) - /** - \param search Search type -- \b IN. - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - \param true_barrier Barrier for true evaluations -- \b IN/OUT. - \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. - */ - void ordering_lop - ( NOMAD::search_type search , // IN : search type - bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::Barrier & true_barrier , // IN/OUT: truth barrier - NOMAD::Barrier & sgte_barrier // IN/OUT: surrogate barrier - ); - - - - - /// Evaluation of a list of points (public version that calls the private version). - /** - \param search Search type -- \b IN. - \param true_barrier Barrier for true evaluations -- \b IN/OUT. - \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. - \param pareto_front A pointer to the Pareto front -- \b IN/OUT - (may be \c NULL). - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - \param new_feas_inc Pointer to the new feasible incumbent -- \b OUT. - \param new_infeas_inc Pointer to the new infeasible incumbent -- \b OUT. - \param success Success for this series of evaluations -- \b OUT. - \param evaluated_pts List of processed points -- \b OUT. - */ - void eval_list_of_points - ( NOMAD::search_type search , - NOMAD::Barrier & true_barrier , - NOMAD::Barrier & sgte_barrier , - NOMAD::Pareto_Front * pareto_front , - bool & stop , - NOMAD::stop_type & stop_reason , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc , - NOMAD::success_type & success , - std::list<const NOMAD::Eval_Point *> * evaluated_pts = NULL ); - - /// Add a point to the list of points to be evaluated. - /** - - The point has to be a dynamic object. - - It can be deleted into the method and be \c NULL after that. - - The point is also snapped to bounds. - - Periodic variables are checked. - \param x The point -- \b IN/OUT. - \param display_degree Display degree -- \b IN. - \param snap_to_bounds Boolean equal to \c true if the - point has to be snapped to bounds -- \b IN. - \param f_sgte Objective value for the surrogate -- \b IN - (may be undefined). - \param h_sgte Feasibility value for the surrogate -- \b IN - (may be undefined). - \param f_model Objective value for the model -- \b IN - (may be undefined). - \param h_model Feasibility value for the model -- \b IN - (may be undefined). - - */ - void add_eval_point ( NOMAD::Eval_Point *& x , - NOMAD::dd_type display_degree , - bool snap_to_bounds , - const NOMAD::Double & f_sgte , - const NOMAD::Double & h_sgte , - const NOMAD::Double & f_model , - const NOMAD::Double & h_model ); - - /// Display the list of evaluation points \c _eval_lop. - /** - \param t Search type -- \b IN - -- \b optional (default = NOMAD::UNDEFINED_SEARCH ). - */ - void display_eval_lop ( NOMAD::search_type t = NOMAD::UNDEFINED_SEARCH ) const; - - /// Access to the number of evaluation points. - /** - \return The number of evaluation points. - */ - int get_nb_eval_points ( void ) const - { - return static_cast<int> ( _eval_lop.size() ); - } - - /// Access to the list of evaluation points. - /** - \return The list of evaluation points. - */ - const std::set<NOMAD::Priority_Eval_Point> & get_eval_lop ( void ) const - { - return _eval_lop; - } - - /// Clear the list of evaluation points. - void clear_eval_lop ( void ) { reduce_eval_lop(0); } - - /// Reduce the list of evaluation points. - /** - \param n New size of the list -- \b IN. - */ - void reduce_eval_lop ( int n ); - - /// Enable the model ordering. - void enable_model_eval_sort ( void ) { _model_eval_sort = true; } - - /// Disable the model ordering. - void disable_model_eval_sort ( void ) { _model_eval_sort = false; } - + + /// Reset. + void reset ( void ); + + + /// Order eval list of points based on surrogate (1st) or model (2nd) + /** + \param search Search type -- \b IN. + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + \param true_barrier Barrier for true evaluations -- \b IN/OUT. + \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. + */ + void ordering_lop + ( NOMAD::search_type search , // IN : search type + bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::Barrier & true_barrier , // IN/OUT: truth barrier + NOMAD::Barrier & sgte_barrier // IN/OUT: surrogate barrier + ); + + + + + /// Evaluation of a list of points (public version that calls the private version). + /** + \param search Search type -- \b IN. + \param true_barrier Barrier for true evaluations -- \b IN/OUT. + \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. + \param pareto_front A pointer to the Pareto front -- \b IN/OUT + (may be \c NULL). + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + \param new_feas_inc Pointer to the new feasible incumbent -- \b OUT. + \param new_infeas_inc Pointer to the new infeasible incumbent -- \b OUT. + \param success Success for this series of evaluations -- \b OUT. + \param evaluated_pts List of processed points -- \b OUT. + */ + void eval_list_of_points + ( NOMAD::search_type search , + NOMAD::Barrier & true_barrier , + NOMAD::Barrier & sgte_barrier , + NOMAD::Pareto_Front * pareto_front , + bool & stop , + NOMAD::stop_type & stop_reason , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc , + NOMAD::success_type & success , + std::list<const NOMAD::Eval_Point *> * evaluated_pts = NULL ); + + /// Add a point to the list of points to be evaluated. + /** + - The point has to be a dynamic object. + - It can be deleted into the method and be \c NULL after that. + - The point is also snapped to bounds. + - Periodic variables are checked. + \param x The point -- \b IN/OUT. + \param display_degree Display degree -- \b IN. + \param snap_to_bounds Boolean equal to \c true if the + point has to be snapped to bounds -- \b IN. + \param f_sgte Objective value for the surrogate -- \b IN + (may be undefined). + \param h_sgte Feasibility value for the surrogate -- \b IN + (may be undefined). + \param f_model Objective value for the model -- \b IN + (may be undefined). + \param h_model Feasibility value for the model -- \b IN + (may be undefined). + + */ + void add_eval_point ( NOMAD::Eval_Point *& x , + NOMAD::dd_type display_degree , + bool snap_to_bounds , + const NOMAD::Double & f_sgte , + const NOMAD::Double & h_sgte , + const NOMAD::Double & f_model , + const NOMAD::Double & h_model ); + + /// Display the list of evaluation points \c _eval_lop. + /** + \param t Search type -- \b IN + -- \b optional (default = NOMAD::UNDEFINED_SEARCH ). + */ + void display_eval_lop ( NOMAD::search_type t = NOMAD::UNDEFINED_SEARCH ) const; + + /// Access to the number of evaluation points. + /** + \return The number of evaluation points. + */ + int get_nb_eval_points ( void ) const + { + return static_cast<int> ( _eval_lop.size() ); + } + + /// Access to the list of evaluation points. + /** + \return The list of evaluation points. + */ + const std::set<NOMAD::Priority_Eval_Point> & get_eval_lop ( void ) const + { + return _eval_lop; + } + + /// Clear the list of evaluation points. + void clear_eval_lop ( void ) { reduce_eval_lop(0); } + + /// Reduce the list of evaluation points. + /** + \param n New size of the list -- \b IN. + */ + void reduce_eval_lop ( int n ); + + /// Enable the model ordering. + void enable_model_eval_sort ( void ) { _model_eval_sort = true; } + + /// Disable the model ordering. + void disable_model_eval_sort ( void ) { _model_eval_sort = false; } + #ifdef USE_MPI - - /// Access to the number of evaluations in progress. - /** - \return the number of evaluations in progress. - */ - int get_nb_eval_in_progress ( void ) const { return _nb_in_progress; } - - /// Wait for evaluations in progress. - /** - \param search Search type -- \b IN. - \param true_barrier Barrier for true evaluations -- \b IN/OUT. - \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. - \param pareto_front A pointer to the Pareto front -- \b IN/OUT - (may be \c NULL). - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - \param success Success for these evaluations -- \b OUT. - \param evaluated_pts List of processed points -- \b OUT. - */ - void wait_for_evaluations ( NOMAD::search_type search , - NOMAD::Barrier & true_barrier , - NOMAD::Barrier & sgte_barrier , - NOMAD::Pareto_Front * pareto_front , - bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::success_type & success , - std::list<const NOMAD::Eval_Point *> - & evaluated_pts ); + + /// Access to the number of evaluations in progress. + /** + \return the number of evaluations in progress. + */ + int get_nb_eval_in_progress ( void ) const { return _nb_in_progress; } + + /// Wait for evaluations in progress. + /** + \param search Search type -- \b IN. + \param true_barrier Barrier for true evaluations -- \b IN/OUT. + \param sgte_barrier Barrier for surrogate evaluations -- \b IN/OUT. + \param pareto_front A pointer to the Pareto front -- \b IN/OUT + (may be \c NULL). + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + \param success Success for these evaluations -- \b OUT. + \param evaluated_pts List of processed points -- \b OUT. + */ + void wait_for_evaluations ( NOMAD::search_type search , + NOMAD::Barrier & true_barrier , + NOMAD::Barrier & sgte_barrier , + NOMAD::Pareto_Front * pareto_front , + bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::success_type & success , + std::list<const NOMAD::Eval_Point *> + & evaluated_pts ); #endif - }; + }; } #endif diff --git a/src/Exception.cpp b/src/Exception.cpp index b600dda..cd72299 100644 --- a/src/Exception.cpp +++ b/src/Exception.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Exception.hpp b/src/Exception.hpp index e318c49..5e32917 100644 --- a/src/Exception.hpp +++ b/src/Exception.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Extended_Poll.cpp b/src/Extended_Poll.cpp index 85d008c..4344e92 100644 --- a/src/Extended_Poll.cpp +++ b/src/Extended_Poll.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -47,10 +47,10 @@ /*----------------------------------------------------------------*/ NOMAD::Extended_Poll::~Extended_Poll ( void ) { - std::set<NOMAD::Signature_Element>::const_iterator it , end = _signatures.end(); - for ( it = _signatures.begin() ; it != end ; ++it ) - delete (*it).get_signature(); - poll_reset(); + std::set<NOMAD::Signature_Element>::const_iterator it , end = _signatures.end(); + for ( it = _signatures.begin() ; it != end ; ++it ) + delete (*it).get_signature(); + poll_reset(); } /*----------------------------------------------------------------*/ @@ -58,16 +58,16 @@ NOMAD::Extended_Poll::~Extended_Poll ( void ) /*----------------------------------------------------------------*/ void NOMAD::Extended_Poll::reset ( void ) { - // successful directions: - std::set<NOMAD::Signature_Element>::const_iterator it , end = _signatures.end(); - for ( it = _signatures.begin() ; it != end ; ++it ) - { - (*it).get_signature()->reset_feas_success_dir(); - (*it).get_signature()->reset_infeas_success_dir(); - } - - // poll_reset: - poll_reset(); + // successful directions: + std::set<NOMAD::Signature_Element>::const_iterator it , end = _signatures.end(); + for ( it = _signatures.begin() ; it != end ; ++it ) + { + (*it).get_signature()->reset_feas_success_dir(); + (*it).get_signature()->reset_infeas_success_dir(); + } + + // poll_reset: + poll_reset(); } /*----------------------------------------------------------------*/ @@ -75,13 +75,13 @@ void NOMAD::Extended_Poll::reset ( void ) /*----------------------------------------------------------------*/ void NOMAD::Extended_Poll::poll_reset ( void ) { - _poll_signatures.clear(); - std::list<NOMAD::Eval_Point *>::const_iterator end = _extended_points.end(); - for ( std::list<NOMAD::Eval_Point *>::iterator it = _extended_points.begin() ; - it != end ; ++it ) - if ( !(*it)->is_in_cache() ) - delete *it; - _extended_points.clear(); + _poll_signatures.clear(); + std::list<NOMAD::Eval_Point *>::const_iterator end = _extended_points.end(); + for ( std::list<NOMAD::Eval_Point *>::iterator it = _extended_points.begin() ; + it != end ; ++it ) + if ( !(*it)->is_in_cache() ) + delete *it; + _extended_points.clear(); } /*----------------------------------------------------------------*/ @@ -89,49 +89,56 @@ void NOMAD::Extended_Poll::poll_reset ( void ) /* created by the user in construct_extended_points() */ /*----------------------------------------------------------------*/ void NOMAD::Extended_Poll::add_extended_poll_point ( NOMAD::Point & ep , - NOMAD::Signature & s ) + NOMAD::Signature & s ) { - // new signature: - // -------------- - NOMAD::Signature * new_s = new NOMAD::Signature (s); - - // . 's' can be standard, but its copy 'new_s' is not - - // . a standard signature will never be inserted into _signatures, - // since standard signatures are handled and deleted by the Parameters class - - { - // signature already registered ? - NOMAD::Signature_Element se ( new_s ); - std::set<NOMAD::Signature_Element>::const_iterator it = _signatures.find ( se ); - - // signature already registered: - if ( it != _signatures.end() ) - { - - // success directions eventually included in new_s are not considered - // since new_s is the copy of s, which is user provided - - delete new_s; - new_s = it->get_signature(); - } - - // new signature to register: - else - _signatures.insert ( se ); - - _poll_signatures.insert ( NOMAD::Signature_Element ( new_s ) ); - } - - // new eval point: - // --------------- - int ell = NOMAD::Mesh::get_mesh_index(); - NOMAD::Eval_Point * pt = new NOMAD::Eval_Point; - pt->set ( ep , _p.get_bb_nb_outputs() ); - pt->set_signature ( new_s ); - pt->set_mesh_index ( &ell ); - - _extended_points.push_back ( pt ); + // new signature: + // -------------- + NOMAD::Signature * new_s = new NOMAD::Signature (s); + + // . 's' can be standard, but its copy 'new_s' is not + + // . a standard signature will never be inserted into _signatures, + // since standard signatures are handled and deleted by the Parameters class + + { + // signature already registered ? + NOMAD::Signature_Element se ( new_s ); + std::set<NOMAD::Signature_Element>::const_iterator it = _signatures.find ( se ); + + // signature already registered: + if ( it != _signatures.end() ) + { + + // success directions eventually included in new_s are not considered + // since new_s is the copy of s, which is user provided + + delete new_s; + new_s = it->get_signature(); + } + + // new signature to register: + else + _signatures.insert ( se ); + + _poll_signatures.insert ( NOMAD::Signature_Element ( new_s ) ); + } + + // new eval point: + // --------------- + NOMAD::Eval_Point * pt = new NOMAD::Eval_Point; + pt->set ( ep , _p.get_bb_nb_outputs() ); + pt->set_signature ( new_s ); + + for ( int i = 0 ; i < pt->get_n() ; ++i ) + { + if ( (pt->get_signature()->get_input_type())[i] != NOMAD::CONTINUOUS && ! (*pt)[i].is_integer() ) + + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , + "NOMAD::Extended_Poll::add_extended_points(): the categorical variables of the added point must be an integer." ); + } + + + _extended_points.push_back ( pt ); } /*----------------------------------------------------------------*/ @@ -141,333 +148,361 @@ void NOMAD::Extended_Poll::add_extended_poll_point ( NOMAD::Point & ep , /* . private method */ /*----------------------------------------------------------------*/ bool NOMAD::Extended_Poll::check_trigger ( const NOMAD::Eval_Point * old_bf , - const NOMAD::Eval_Point * old_bi , - const NOMAD::Eval_Point * y ) const + const NOMAD::Eval_Point * old_bi , + const NOMAD::Eval_Point * y ) const { - if ( !y->is_in_cache() || - !y->is_eval_ok() || - !y->get_f().is_defined() || - !y->get_h().is_defined() ) - return false; - - // y is feasible: - // -------------- - if ( y->is_feasible ( _p.get_h_min() ) ) - { - - if ( !old_bf ) - return true; - - return check_trigger_on_f ( old_bf->get_f() , y->get_f() ); - } - - // y is infeasible: - // ---------------- - if ( !old_bf && !old_bi ) - return true; - - if ( !old_bf ) - return ( y->get_h() < old_bi->get_h() ); - - if ( !old_bi ) - return check_trigger_on_f ( old_bf->get_f() , y->get_f() ); - - if ( y->get_h() >= old_bi->get_h() ) - return false; - - // y is infeasible, and old best feasible and best infeasible solutions are - // available: the extended poll will be performed if the y point in the - // (h,f) space is below the line joining [ h(old_bf) , f(old_bf)+trigger ] - // to [ h(old_bi) , f(old_bi)+trigger ] : - const NOMAD::Double & hA = old_bf->get_h(); - NOMAD::Double fA = old_bf->get_f(); - - const NOMAD::Double & hB = old_bi->get_h(); - NOMAD::Double fB = old_bi->get_f(); - - const NOMAD::Double & hy = y->get_h(); - const NOMAD::Double & fy = y->get_f(); - - const NOMAD::Double & ept = _p.get_extended_poll_trigger(); - - if ( _p.get_relative_ept() && fA != 0.0 && fB != 0.0 && fy != 0.0 ) - { - fA = fA + fA.abs() * ept; - fB = fB + fB.abs() * ept; - } - else - { - fA = fA + ept; - fB = fB + ept; - } - - // line joining [h(A),f(A)] to [h(B),f(B)]: f=a*h+b : - NOMAD::Double a = (fA-fB) / (hA-hB); - NOMAD::Double b = fA - a * hA; - - return fy < a*hy + b; + if ( !y->is_in_cache() || + !y->is_eval_ok() || + !y->get_f().is_defined() || + !y->get_h().is_defined() ) + return false; + + // y is feasible: + // -------------- + if ( y->is_feasible ( _p.get_h_min() ) ) + { + + if ( !old_bf ) + return true; + + return check_trigger_on_f ( old_bf->get_f() , y->get_f() ); + } + + // y is infeasible: + // ---------------- + if ( !old_bf && !old_bi ) + return true; + + if ( !old_bf ) + return ( y->get_h() < old_bi->get_h() ); + + if ( !old_bi ) + return check_trigger_on_f ( old_bf->get_f() , y->get_f() ); + + if ( y->get_h() >= old_bi->get_h() ) + return false; + + // y is infeasible, and old best feasible and best infeasible solutions are + // available: the extended poll will be performed if the y point in the + // (h,f) space is below the line joining [ h(old_bf) , f(old_bf)+trigger ] + // to [ h(old_bi) , f(old_bi)+trigger ] : + const NOMAD::Double & hA = old_bf->get_h(); + NOMAD::Double fA = old_bf->get_f(); + + const NOMAD::Double & hB = old_bi->get_h(); + NOMAD::Double fB = old_bi->get_f(); + + const NOMAD::Double & hy = y->get_h(); + const NOMAD::Double & fy = y->get_f(); + + const NOMAD::Double & ept = _p.get_extended_poll_trigger(); + + if ( _p.get_relative_ept() && fA != 0.0 && fB != 0.0 && fy != 0.0 ) + { + fA = fA + fA.abs() * ept; + fB = fB + fB.abs() * ept; + } + else + { + fA = fA + ept; + fB = fB + ept; + } + + // line joining [h(A),f(A)] to [h(B),f(B)]: f=a*h+b : + NOMAD::Double a = (fA-fB) / (hA-hB); + NOMAD::Double b = fA - a * hA; + + return fy < a*hy + b; } /*-------------------------------------------------------------------*/ /* check only the f values for the extended poll trigger (private) */ /*-------------------------------------------------------------------*/ bool NOMAD::Extended_Poll::check_trigger_on_f ( const NOMAD::Double & old_f , - const NOMAD::Double & new_f ) const + const NOMAD::Double & new_f ) const { - if ( new_f <= old_f ) - return true; - - // relative comparison (both values are != 0): - if ( _p.get_relative_ept() && old_f != 0.0 && new_f != 0.0 ) - return ( new_f < old_f + old_f.abs() * _p.get_extended_poll_trigger() ); - - // absolute comparison: - return ( new_f < old_f + _p.get_extended_poll_trigger() ); + if ( new_f <= old_f ) + return true; + + // relative comparison (both values are != 0): + if ( _p.get_relative_ept() && old_f != 0.0 && new_f != 0.0 ) + return ( new_f < old_f + old_f.abs() * _p.get_extended_poll_trigger() ); + + // absolute comparison: + return ( new_f < old_f + _p.get_extended_poll_trigger() ); } /*----------------------------------------------------------------*/ /* descent from the extended poll center (private) */ /*----------------------------------------------------------------*/ void NOMAD::Extended_Poll::descent ( const NOMAD::Eval_Point * y , - Mads & mads , - int & nb_ext_poll_pts , - bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::success_type & success , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc ) + Mads & mads , + int & nb_ext_poll_pts , + bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::success_type & success , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc ) { - int mesh_index = NOMAD::Mesh::get_mesh_index(); - NOMAD::Stats & stats = mads.get_stats(); - bool has_sgte = _p.has_sgte(); - bool opt_only_sgte = _p.get_opt_only_sgte(); - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_poll_dd(); - - // displays: - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - - std::ostringstream oss; - oss << NOMAD::EXTENDED_POLL << " descent"; - if ( has_sgte ) - oss << " (on surrogates)"; - - out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; - - out << " iteration = " << stats.get_iterations() << std::endl - << " blackbox eval. = " << stats.get_bb_eval() << std::endl; - if ( has_sgte ) - out << " sgte eval. = " << stats.get_sgte_eval() << std::endl; - out << " mesh index = " << mesh_index << std::endl - << "ext. poll center = ( "; - y->Point::display ( out , " " , 5 , _p.get_point_display_limit() ); - out << " ) f=" << y->get_f() << " h=" << y->get_h() << std::endl << std::endl; - } - - // get the signature: - NOMAD::Signature * signature = y->get_signature(); - - - // create the descent parameters: - NOMAD::Parameters descent_p ( signature , _p.out() ); - set_descent_parameters ( y , stats , descent_p ); - - // Evaluator_Control object: - NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); - - // descent: run MADS: - // ------------------ - NOMAD::Mads EP_mads ( descent_p , - ev_control.get_evaluator () , - NULL , - &ev_control.get_cache () , - &ev_control.get_sgte_cache() ); + + + NOMAD::Stats & stats = mads.get_stats(); + bool has_sgte = _p.has_sgte(); + bool opt_only_sgte = _p.get_opt_only_sgte(); + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_poll_dd(); + + // get the signature: + NOMAD::Signature * signature = y->get_signature(); + + + // displays: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + + std::ostringstream oss; + oss << NOMAD::EXTENDED_POLL << " descent"; + if ( has_sgte ) + oss << " (on surrogates)"; + + out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; + + out << " iteration = " << stats.get_iterations() << std::endl + << " blackbox eval. = " << stats.get_bb_eval() << std::endl; + if ( has_sgte ) + out << " sgte eval. = " << stats.get_sgte_eval() << std::endl; + out << " mesh indices = (" << signature->get_mesh()->get_mesh_indices() << " )" << std::endl + << "ext. poll center = ( "; + y->Point::display ( out , " " , 5 , _p.get_point_display_limit() ); + out << " ) f=" << y->get_f() << " h=" << y->get_h() << std::endl << std::endl; + } + + + + // create the descent parameters: + NOMAD::Parameters descent_p ( signature , _p.out() ); + set_descent_parameters ( y , stats , descent_p ); + + + // mesh indices before the descent --> restore after descent + NOMAD::Point mesh_indices = signature->get_mesh()->get_mesh_indices(); + + // limit mesh index before the descent --> restore after descent + int limit_mesh_index = signature->get_mesh()->get_limit_mesh_index(); + + + // Set mesh indices to 0 + NOMAD::Point delta( signature->get_n(), 0 ); + descent_p.get_signature()->get_mesh()->set_mesh_indices( delta ); + + // Use best_feasible or best_infeasible limit mesh index as a termination criterion for descent + const NOMAD::Eval_Point * old_bf = mads.get_best_feasible(); + const NOMAD::Eval_Point * old_bi = mads.get_best_infeasible(); + int l1=0,l2=0; + if ( old_bf ) + l1 = static_cast<int>((old_bf->get_signature()->get_mesh()->get_min_mesh_indices())[0].value()); // index same for all variables when using categorical variable + else if ( old_bi ) + l2 = static_cast<int>((old_bi->get_signature()->get_mesh()->get_min_mesh_indices())[0].value()); + descent_p.get_signature()->get_mesh()->set_limit_mesh_index( min( l1, l2) ); + + + + // Evaluator_Control object: + NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); + + // descent: run MADS: + // ------------------ + NOMAD::Mads EP_mads ( descent_p , + ev_control.get_evaluator () , + NULL , + &ev_control.get_cache () , + &ev_control.get_sgte_cache() ); #ifdef DEBUG out << std::endl << NOMAD::open_block ( "MADS run (ext. poll)" ) << std::endl; #endif - - NOMAD::Mads::set_flag_reset_barriers ( true ); - NOMAD::Mads::set_flag_reset_mesh ( false ); - - NOMAD::stop_type st = EP_mads.run(); - - NOMAD::Mads::set_flag_reset_mesh ( true ); - + + NOMAD::Mads::set_flag_reset_barriers ( true ); + NOMAD::Mads::set_flag_reset_mesh ( false ); + + NOMAD::stop_type st = EP_mads.run(); + + NOMAD::Mads::set_flag_reset_mesh ( true ); + #ifdef DEBUG out << std::endl << NOMAD::close_block ( "end of run (ext. poll)" ) << std::endl; #endif - - // restore mesh index: - NOMAD::Mesh::set_mesh_index ( mesh_index ); - - // update stats: - const NOMAD::Stats & EP_stats = EP_mads.get_stats(); - stats.update ( EP_stats , true ); // for_search = true - stats.add_ext_poll_bb_eval ( EP_stats.get_bb_eval() ); - stats.add_ext_poll_descent (); - - // check MADS stopping criteria: - if ( st == NOMAD::CTRL_C || - st == NOMAD::ERROR || - st == NOMAD::UNKNOWN_STOP_REASON || - st == NOMAD::FEAS_REACHED || - st == NOMAD::MAX_CACHE_MEMORY_REACHED || - st == NOMAD::STAT_SUM_TARGET_REACHED || - st == NOMAD::MAX_SGTE_EVAL_REACHED || - st == NOMAD::F_TARGET_REACHED || - st == NOMAD::MAX_SIM_BB_EVAL_REACHED || - st == NOMAD::MAX_TIME_REACHED || - st == NOMAD::MAX_BB_EVAL_REACHED ) - { - stop_reason = st; - stop = true; - } - - // Pareto front: - NOMAD::Pareto_Front * pareto_front = mads.get_pareto_front(); - - // the barriers: - NOMAD::Barrier & true_barrier = mads.get_true_barrier(); - NOMAD::Barrier & sgte_barrier = mads.get_sgte_barrier(); - - // surrogate evaluations: perform at most one true evaluation: - if ( has_sgte && !opt_only_sgte ) - { - - if ( !stop ) - { - - // remember old best surrogates incumbents: - const NOMAD::Eval_Point * old_sgte_bf = sgte_barrier.get_best_feasible (); - const NOMAD::Eval_Point * old_sgte_bi = sgte_barrier.get_best_infeasible(); - - // update the surrogate barrier - // (no need to invoke Evaluator_Control::process_barrier_points() here - // since only surrogate evaluations have been made): - sgte_barrier.insert ( EP_mads.get_sgte_barrier() ); - NOMAD::success_type sgte_succ = sgte_barrier.get_success(); - sgte_barrier.update_and_reset_success(); - - // we generate only a true trial point if the - // surrogates improved the surrogate barrier: - if ( sgte_succ != NOMAD::UNSUCCESSFUL ) - { - - // choose the best surrogate point(s) where to evaluate the true function: - const NOMAD::Eval_Point * sgte_bf = sgte_barrier.get_best_feasible (); - const NOMAD::Eval_Point * sgte_bi = sgte_barrier.get_best_infeasible(); - - std::list<const NOMAD::Eval_Point *> candidates; - - if ( sgte_bf && ( !y->is_feasible(_p.get_h_min()) || sgte_bf != old_sgte_bf ) ) - candidates.push_back ( sgte_bf ); - - if ( sgte_bi && sgte_bi != old_sgte_bi ) - candidates.push_back ( sgte_bi ); - - // generate the new trial points: - NOMAD::Eval_Point * sk; - std::list<const NOMAD::Eval_Point *>::const_iterator it , end = candidates.end(); - for ( it = candidates.begin() ; it != end ; ++it ) - { - - // display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << "ext. poll surrogate candidate: " << **it << std::endl; - - sk = new NOMAD::Eval_Point; - sk->set ( signature->get_n() , _p.get_bb_nb_outputs() ); - sk->set_signature ( signature ); - sk->set_mesh_index ( &mesh_index ); - sk->Point::operator = ( **it ); - - // add the new point to the list of trial points: - ev_control.add_eval_point ( sk , - display_degree , - _p.get_snap_to_bounds() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() ); - } - - // eval_list_of_points: - // -------------------- - success = NOMAD::UNSUCCESSFUL; - new_feas_inc = new_infeas_inc = NULL; - - ev_control.eval_list_of_points ( NOMAD::EXTENDED_POLL , - true_barrier , - sgte_barrier , - pareto_front , - stop , - stop_reason , - new_feas_inc , - new_infeas_inc , - success ); - - // number of search points (0 or 1 or 2): - nb_ext_poll_pts += static_cast<int> ( candidates.size() ); - } - } - } - - // true evaluations (or surrogate evaluations if opt_only_sgte==true): - else - { - - const NOMAD::Barrier & active_barrier = mads.get_active_barrier(); - - // for the update of new_feas_inc and new_infeas_inc (1/2): - const NOMAD::Eval_Point * old_feasible_incumbent - = active_barrier.get_best_feasible(); - const NOMAD::Eval_Point * old_infeasible_incumbent - = active_barrier.get_best_infeasible(); - - // update barriers and process extended poll points: - NOMAD::success_type sgte_succ - = ev_control.process_barrier_points ( sgte_barrier , - EP_mads.get_sgte_barrier() , - pareto_front , - display_degree , - NOMAD::EXTENDED_POLL ); - - NOMAD::success_type true_succ - = ev_control.process_barrier_points ( true_barrier , - EP_mads.get_true_barrier() , - pareto_front , - display_degree , - NOMAD::EXTENDED_POLL ); - - // update of new_feas_inc and new_infeas_inc (2/2): - const NOMAD::Eval_Point * bf = active_barrier.get_best_feasible (); - const NOMAD::Eval_Point * bi = active_barrier.get_best_infeasible(); - if ( bf && bf != old_feasible_incumbent ) - new_feas_inc = bf; - if ( bi && bi != old_infeasible_incumbent ) - new_infeas_inc = bi; - - // number of extended poll points and success: - if ( opt_only_sgte ) - { - nb_ext_poll_pts += EP_mads.get_stats().get_sgte_eval(); - success = sgte_succ; - } - else - { - nb_ext_poll_pts += EP_mads.get_stats().get_eval(); - success = true_succ; - } - } - - // final display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - std::ostringstream oss; - oss << "end of " << NOMAD::EXTENDED_POLL << " descent (" << success << ")"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } + + // Restore mesh indices and limit mesh index (termination criterion) + signature->get_mesh()->set_mesh_indices( mesh_indices ); + signature->get_mesh()->set_limit_mesh_index( limit_mesh_index ); + + + // update stats: + const NOMAD::Stats & EP_stats = EP_mads.get_stats(); + stats.update ( EP_stats , true ); // for_search = true + stats.add_ext_poll_bb_eval ( EP_stats.get_bb_eval() ); + stats.add_ext_poll_descent (); + + // check MADS stopping criteria: + if ( st == NOMAD::CTRL_C || + st == NOMAD::ERROR || + st == NOMAD::UNKNOWN_STOP_REASON || + st == NOMAD::FEAS_REACHED || + st == NOMAD::MAX_CACHE_MEMORY_REACHED || + st == NOMAD::STAT_SUM_TARGET_REACHED || + st == NOMAD::MAX_SGTE_EVAL_REACHED || + st == NOMAD::F_TARGET_REACHED || + st == NOMAD::MAX_SIM_BB_EVAL_REACHED || + st == NOMAD::MAX_TIME_REACHED || + st == NOMAD::MAX_BB_EVAL_REACHED ) + { + stop_reason = st; + stop = true; + } + + // Pareto front: + NOMAD::Pareto_Front * pareto_front = mads.get_pareto_front(); + + // the barriers: + NOMAD::Barrier & true_barrier = mads.get_true_barrier(); + NOMAD::Barrier & sgte_barrier = mads.get_sgte_barrier(); + + // surrogate evaluations: perform at most one true evaluation: + if ( has_sgte && !opt_only_sgte ) + { + + if ( !stop ) + { + + // remember old best surrogates incumbents: + const NOMAD::Eval_Point * old_sgte_bf = sgte_barrier.get_best_feasible (); + const NOMAD::Eval_Point * old_sgte_bi = sgte_barrier.get_best_infeasible(); + + // update the surrogate barrier + // (no need to invoke Evaluator_Control::process_barrier_points() here + // since only surrogate evaluations have been made): + sgte_barrier.insert ( EP_mads.get_sgte_barrier() ); + NOMAD::success_type sgte_succ = sgte_barrier.get_success(); + sgte_barrier.update_and_reset_success(); + + // we generate only a true trial point if the + // surrogates improved the surrogate barrier: + if ( sgte_succ != NOMAD::UNSUCCESSFUL ) + { + + // choose the best surrogate point(s) where to evaluate the true function: + const NOMAD::Eval_Point * sgte_bf = sgte_barrier.get_best_feasible (); + const NOMAD::Eval_Point * sgte_bi = sgte_barrier.get_best_infeasible(); + + std::list<const NOMAD::Eval_Point *> candidates; + + if ( sgte_bf && ( !y->is_feasible(_p.get_h_min()) || sgte_bf != old_sgte_bf ) ) + candidates.push_back ( sgte_bf ); + + if ( sgte_bi && sgte_bi != old_sgte_bi ) + candidates.push_back ( sgte_bi ); + + // generate the new trial points: + NOMAD::Eval_Point * sk; + std::list<const NOMAD::Eval_Point *>::const_iterator it , end = candidates.end(); + for ( it = candidates.begin() ; it != end ; ++it ) + { + + // display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << "ext. poll surrogate candidate: " << **it << std::endl; + + sk = new NOMAD::Eval_Point; + sk->set ( signature->get_n() , _p.get_bb_nb_outputs() ); + sk->set_signature ( signature ); + sk->Point::operator = ( **it ); + + // add the new point to the list of trial points: + ev_control.add_eval_point ( sk , + display_degree , + _p.get_snap_to_bounds() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() ); + } + + // eval_list_of_points: + // -------------------- + success = NOMAD::UNSUCCESSFUL; + new_feas_inc = new_infeas_inc = NULL; + + ev_control.eval_list_of_points ( NOMAD::EXTENDED_POLL , + true_barrier , + sgte_barrier , + pareto_front , + stop , + stop_reason , + new_feas_inc , + new_infeas_inc , + success ); + + // number of search points (0 or 1 or 2): + nb_ext_poll_pts += static_cast<int> ( candidates.size() ); + } + } + } + + // true evaluations (or surrogate evaluations if opt_only_sgte==true): + else + { + + const NOMAD::Barrier & active_barrier = mads.get_active_barrier(); + + // for the update of new_feas_inc and new_infeas_inc (1/2): + const NOMAD::Eval_Point * old_feasible_incumbent + = active_barrier.get_best_feasible(); + const NOMAD::Eval_Point * old_infeasible_incumbent + = active_barrier.get_best_infeasible(); + + // update barriers and process extended poll points: + NOMAD::success_type sgte_succ + = ev_control.process_barrier_points ( sgte_barrier , + EP_mads.get_sgte_barrier() , + pareto_front , + display_degree , + NOMAD::EXTENDED_POLL ); + + NOMAD::success_type true_succ + = ev_control.process_barrier_points ( true_barrier , + EP_mads.get_true_barrier() , + pareto_front , + display_degree , + NOMAD::EXTENDED_POLL ); + + // update of new_feas_inc and new_infeas_inc (2/2): + const NOMAD::Eval_Point * bf = active_barrier.get_best_feasible (); + const NOMAD::Eval_Point * bi = active_barrier.get_best_infeasible(); + if ( bf && bf != old_feasible_incumbent ) + new_feas_inc = bf; + if ( bi && bi != old_infeasible_incumbent ) + new_infeas_inc = bi; + + // number of extended poll points and success: + if ( opt_only_sgte ) + { + nb_ext_poll_pts += EP_mads.get_stats().get_sgte_eval(); + success = sgte_succ; + } + else + { + nb_ext_poll_pts += EP_mads.get_stats().get_eval(); + success = true_succ; + } + } + + // final display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "end of " << NOMAD::EXTENDED_POLL << " descent (" << success << ")"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } } /*----------------------------------------------------------------*/ @@ -478,191 +513,191 @@ void NOMAD::Extended_Poll::set_descent_parameters const NOMAD::Stats & stats , NOMAD::Parameters & descent_p ) const { - - // extended poll center signature - // (will be the temporary standard signature): - NOMAD::Signature * epc_signature = y->get_signature(); - if ( !epc_signature ) - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , - "Extended_Poll::set_descent_parameters(): ext. poll center has no signature" ); - - // we set all the parameters: - descent_p.set_DIMENSION ( epc_signature->get_n() ); - descent_p.set_BB_INPUT_TYPE ( epc_signature->get_input_types() ); - descent_p.set_LOWER_BOUND ( epc_signature->get_lb() ); - descent_p.set_UPPER_BOUND ( epc_signature->get_ub() ); - descent_p.set_FIXED_VARIABLE ( epc_signature->get_fixed_variables() ); - descent_p.set_PERIODIC_VARIABLE ( epc_signature->get_periodic_variables() ); - descent_p.set_VARIABLE_GROUP ( epc_signature->get_var_groups() ); - descent_p.set_BB_OUTPUT_TYPE ( _p.get_bb_output_type() ); - descent_p.set_DIRECTION_TYPE ( _p.get_direction_types() ); - - - { - const std::list<std::string> & bb_exe = _p.get_bb_exe(); - descent_p.set_BB_EXE ( bb_exe ); - std::list<std::string>::const_iterator it , end = bb_exe.end(); - for ( it = bb_exe.begin() ; it != end ; ++it ) - descent_p.set_SGTE_EXE ( *it , _p.get_sgte_exe ( *it ) ); - } - - descent_p.set_PROBLEM_DIR ( _p.get_problem_dir() ); - descent_p.set_TMP_DIR ( _p.get_tmp_dir() ); - descent_p.set_SGTE_COST ( _p.get_sgte_cost() ); - descent_p.set_SGTE_EVAL_SORT ( _p.get_sgte_eval_sort() ); - descent_p.set_X0 ( *y ); - - bool has_sgte = _p.has_sgte(); - if ( has_sgte ) - { - descent_p.reset_f_target(); - descent_p.set_HAS_SGTE ( true ); - descent_p.set_OPT_ONLY_SGTE ( true ); - descent_p.set_STOP_IF_FEASIBLE ( false ); - descent_p.set_MODEL_SEARCH ( false ); - descent_p.set_MODEL_EVAL_SORT ( NOMAD::NO_MODEL ); - } - else - { - descent_p.set_F_TARGET ( _p.get_f_target() ); - descent_p.set_STOP_IF_FEASIBLE ( _p.get_stop_if_feasible() ); - descent_p.set_MODEL_EVAL_SORT ( _p.get_model_eval_sort()); - descent_p.set_MODEL_SEARCH (_p.has_model_search()); - } - - descent_p.set_DIRECTION_TYPE ( _p.get_direction_types() ); - descent_p.set_SEC_POLL_DIR_TYPE ( _p.get_sec_poll_dir_types() ); - descent_p.set_HALTON_SEED ( _p.get_halton_seed() ); - descent_p.set_SEED ( _p.get_seed() ); - - descent_p.set_LH_SEARCH ( 0 , 0 ); - - int bbe = stats.get_bb_eval(); - int sgte_eval = stats.get_sgte_eval(); - - { - int p_max_bbe = _p.get_max_bb_eval(); - if ( p_max_bbe > 0 ) - descent_p.set_MAX_BB_EVAL ( p_max_bbe - bbe ); - - int p_max_sgte_eval = _p.get_max_sgte_eval(); - if ( p_max_sgte_eval > 0 ) - descent_p.set_MAX_SGTE_EVAL ( p_max_sgte_eval - sgte_eval ); - - int p_max_eval = _p.get_max_eval(); - if ( p_max_eval > 0 ) - descent_p.set_MAX_EVAL ( p_max_eval - stats.get_eval() ); - - int p_max_sbe = _p.get_max_sim_bb_eval(); - if ( p_max_sbe > 0 ) - descent_p.set_MAX_SIM_BB_EVAL ( p_max_sbe - stats.get_sim_bb_eval() ); - - int p_max_time = _p.get_max_time(); - if ( p_max_time > 0 ) - descent_p.set_MAX_TIME ( p_max_time - stats.get_real_time() ); - - NOMAD::Double p_sst = _p.get_stat_sum_target(); - if ( p_sst.is_defined() ) - descent_p.set_STAT_SUM_TARGET ( p_sst - stats.get_stat_sum() ); - } - - descent_p.set_OPPORTUNISTIC_EVAL ( _p.get_opportunistic_eval() ); - descent_p.set_BB_INPUT_INCLUDE_SEED ( _p.get_bb_input_include_seed() ); - descent_p.set_BB_INPUT_INCLUDE_TAG ( _p.get_bb_input_include_tag() ); - descent_p.set_BB_REDIRECTION ( _p.get_bb_redirection() ); - - descent_p.set_EXTENDED_POLL_ENABLED ( false ); - descent_p.set_USER_CALLS_ENABLED ( false ); - - descent_p.set_H_MAX_0 ( _p.get_h_max_0() ); - descent_p.set_H_MIN ( _p.get_h_min() ); - descent_p.set_H_NORM ( _p.get_h_norm() ); - descent_p.set_RHO ( _p.get_rho() ); - descent_p.set_SNAP_TO_BOUNDS ( _p.get_snap_to_bounds() ); - descent_p.set_MAX_CACHE_MEMORY ( _p.get_max_cache_memory() ); - descent_p.set_SPECULATIVE_SEARCH ( _p.get_speculative_search() ); - descent_p.set_OPPORTUNISTIC_LUCKY_EVAL ( _p.get_opportunistic_lucky_eval() ); - descent_p.set_OPPORTUNISTIC_MIN_EVAL ( _p.get_opportunistic_min_eval() ); - descent_p.set_OPPORTUNISTIC_MIN_F_IMPRVMT ( _p.get_opportunistic_min_f_imprvmt() ); - descent_p.set_OPPORTUNISTIC_MIN_NB_SUCCESS ( _p.get_opportunistic_min_nb_success() ); - - descent_p.set_CACHE_FILE ( _p.get_cache_file() ); - descent_p.set_SGTE_CACHE_FILE ( _p.get_sgte_cache_file() ); - descent_p.set_CACHE_SAVE_PERIOD ( _p.get_cache_save_period() ); - - descent_p.set_ADD_SEED_TO_FILE_NAMES ( _p.get_add_seed_to_file_names() ); - - descent_p.set_DISPLAY_ALL_EVAL(_p.get_display_all_eval()); - if ( _p.out().get_poll_dd() == NOMAD::FULL_DISPLAY ) - descent_p.set_DISPLAY_DEGREE ( NOMAD::NORMAL_DISPLAY ); - else if (_p.out().get_poll_dd() == NOMAD::NORMAL_DISPLAY ) - descent_p.set_DISPLAY_DEGREE ( NOMAD::MINIMAL_DISPLAY ); - else - descent_p.set_DISPLAY_DEGREE ( _p.out().get_poll_dd()); - - if ( has_sgte ) - descent_p.set_DISPLAY_STATS ( NOMAD::itos(sgte_eval) + "+SGTE OBJ (ExtendedPoll---surrogate)" ); - else - { - std::list<std::string> ds = _p.get_display_stats(); - std::list<std::string>::iterator it = ds.begin(); - std::list<std::string>::const_iterator end = ds.end(); - std::string s_bbe = NOMAD::itos(bbe) + "+"; - while ( it != end ) - { - if (*it == "BBE") - ds.insert ( it , s_bbe ); - ++it; - } - ds.push_back ( " (ExtendedPoll)" ); - descent_p.set_DISPLAY_STATS ( ds ); - } - - // STATS_FILE: - if ( has_sgte ) - descent_p.set_STATS_FILE ( _p.get_stats_file_name() , NOMAD::itos(sgte_eval) + "+SGTE OBJ (ExtendedPoll---surrogate)" ); - else - { - std::list<std::string> sf = _p.get_stats_file(); - std::list<std::string>::iterator it = sf.begin(); - std::list<std::string>::const_iterator end = sf.end(); - std::string s_bbe = NOMAD::itos(bbe) + "+"; - while ( it != end ) - { - if ( *it == "BBE" ) - sf.insert ( it , s_bbe ); - ++it; - } - sf.push_back ( " (ExtendedPoll)" ); - descent_p.set_STATS_FILE ( _p.get_stats_file_name() , sf ); - } - - // Mesh: - { - const Mesh & mesh = epc_signature->get_mesh(); - descent_p.set_MIN_MESH_SIZE ( mesh.get_min_mesh_size() ); - descent_p.set_MIN_POLL_SIZE ( mesh.get_min_poll_size() ); - int ell = NOMAD::Mesh::get_mesh_index(); - descent_p.set_INITIAL_MESH_INDEX ( ell ); - descent_p.set_MAX_MESH_INDEX ( ell ); - descent_p.set_INITIAL_MESH_SIZE ( mesh.get_initial_mesh_size() , false ); - - - } - - // check the parameters: - try - { - descent_p.check ( false , // remove_history_file = false - false , // remove_solution_file = false - false ); // remove_stats_file = false - } - catch ( NOMAD::Exception & e ) - { - std::ostringstream err; - err << "-- " << e.what(); - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err.str() ); - } + + // extended poll center signature + // (will be the temporary standard signature): + NOMAD::Signature * epc_signature = y->get_signature(); + if ( !epc_signature ) + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , + "Extended_Poll::set_descent_parameters(): ext. poll center has no signature" ); + + // we set all the parameters: + descent_p.set_DIMENSION ( epc_signature->get_n() ); + descent_p.set_BB_INPUT_TYPE ( epc_signature->get_input_types() ); + descent_p.set_LOWER_BOUND ( epc_signature->get_lb() ); + descent_p.set_UPPER_BOUND ( epc_signature->get_ub() ); + descent_p.set_FIXED_VARIABLE ( epc_signature->get_fixed_variables() ); + descent_p.set_PERIODIC_VARIABLE ( epc_signature->get_periodic_variables() ); + descent_p.set_VARIABLE_GROUP ( epc_signature->get_var_groups() ); + descent_p.set_BB_OUTPUT_TYPE ( _p.get_bb_output_type() ); + descent_p.set_DIRECTION_TYPE ( _p.get_direction_types() ); + descent_p.set_SEC_POLL_DIR_TYPE ( _p.get_sec_poll_dir_types() ); + + + { + const std::list<std::string> & bb_exe = _p.get_bb_exe(); + descent_p.set_BB_EXE ( bb_exe ); + std::list<std::string>::const_iterator it , end = bb_exe.end(); + for ( it = bb_exe.begin() ; it != end ; ++it ) + descent_p.set_SGTE_EXE ( *it , _p.get_sgte_exe ( *it ) ); + } + + descent_p.set_PROBLEM_DIR ( _p.get_problem_dir() ); + descent_p.set_TMP_DIR ( _p.get_tmp_dir() ); + descent_p.set_SGTE_COST ( _p.get_sgte_cost() ); + descent_p.set_SGTE_EVAL_SORT ( _p.get_sgte_eval_sort() ); + descent_p.set_X0 ( *y ); + + bool has_sgte = _p.has_sgte(); + if ( has_sgte ) + { + descent_p.reset_f_target(); + descent_p.set_HAS_SGTE ( true ); + descent_p.set_OPT_ONLY_SGTE ( true ); + descent_p.set_STOP_IF_FEASIBLE ( false ); + descent_p.set_MODEL_SEARCH ( false ); + descent_p.set_MODEL_EVAL_SORT ( NOMAD::NO_MODEL ); + } + else + { + descent_p.set_F_TARGET ( _p.get_f_target() ); + descent_p.set_STOP_IF_FEASIBLE ( _p.get_stop_if_feasible() ); + descent_p.set_MODEL_EVAL_SORT ( _p.get_model_eval_sort()); + descent_p.set_MODEL_SEARCH (_p.has_model_search()); + + + } + + descent_p.set_LH_SEARCH ( 0 , 0 ); + + int bbe = stats.get_bb_eval(); + int sgte_eval = stats.get_sgte_eval(); + + { + int p_max_bbe = _p.get_max_bb_eval(); + if ( p_max_bbe > 0 ) + descent_p.set_MAX_BB_EVAL ( p_max_bbe - bbe ); + + int p_max_sgte_eval = _p.get_max_sgte_eval(); + if ( p_max_sgte_eval > 0 ) + descent_p.set_MAX_SGTE_EVAL ( p_max_sgte_eval - sgte_eval ); + + int p_max_eval = _p.get_max_eval(); + if ( p_max_eval > 0 ) + descent_p.set_MAX_EVAL ( p_max_eval - stats.get_eval() ); + + int p_max_sbe = _p.get_max_sim_bb_eval(); + if ( p_max_sbe > 0 ) + descent_p.set_MAX_SIM_BB_EVAL ( p_max_sbe - stats.get_sim_bb_eval() ); + + int p_max_time = _p.get_max_time(); + if ( p_max_time > 0 ) + descent_p.set_MAX_TIME ( p_max_time - stats.get_real_time() ); + + NOMAD::Double p_sst = _p.get_stat_sum_target(); + if ( p_sst.is_defined() ) + descent_p.set_STAT_SUM_TARGET ( p_sst - stats.get_stat_sum() ); + } + + descent_p.set_OPPORTUNISTIC_EVAL ( _p.get_opportunistic_eval() ); + descent_p.set_BB_INPUT_INCLUDE_SEED ( _p.get_bb_input_include_seed() ); + descent_p.set_BB_INPUT_INCLUDE_TAG ( _p.get_bb_input_include_tag() ); + descent_p.set_BB_REDIRECTION ( _p.get_bb_redirection() ); + + descent_p.set_EXTENDED_POLL_ENABLED ( false ); + descent_p.set_USER_CALLS_ENABLED ( false ); + + descent_p.set_H_MAX_0 ( _p.get_h_max_0() ); + descent_p.set_H_MIN ( _p.get_h_min() ); + descent_p.set_H_NORM ( _p.get_h_norm() ); + descent_p.set_RHO ( _p.get_rho() ); + descent_p.set_SNAP_TO_BOUNDS ( _p.get_snap_to_bounds() ); + descent_p.set_MAX_CACHE_MEMORY ( _p.get_max_cache_memory() ); + descent_p.set_SPECULATIVE_SEARCH ( _p.get_speculative_search() ); + descent_p.set_OPPORTUNISTIC_LUCKY_EVAL ( _p.get_opportunistic_lucky_eval() ); + descent_p.set_OPPORTUNISTIC_MIN_EVAL ( _p.get_opportunistic_min_eval() ); + descent_p.set_OPPORTUNISTIC_MIN_F_IMPRVMT ( _p.get_opportunistic_min_f_imprvmt() ); + descent_p.set_OPPORTUNISTIC_MIN_NB_SUCCESS ( _p.get_opportunistic_min_nb_success() ); + + if (_p.eval_points_as_block()) + descent_p.set_BB_MAX_BLOCK_SIZE( _p.get_bb_max_block_size() ); + + + descent_p.set_CACHE_FILE ( _p.get_cache_file() ); + descent_p.set_SGTE_CACHE_FILE ( _p.get_sgte_cache_file() ); + descent_p.set_CACHE_SAVE_PERIOD ( _p.get_cache_save_period() ); + + descent_p.set_ADD_SEED_TO_FILE_NAMES ( _p.get_add_seed_to_file_names() ); + + descent_p.set_DISPLAY_ALL_EVAL(_p.get_display_all_eval()); + if ( _p.out().get_poll_dd() == NOMAD::FULL_DISPLAY ) + descent_p.set_DISPLAY_DEGREE ( NOMAD::NORMAL_DISPLAY ); + else if (_p.out().get_poll_dd() == NOMAD::NORMAL_DISPLAY ) + descent_p.set_DISPLAY_DEGREE ( NOMAD::MINIMAL_DISPLAY ); + else + descent_p.set_DISPLAY_DEGREE ( _p.out().get_poll_dd()); + + // Stats style modified + if ( has_sgte ) + descent_p.set_DISPLAY_STATS ( NOMAD::itos(sgte_eval) + "+SGTE OBJ (ExtendedPoll---surrogate)" ); + else + { + std::list<std::string> ds = _p.get_display_stats(); + std::list<std::string>::iterator it = ds.begin(); + std::list<std::string>::const_iterator end = ds.end(); + std::string s_bbe = NOMAD::itos(bbe) + "+"; + while ( it != end ) + { + if (*it == "BBE") + ds.insert ( it , s_bbe ); + ++it; + } + ds.push_back ( " (ExtendedPoll)" ); + descent_p.set_DISPLAY_STATS ( ds ); + } + + // STATS_FILE: + if ( has_sgte ) + descent_p.set_STATS_FILE ( _p.get_stats_file_name() , NOMAD::itos(sgte_eval) + "+SGTE OBJ (ExtendedPoll---surrogate)" ); + else + { + std::list<std::string> sf = _p.get_stats_file(); + std::list<std::string>::iterator it = sf.begin(); + std::list<std::string>::const_iterator end = sf.end(); + std::string s_bbe = NOMAD::itos(bbe) + "+"; + while ( it != end ) + { + if ( *it == "BBE" ) + sf.insert ( it , s_bbe ); + ++it; + } + sf.push_back ( " (ExtendedPoll)" ); + descent_p.set_STATS_FILE ( _p.get_stats_file_name() , sf ); + } + + // Mesh: + { + const OrthogonalMesh * mesh = epc_signature->get_mesh(); + descent_p.set_MIN_MESH_SIZE ( mesh->get_min_mesh_size() ); + descent_p.set_MIN_POLL_SIZE ( mesh->get_min_poll_size() ); + descent_p.set_INITIAL_POLL_SIZE ( mesh->get_initial_poll_size() , false ); + + } + + // check the parameters: + try + { + descent_p.check ( false , // remove_history_file = false + false , // remove_solution_file = false + false ); // remove_stats_file = false + } + catch ( NOMAD::Exception & e ) + { + std::ostringstream err; + err << "-- " << e.what(); + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err.str() ); + } + } /*----------------------------------------------------------------*/ @@ -677,270 +712,270 @@ const NOMAD::Eval_Point * NOMAD::Extended_Poll::eval_epp const NOMAD::Eval_Point *& new_feas_inc , const NOMAD::Eval_Point *& new_infeas_inc ) const { - NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_poll_dd(); - - // initial display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - out << std::endl << NOMAD::open_block ( "extended poll point eval" ) << std::endl - << "extended poll point = ( "; - y->Point::display ( out , " " , 5 , _p.get_point_display_limit() ); - out << " )" << std::endl; - } - - // add the eval point to the evaluator control: - ev_control.add_eval_point ( y , - display_degree , - _p.get_snap_to_bounds() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() ); - - // get the stats: - NOMAD::Stats & stats = mads.get_stats(); - int old_bbe = stats.get_bb_eval(); - - // eval list of points: - new_feas_inc = new_infeas_inc = NULL; - std::list<const NOMAD::Eval_Point *> evaluated_pts; - - ev_control.eval_list_of_points ( NOMAD::EXTENDED_POLL , - mads.get_true_barrier() , - mads.get_sgte_barrier() , - mads.get_pareto_front() , - stop , - stop_reason , - new_feas_inc , - new_infeas_inc , - success , - &evaluated_pts ); - - // update the number of extended poll blackbox evaluations: - stats.add_ext_poll_bb_eval ( stats.get_bb_eval() - old_bbe ); - - // final display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::close_block() << std::endl; - - // return the evaluated point: - return ( evaluated_pts.size() != 1 ) ? NULL : *evaluated_pts.begin(); + NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_poll_dd(); + + // initial display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + out << std::endl << NOMAD::open_block ( "extended poll point eval" ) << std::endl + << "extended poll point = ( "; + y->Point::display ( out , " " , 5 , _p.get_point_display_limit() ); + out << " )" << std::endl; + } + + // add the eval point to the evaluator control: + ev_control.add_eval_point ( y , + display_degree , + _p.get_snap_to_bounds() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() ); + + // get the stats: + NOMAD::Stats & stats = mads.get_stats(); + int old_bbe = stats.get_bb_eval(); + + // eval list of points: + new_feas_inc = new_infeas_inc = NULL; + std::list<const NOMAD::Eval_Point *> evaluated_pts; + + ev_control.eval_list_of_points ( NOMAD::EXTENDED_POLL , + mads.get_true_barrier() , + mads.get_sgte_barrier() , + mads.get_pareto_front() , + stop , + stop_reason , + new_feas_inc , + new_infeas_inc , + success , + &evaluated_pts ); + + // update the number of extended poll blackbox evaluations: + stats.add_ext_poll_bb_eval ( stats.get_bb_eval() - old_bbe ); + + // final display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << NOMAD::close_block() << std::endl; + + // return the evaluated point: + return ( evaluated_pts.size() != 1 ) ? NULL : *evaluated_pts.begin(); } /*-----------------------------------------*/ /* run the extended poll */ /*-----------------------------------------*/ void NOMAD::Extended_Poll::run ( Mads & mads , - int & nb_ext_poll_pts , - bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::success_type & success , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc ) + int & nb_ext_poll_pts , + bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::success_type & success , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc ) { - nb_ext_poll_pts = 0; - success = NOMAD::UNSUCCESSFUL; - new_feas_inc = new_infeas_inc = NULL; - - if ( stop || _extended_points.empty() ) - return; - - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_poll_dd(); - NOMAD::Eval_Point * cur; - - // phase 1: evaluate the extended poll points in order to sort them - // -------- (based on the surrogates or on the true function): - if ( _extended_points.size() > 1 ) - { - - bool has_sgte = _p.has_sgte(); - bool old_sgte_eval_sort = _p.get_sgte_eval_sort(); - - // phase 1 initial display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - std::ostringstream oss; - oss << "extended poll pts sorting"; - if ( has_sgte ) - oss << " (on surrogates)"; - out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; - } - - if ( has_sgte ) { - _p.set_SGTE_EVAL_SORT ( false ); // this ensures that only surrogate - _p.force_check_flag(); // evaluations are performed - } - - NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); - - // loop on the extended poll points: - std::list<NOMAD::Eval_Point *>::const_iterator end = _extended_points.end(); - for ( std::list<NOMAD::Eval_Point *>::iterator it = _extended_points.begin() ; - it != end ; ++it ) - { - cur = *it; - - if ( has_sgte ) - cur->set_eval_type ( NOMAD::SGTE ); - - ev_control.add_eval_point ( cur , - display_degree , - _p.get_snap_to_bounds() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() ); - } - - _extended_points.clear(); - - // get the stats: - NOMAD::Stats & stats = mads.get_stats(); - int old_bbe = stats.get_bb_eval(); - - // number of eval points: - nb_ext_poll_pts = ev_control.get_nb_eval_points(); - - // eval list of points: - new_feas_inc = new_infeas_inc = NULL; - std::list<const NOMAD::Eval_Point *> evaluated_pts; - - ev_control.eval_list_of_points ( NOMAD::EXTENDED_POLL , - mads.get_true_barrier() , - mads.get_sgte_barrier() , - mads.get_pareto_front() , - stop , - stop_reason , - new_feas_inc , - new_infeas_inc , - success , - &evaluated_pts ); - if ( has_sgte ) - { - if ( !_p.get_opt_only_sgte() ) { - success = NOMAD::UNSUCCESSFUL; - new_feas_inc = new_infeas_inc = NULL; - } - _p.set_SGTE_EVAL_SORT ( old_sgte_eval_sort ); - _p.force_check_flag(); - } - - // update the number of extended poll blackbox evaluations: - stats.add_ext_poll_bb_eval ( stats.get_bb_eval() - old_bbe ); - - // sort the evaluated extended poll points: - if ( success != NOMAD::FULL_SUCCESS ) - sort_epp ( evaluated_pts ); - - // the extended poll is terminated in case of success: - if ( stop || success == NOMAD::FULL_SUCCESS || new_feas_inc || new_infeas_inc ) - { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl - << NOMAD::close_block ( "end of ext poll pts sorting (success)" ) - << std::endl; - return; - } - - // phase 1 final display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - std::ostringstream oss; - oss << "end of ext poll pts sorting"; - if ( has_sgte ) - oss << " (on surrogates)"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } - - } // end of phase 1 + nb_ext_poll_pts = 0; + success = NOMAD::UNSUCCESSFUL; + new_feas_inc = new_infeas_inc = NULL; + + if ( stop || _extended_points.empty() ) + return; + + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_poll_dd(); + NOMAD::Eval_Point * cur; + + // phase 1: evaluate the extended poll points in order to sort them + // -------- (based on the surrogates or on the true function): + if ( _extended_points.size() > 1 ) + { + + bool has_sgte = _p.has_sgte(); + bool old_sgte_eval_sort = _p.get_sgte_eval_sort(); + + // phase 1 initial display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "extended poll pts sorting"; + if ( has_sgte ) + oss << " (on surrogates)"; + out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; + } + + if ( has_sgte ) { + _p.set_SGTE_EVAL_SORT ( false ); // this ensures that only surrogate + _p.force_check_flag(); // evaluations are performed + } + + NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); + + // loop on the extended poll points: + std::list<NOMAD::Eval_Point *>::const_iterator end = _extended_points.end(); + for ( std::list<NOMAD::Eval_Point *>::iterator it = _extended_points.begin() ; + it != end ; ++it ) + { + cur = *it; + + if ( has_sgte ) + cur->set_eval_type ( NOMAD::SGTE ); + + ev_control.add_eval_point ( cur , + display_degree , + _p.get_snap_to_bounds() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() ); + } + + _extended_points.clear(); + + // get the stats: + NOMAD::Stats & stats = mads.get_stats(); + int old_bbe = stats.get_bb_eval(); + + // number of eval points: + nb_ext_poll_pts = ev_control.get_nb_eval_points(); + + // eval list of points: + new_feas_inc = new_infeas_inc = NULL; + std::list<const NOMAD::Eval_Point *> evaluated_pts; + + ev_control.eval_list_of_points ( NOMAD::EXTENDED_POLL , + mads.get_true_barrier() , + mads.get_sgte_barrier() , + mads.get_pareto_front() , + stop , + stop_reason , + new_feas_inc , + new_infeas_inc , + success , + &evaluated_pts ); + if ( has_sgte ) + { + if ( !_p.get_opt_only_sgte() ) { + success = NOMAD::UNSUCCESSFUL; + new_feas_inc = new_infeas_inc = NULL; + } + _p.set_SGTE_EVAL_SORT ( old_sgte_eval_sort ); + _p.force_check_flag(); + } + + // update the number of extended poll blackbox evaluations: + stats.add_ext_poll_bb_eval ( stats.get_bb_eval() - old_bbe ); + + // sort the evaluated extended poll points: + if ( success != NOMAD::FULL_SUCCESS ) + sort_epp ( evaluated_pts ); + + // the extended poll is terminated in case of success: + if ( stop || success == NOMAD::FULL_SUCCESS || new_feas_inc || new_infeas_inc ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl + << NOMAD::close_block ( "end of ext poll pts sorting (success)" ) + << std::endl; + return; + } + + // phase 1 final display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "end of ext poll pts sorting"; + if ( has_sgte ) + oss << " (on surrogates)"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } + + } // end of phase 1 + // -------------- + + /*--------------------------------------------------------------*/ + + // phase 2: execute the extended poll for each extended point: + // -------- + { + const NOMAD::Eval_Point * old_bf = mads.get_best_feasible(); + const NOMAD::Eval_Point * old_bi = mads.get_best_infeasible(); + const NOMAD::Eval_Point * y; + + while ( !_extended_points.empty() ) + { + + cur = *_extended_points.begin(); + + // the point has already been evaluated during + // the extended poll points sorting: + if ( cur->is_in_cache() && cur->get_eval_type() == NOMAD::TRUTH ) + y = cur; + + // the point has to be evaluated: + else + { + + y = eval_epp ( cur , + mads , + stop , + stop_reason , + success , + new_feas_inc , + new_infeas_inc ); + + ++nb_ext_poll_pts; + + // the extended poll is terminated in case of success: + if ( !y || + stop || + success == NOMAD::FULL_SUCCESS || + new_feas_inc || + new_infeas_inc ) + break; + } + + _extended_points.pop_front(); + + // perform the extended poll descent ? + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + out << std::endl + << "extended poll center: ( "; + y->Point::display ( out , " " , 5 , _p.get_point_display_limit() ); + out << " )" << std::endl << std::endl + << "perform extended poll descent ..."; + } + if ( check_trigger ( old_bf , old_bi , y ) ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "... yes" << std::endl; + descent ( y , + mads , + nb_ext_poll_pts , + stop , + stop_reason , + success , + new_feas_inc , + new_infeas_inc ); + + // the extended poll is terminated in case of success: + if ( stop || success == NOMAD::FULL_SUCCESS || new_feas_inc || new_infeas_inc ) + break; + } + else if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "... no" << std::endl; + } + } // end of phase 2 // -------------- - - /*--------------------------------------------------------------*/ - - // phase 2: execute the extended poll for each extended point: - // -------- - { - const NOMAD::Eval_Point * old_bf = mads.get_best_feasible(); - const NOMAD::Eval_Point * old_bi = mads.get_best_infeasible(); - const NOMAD::Eval_Point * y; - - while ( !_extended_points.empty() ) - { - - cur = *_extended_points.begin(); - - // the point has already been evaluated during - // the extended poll points sorting: - if ( cur->is_in_cache() && cur->get_eval_type() == NOMAD::TRUTH ) - y = cur; - - // the point has to be evaluated: - else - { - - y = eval_epp ( cur , - mads , - stop , - stop_reason , - success , - new_feas_inc , - new_infeas_inc ); - - ++nb_ext_poll_pts; - - // the extended poll is terminated in case of success: - if ( !y || - stop || - success == NOMAD::FULL_SUCCESS || - new_feas_inc || - new_infeas_inc ) - break; - } - - _extended_points.pop_front(); - - // perform the extended poll descent ? - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - out << std::endl - << "extended poll center: ( "; - y->Point::display ( out , " " , 5 , _p.get_point_display_limit() ); - out << " )" << std::endl << std::endl - << "perform extended poll descent ..."; - } - if ( check_trigger ( old_bf , old_bi , y ) ) - { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "... yes" << std::endl; - descent ( y , - mads , - nb_ext_poll_pts , - stop , - stop_reason , - success , - new_feas_inc , - new_infeas_inc ); - - // the extended poll is terminated in case of success: - if ( stop || success == NOMAD::FULL_SUCCESS || new_feas_inc || new_infeas_inc ) - break; - } - else if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "... no" << std::endl; - } - } // end of phase 2 - // -------------- - - // clean the extended points that have not been considered: - std::list<NOMAD::Eval_Point *>::const_iterator end = _extended_points.end(); - for ( std::list<NOMAD::Eval_Point *>::iterator it = _extended_points.begin() ; - it != end ; ++it ) - if ( !(*it)->is_in_cache() ) - delete *it; - _extended_points.clear(); + + // clean the extended points that have not been considered: + std::list<NOMAD::Eval_Point *>::const_iterator end = _extended_points.end(); + for ( std::list<NOMAD::Eval_Point *>::iterator it = _extended_points.begin() ; + it != end ; ++it ) + if ( !(*it)->is_in_cache() ) + delete *it; + _extended_points.clear(); } /*----------------------------------------------------------------*/ @@ -950,71 +985,70 @@ void NOMAD::Extended_Poll::run ( Mads & mads , void NOMAD::Extended_Poll::sort_epp ( const std::list<const NOMAD::Eval_Point *> & evaluated_pts ) { - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_poll_dd(); - const NOMAD::Double & h_min = _p.get_h_min(); - std::set<NOMAD::Priority_Eval_Point> sorted_pts; - - // 1. loop on the evaluated points: - std::list<const NOMAD::Eval_Point *>::const_iterator it1 , end1 = evaluated_pts.end(); - for ( it1 = evaluated_pts.begin() ; it1 != end1 ; ++it1 ) - { - - // creation of a Priority_Eval_Point: - NOMAD::Priority_Eval_Point pep ( *it1 , h_min ); - - // surrogate values for f and h: - if ( (*it1)->get_eval_type() == NOMAD::SGTE ) - { - pep.set_f_sgte ( (*it1)->get_f() ); - pep.set_h_sgte ( (*it1)->get_h() ); - } - - // insertion in the sorted list of points: - sorted_pts.insert ( pep ); - } - - // 2. loop on the sorted points: - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::open_block ( "sorted ext poll pts" ) << std::endl; - - const NOMAD::Eval_Point * cur; - NOMAD::Eval_Point * y; - int i = 0 , nb_pts = static_cast<int> ( sorted_pts.size() ); - std::set<NOMAD::Priority_Eval_Point>::const_iterator + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_poll_dd(); + const NOMAD::Double & h_min = _p.get_h_min(); + std::set<NOMAD::Priority_Eval_Point> sorted_pts; + + // 1. loop on the evaluated points: + std::list<const NOMAD::Eval_Point *>::const_iterator it1 , end1 = evaluated_pts.end(); + for ( it1 = evaluated_pts.begin() ; it1 != end1 ; ++it1 ) + { + + // creation of a Priority_Eval_Point: + NOMAD::Priority_Eval_Point pep ( *it1 , h_min ); + + // surrogate values for f and h: + if ( (*it1)->get_eval_type() == NOMAD::SGTE ) + { + pep.set_f_sgte ( (*it1)->get_f() ); + pep.set_h_sgte ( (*it1)->get_h() ); + } + + // insertion in the sorted list of points: + sorted_pts.insert ( pep ); + } + + // 2. loop on the sorted points: + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << NOMAD::open_block ( "sorted ext poll pts" ) << std::endl; + + const NOMAD::Eval_Point * cur; + NOMAD::Eval_Point * y; + int i = 0 , nb_pts = static_cast<int> ( sorted_pts.size() ); + std::set<NOMAD::Priority_Eval_Point>::const_iterator it2 , end2 = sorted_pts.end(); - - for ( it2 = sorted_pts.begin() ; it2 != end2 ; ++it2 ) - { - - // we copy y=cur an create a new Eval_Point because cur can be a surrogate - // point already in the surrogate cache - - cur = (*it2).get_point(); - - y = new NOMAD::Eval_Point; - y->set ( cur->size() , _p.get_bb_nb_outputs() ); - y->set_signature ( cur->get_signature () ); - y->set_direction ( cur->get_direction () ); - y->set_mesh_index ( cur->get_mesh_index() ); - y->Point::operator = ( *cur ); - - // display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - out << "point #"; - out.display_int_w ( ++i , nb_pts ); - out << "/" << nb_pts << " : ( "; - y->Point::display ( out , " " , 5 , _p.get_point_display_limit() ); - out << " )" << std::endl; - } - - // insertion in _extended_points: - _extended_points.push_back ( y ); - } - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::close_block() << std::endl; + + for ( it2 = sorted_pts.begin() ; it2 != end2 ; ++it2 ) + { + + // we copy y=cur an create a new Eval_Point because cur can be a surrogate + // point already in the surrogate cache + + cur = (*it2).get_point(); + + y = new NOMAD::Eval_Point; + y->set ( cur->size() , _p.get_bb_nb_outputs() ); + y->set_signature ( cur->get_signature () ); + y->set_direction ( cur->get_direction () ); + y->Point::operator = ( *cur ); + + // display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + out << "point #"; + out.display_int_w ( ++i , nb_pts ); + out << "/" << nb_pts << " : ( "; + y->Point::display ( out , " " , 5 , _p.get_point_display_limit() ); + out << " )" << std::endl; + } + + // insertion in _extended_points: + _extended_points.push_back ( y ); + } + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << NOMAD::close_block() << std::endl; } /*--------------------------------------------------------------------*/ @@ -1022,67 +1056,67 @@ void NOMAD::Extended_Poll::sort_epp /*--------------------------------------------------------------------*/ bool NOMAD::Extended_Poll::set_neighbors_exe ( std::string & error_str ) { - error_str.clear(); - - _neighbors_exe = _p.get_neighbors_exe(); - - if ( _neighbors_exe.empty() ) { - error_str = "categorical variables: parameter NEIGHBORS_EXE is undefined"; - return false; - } - - const std::string problem_dir = _p.get_problem_dir(); - - std::list<std::string> neighbors_exe_words; - NOMAD::get_words ( _neighbors_exe , neighbors_exe_words ); - - // _neighbors_exe is composed of several words (it is a command): - if ( neighbors_exe_words.size() > 1 ) - { - - _neighbors_exe.clear(); - - std::list<std::string>::const_iterator it = neighbors_exe_words.begin() , - end = neighbors_exe_words.end(); - while (true) { - - if ( (*it)[0] != '$' ) { - _neighbors_exe += "\"" + problem_dir; - _neighbors_exe += *it + "\""; - } - else - _neighbors_exe += it->substr ( 1 , it->size()-1 ); - - ++it; - - if ( it == end ) - break; - - _neighbors_exe += " "; - } - } - - // _neighbors_exe is just composed of one name (it is an executable): - else - { - - if ( _neighbors_exe[0] != '$' ) - _neighbors_exe = problem_dir + _neighbors_exe; - else - _neighbors_exe = _neighbors_exe.substr ( 1 , _neighbors_exe.size()-1 ); - - if ( !NOMAD::check_exe_file ( _neighbors_exe ) ) - { - error_str = "categorical variables: \'" + _neighbors_exe - + "\' is not a valid executable file"; - return false; - } - - if ( _neighbors_exe[0] != '$' ) - _neighbors_exe = "\"" + _neighbors_exe + "\""; - } - - return true; + error_str.clear(); + + _neighbors_exe = _p.get_neighbors_exe(); + + if ( _neighbors_exe.empty() ) { + error_str = "categorical variables: parameter NEIGHBORS_EXE is undefined"; + return false; + } + + const std::string problem_dir = _p.get_problem_dir(); + + std::list<std::string> neighbors_exe_words; + NOMAD::get_words ( _neighbors_exe , neighbors_exe_words ); + + // _neighbors_exe is composed of several words (it is a command): + if ( neighbors_exe_words.size() > 1 ) + { + + _neighbors_exe.clear(); + + std::list<std::string>::const_iterator it = neighbors_exe_words.begin() , + end = neighbors_exe_words.end(); + while (true) { + + if ( (*it)[0] != '$' ) { + _neighbors_exe += "\"" + problem_dir; + _neighbors_exe += *it + "\""; + } + else + _neighbors_exe += it->substr ( 1 , it->size()-1 ); + + ++it; + + if ( it == end ) + break; + + _neighbors_exe += " "; + } + } + + // _neighbors_exe is just composed of one name (it is an executable): + else + { + + if ( _neighbors_exe[0] != '$' ) + _neighbors_exe = problem_dir + _neighbors_exe; + else + _neighbors_exe = _neighbors_exe.substr ( 1 , _neighbors_exe.size()-1 ); + + if ( !NOMAD::check_exe_file ( _neighbors_exe ) ) + { + error_str = "categorical variables: \'" + _neighbors_exe + + "\' is not a valid executable file"; + return false; + } + + if ( _neighbors_exe[0] != '$' ) + _neighbors_exe = "\"" + _neighbors_exe + "\""; + } + + return true; } /*----------------------------------------------------------------------*/ @@ -1092,130 +1126,130 @@ bool NOMAD::Extended_Poll::set_neighbors_exe ( std::string & error_str ) /*----------------------------------------------------------------------*/ void NOMAD::Extended_Poll::construct_extended_points ( const NOMAD::Eval_Point & xk ) { - if ( _neighbors_exe.empty() ) - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , - "NOMAD::Extended_Poll::construct_extended_points(): no NEIGHBORS_EXE executable (batch mode) or no subclass implementation of the method (library mode)" ); - - if ( !xk.is_complete() ) - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , - "NOMAD::Extended_Poll::construct_extended_points(): bad extended poll center"); - - NOMAD::Signature * signature = _p.get_signature(); - if ( !signature ) - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , - "NOMAD::Extended_Poll::construct_extended_points(): no signature" ); - - std::string tmp_dir = _p.get_tmp_dir(); - - std::ostringstream oss; - oss << "." << _p.get_seed() << "." << xk.get_tag() << ".neighbors."; - const std::string & sint = oss.str(); - - // input file writing: - // ------------------- - std::string input_file_name = + if ( _neighbors_exe.empty() ) + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , + "NOMAD::Extended_Poll::construct_extended_points(): no NEIGHBORS_EXE executable (batch mode) or no subclass implementation of the method (library mode)" ); + + if ( !xk.is_complete() ) + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , + "NOMAD::Extended_Poll::construct_extended_points(): bad extended poll center"); + + NOMAD::Signature * signature = _p.get_signature(); + if ( !signature ) + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , + "NOMAD::Extended_Poll::construct_extended_points(): no signature" ); + + std::string tmp_dir = _p.get_tmp_dir(); + + std::ostringstream oss; + oss << "." << _p.get_seed() << "." << xk.get_tag() << ".neighbors."; + const std::string & sint = oss.str(); + + // input file writing: + // ------------------- + std::string input_file_name = tmp_dir + NOMAD::BLACKBOX_INPUT_FILE_PREFIX + sint + NOMAD::BLACKBOX_INPUT_FILE_EXT; - - std::string output_file_name = + + std::string output_file_name = tmp_dir + NOMAD::BLACKBOX_OUTPUT_FILE_PREFIX + sint + NOMAD::BLACKBOX_OUTPUT_FILE_EXT; - - std::ofstream fout ( input_file_name.c_str() ); - if ( fout.fail() ) - { - remove ( input_file_name.c_str () ); - std::string err = "could not open file neighbors input file " + input_file_name; - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); - } - - fout.setf ( std::ios::fixed ); - fout.precision ( NOMAD::DISPLAY_PRECISION_BB ); - xk.Point::display ( fout , " " , -1 , -1 ); - fout << std::endl; - - fout.close(); - - if ( fout.fail() ) - { - remove ( input_file_name.c_str () ); - std::string err = "could not write file neighbors input file " + input_file_name; - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); - } - - // system call to get the neighbors: - // --------------------------------- - - std::string cmd = _neighbors_exe + " " + input_file_name + " > " + output_file_name; - + + std::ofstream fout ( input_file_name.c_str() ); + if ( fout.fail() ) + { + remove ( input_file_name.c_str () ); + std::string err = "could not open file neighbors input file " + input_file_name; + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); + } + + fout.setf ( std::ios::fixed ); + fout.precision ( NOMAD::DISPLAY_PRECISION_BB ); + xk.Point::display ( fout , " " , -1 , -1 ); + fout << std::endl; + + fout.close(); + + if ( fout.fail() ) + { + remove ( input_file_name.c_str () ); + std::string err = "could not write file neighbors input file " + input_file_name; + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); + } + + // system call to get the neighbors: + // --------------------------------- + + std::string cmd = _neighbors_exe + " " + input_file_name + " > " + output_file_name; + #ifdef DEBUG #ifdef USE_MPI - int rank; - MPI_Comm_rank ( MPI_COMM_WORLD, &rank); - _p.out() << "command(rank=" << rank - << ") = \'" << cmd << "\'" << std::endl; + int rank; + MPI_Comm_rank ( MPI_COMM_WORLD, &rank); + _p.out() << "command(rank=" << rank + << ") = \'" << cmd << "\'" << std::endl; #else - _p.out() << "command=\'" << cmd << "\'" << std::endl; + _p.out() << "command=\'" << cmd << "\'" << std::endl; #endif #endif - - // the call: - if ( ( system ( cmd.c_str() ) ) != 0 ) - { - remove ( input_file_name.c_str () ); - remove ( output_file_name.c_str() ); - std::string err = "error with command " + cmd; - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); - } - - // reading of the output file: - // --------------------------- - - std::ifstream fin ( output_file_name.c_str() ); - - if ( fin.fail() ) - { - remove ( input_file_name.c_str () ); - remove ( output_file_name.c_str() ); - std::string err = "could not open neighbors output file " + output_file_name; - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); - } - - int n = xk.size(); - - while ( true ) - { - NOMAD::Point y(n); - try - { - fin >> y; - } - catch ( NOMAD::Point::Bad_Input & ) - { - if ( y.is_defined() ) { - remove ( input_file_name.c_str () ); - remove ( output_file_name.c_str() ); - std::string err = "error with neighbor in file " + output_file_name; - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); - } - break; - } - - if ( !y.is_complete() ) - { - remove ( input_file_name.c_str () ); - remove ( output_file_name.c_str() ); - std::string err = "error with neighbor in file " + output_file_name; - throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); - } - - add_extended_poll_point ( y , *signature ); - } - - fin.close(); - - // delete the input and output files: - // ---------------------------------- - remove ( input_file_name.c_str () ); - remove ( output_file_name.c_str() ); + + // the call: + if ( ( system ( cmd.c_str() ) ) != 0 ) + { + remove ( input_file_name.c_str () ); + remove ( output_file_name.c_str() ); + std::string err = "error with command " + cmd; + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); + } + + // reading of the output file: + // --------------------------- + + std::ifstream fin ( output_file_name.c_str() ); + + if ( fin.fail() ) + { + remove ( input_file_name.c_str () ); + remove ( output_file_name.c_str() ); + std::string err = "could not open neighbors output file " + output_file_name; + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); + } + + int n = xk.size(); + + while ( true ) + { + NOMAD::Point y(n); + try + { + fin >> y; + } + catch ( NOMAD::Point::Bad_Input & ) + { + if ( y.is_defined() ) { + remove ( input_file_name.c_str () ); + remove ( output_file_name.c_str() ); + std::string err = "error with neighbor in file " + output_file_name; + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); + } + break; + } + + if ( !y.is_complete() ) + { + remove ( input_file_name.c_str () ); + remove ( output_file_name.c_str() ); + std::string err = "error with neighbor in file " + output_file_name; + throw NOMAD::Exception ( "Extended_Poll.cpp" , __LINE__ , err ); + } + + add_extended_poll_point ( y , *signature ); + } + + fin.close(); + + // delete the input and output files: + // ---------------------------------- + remove ( input_file_name.c_str () ); + remove ( output_file_name.c_str() ); } diff --git a/src/Extended_Poll.hpp b/src/Extended_Poll.hpp index 5f39f1e..55cdae4 100644 --- a/src/Extended_Poll.hpp +++ b/src/Extended_Poll.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Filter_Point.hpp b/src/Filter_Point.hpp index 81d9858..3e74cc4 100644 --- a/src/Filter_Point.hpp +++ b/src/Filter_Point.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/LH_Search.cpp b/src/LH_Search.cpp index d9ec06b..43d76d1 100644 --- a/src/LH_Search.cpp +++ b/src/LH_Search.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,221 +34,227 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file LH_Search.cpp - \brief Latin-Hypercube search (implementation) - \author Sebastien Le Digabel - \date 2010-04-09 - \see LH_Search.hpp -*/ + \file LH_Search.cpp + \brief Latin-Hypercube search (implementation) + \author Sebastien Le Digabel + \date 2010-04-09 + \see LH_Search.hpp + */ #include "LH_Search.hpp" /*-----------------------------------------------------------*/ /* MADS Latin-Hypercube (LH) search */ /*-----------------------------------------------------------*/ void NOMAD::LH_Search::search ( NOMAD::Mads & mads , - int & nb_search_pts , - bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::success_type & success , - bool & count_search , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc ) + int & nb_search_pts , + bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::success_type & success , + bool & count_search , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc ) { - new_feas_inc = new_infeas_inc = NULL; - nb_search_pts = 0; - success = NOMAD::UNSUCCESSFUL; - count_search = !stop; - - if ( stop ) - return; - - // initial display: - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_search_dd(); - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << NOMAD::LH_SEARCH; - out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; - } - - // active barrier: - const NOMAD::Barrier & barrier = mads.get_active_barrier(); - - // Evaluator_Control: - NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); - - // current incumbents: - const NOMAD::Eval_Point * feas_inc = barrier.get_best_feasible (); - const NOMAD::Eval_Point * infeas_inc = barrier.get_best_infeasible(); - - // get a reference point and a signature: - const NOMAD::Eval_Point * ref = (feas_inc) ? feas_inc : infeas_inc; - NOMAD::Signature * signature = _p.get_signature(); - - // check the number of points: - int p = _initial_search ? _p.get_LH_search_p0() : _p.get_LH_search_pi(); - if ( p <= 0 ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "end of LH " << ( _initial_search ? "initial " : "") - << "search (number of points <= 0)"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + new_feas_inc = new_infeas_inc = NULL; + nb_search_pts = 0; + success = NOMAD::UNSUCCESSFUL; + count_search = !stop; + + if ( stop ) + return; + + // initial display: + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_search_dd(); + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << NOMAD::LH_SEARCH; + out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; } - return; - } - - // no reference point is available (we consider the standard signature): - if ( !ref ) - { - - // it is not sufficient with categorical variables: - if ( signature->has_categorical() ) - { - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - std::ostringstream oss; - oss << "end of LH " << ( _initial_search ? "initial " : "") - << "search (no available reference point)"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } - return; + + // active barrier: + const NOMAD::Barrier & barrier = mads.get_active_barrier(); + + // Evaluator_Control: + NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); + + // current incumbents: + const NOMAD::Eval_Point * feas_inc = barrier.get_best_feasible (); + const NOMAD::Eval_Point * infeas_inc = barrier.get_best_infeasible(); + + // get a reference point and a signature: + const NOMAD::Eval_Point * ref = (feas_inc) ? feas_inc : infeas_inc; + NOMAD::Signature * signature = _p.get_signature(); + + // check the number of points: + int p = _initial_search ? _p.get_LH_search_p0() : _p.get_LH_search_pi(); + if ( p <= 0 ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "end of LH " << ( _initial_search ? "initial " : "") + << "search (number of points <= 0)"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } + return; } - } - else - signature = ref->get_signature(); - - // Change Display stats style - const std::list<std::string> old_ds = _p.get_display_stats(); - std::list<std::string> ds = old_ds; - ds.push_back ( " (LH)" ); - _p.set_DISPLAY_STATS ( ds ); - - // check the parameters: - _p.check ( false , // remove_history_file = false - false , // remove_solution_file = false - false ); // remove_stats_file = false - - int i; - NOMAD::Eval_Point * x; - int n = signature->get_n(); - int m = _p.get_bb_nb_outputs(); - int mesh_index = NOMAD::Mesh::get_mesh_index(); - int pm1 = p-1; - - // mesh sizes: - NOMAD::Point delta_m_max ( n ); - signature->get_mesh().get_delta_m ( delta_m_max , NOMAD::Mesh::get_min_mesh_index() ); - - NOMAD::Double delta_m_i; - NOMAD::Point delta_m; - if ( !_initial_search ) - signature->get_mesh().get_delta_m ( delta_m , mesh_index ); - - // fixed variables: - const NOMAD::Point & fixed_variables = signature->get_fixed_variables(); - - // bb input types: - const std::vector<NOMAD::bb_input_type> & bbit = signature->get_input_types(); - - // bounds: - const NOMAD::Point & lb = signature->get_lb(); - const NOMAD::Point & ub = signature->get_ub(); - - // pts contains n points of dimension p: each of these points contains - // p different values for each variable: - NOMAD::Point ** pts = new NOMAD::Point * [n]; - - // creation of p search points: - for ( int k = 0 ; k < p ; ++k ) { - - x = new NOMAD::Eval_Point ( n , m ); - x->set_signature ( signature ); - x->set_mesh_index ( &mesh_index ); - - for ( i = 0 ; i < n ; ++i ) { - - if ( k==0 ) { - if ( fixed_variables[i].is_defined() ) - pts[i] = new NOMAD::Point ( p , fixed_variables[i] ); - else if ( bbit[i] == NOMAD::CATEGORICAL ) { - pts[i] = new NOMAD::Point ( p , (*ref)[i] ); - } - else { - pts[i] = new NOMAD::Point ( p ); - - // for the initial mesh: delta_m is not used and there will - // be no projection on mesh: - if ( !_initial_search ) - delta_m_i = delta_m[i]; - - values_for_var_i ( p , - delta_m_i , - delta_m_max[i] , - bbit [i] , - lb [i] , - ub [i] , - *pts [i] ); - } - } - - (*x)[i] = (*pts[i])[k]; - - if ( k == pm1 ) - delete pts[i]; + + // no reference point is available (we consider the standard signature): + if ( !ref ) + { + + // it is not sufficient with categorical variables: + if ( signature->has_categorical() ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "end of LH " << ( _initial_search ? "initial " : "") + << "search (no available reference point)"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } + return; + } } + else + signature = ref->get_signature(); + + // Change Display stats style + const std::list<std::string> old_ds = _p.get_display_stats(); + std::list<std::string> ds = old_ds; + ds.push_back ( " (LH)" ); + _p.set_DISPLAY_STATS ( ds ); + + // check the parameters: + _p.check ( false , // remove_history_file = false + false , // remove_solution_file = false + false ); // remove_stats_file = false + + int i; + NOMAD::Eval_Point * x; + int n = signature->get_n(); + int m = _p.get_bb_nb_outputs(); + int pm1 = p-1; - if ( display_degree == NOMAD::FULL_DISPLAY ) { - out << "LH point #" << x->get_tag() - << ": ( "; - x->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; + // mesh sizes: + NOMAD::Point delta_max = signature->get_mesh()->get_delta_max (); + NOMAD::Double delta_i; + NOMAD::Point delta; + if ( !_initial_search ) + signature->get_mesh()->get_delta ( delta ); + + // fixed variables: + const NOMAD::Point & fixed_variables = signature->get_fixed_variables(); + + // bb input types: + const std::vector<NOMAD::bb_input_type> & bbit = signature->get_input_types(); + + // bounds: + const NOMAD::Point & lb = signature->get_lb(); + const NOMAD::Point & ub = signature->get_ub(); + + // pts contains n points of dimension p: each of these points contains + // p different values for each variable: + NOMAD::Point ** pts = new NOMAD::Point * [n]; + + // creation of p search points: + for ( int k = 0 ; k < p ; ++k ) + { + + x = new NOMAD::Eval_Point ( n , m ); + x->set_signature ( signature ); + + for ( i = 0 ; i < n ; ++i ) + { + + if ( k==0 ) + { + if ( fixed_variables[i].is_defined() ) + pts[i] = new NOMAD::Point ( p , fixed_variables[i] ); + else if ( bbit[i] == NOMAD::CATEGORICAL ) + { + pts[i] = new NOMAD::Point ( p , (*ref)[i] ); + } + else + { + pts[i] = new NOMAD::Point ( p ); + + // for the initial mesh: delta is not used and there will + // be no projection on mesh: + if ( !_initial_search ) + delta_i = delta[i]; + + values_for_var_i ( p , + delta_i , + delta_max[i] , + bbit [i] , + lb [i] , + ub [i] , + *pts [i] ); + } + } + + (*x)[i] = (*pts[i])[k]; + + if ( k == pm1 ) + delete pts[i]; + } + + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + out << "LH point #" << x->get_tag() + << ": ( "; + x->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + + // add the new point to the ordered list of search trial points: + ev_control.add_eval_point ( x , + display_degree , + false , // snap_to_bounds = false + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() ); } - - // add the new point to the ordered list of search trial points: - ev_control.add_eval_point ( x , - display_degree , - false , // snap_to_bounds = false - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() ); - } - - delete [] pts; - - nb_search_pts = ev_control.get_nb_eval_points(); - - // eval_list_of_points: - // -------------------- - new_feas_inc = new_infeas_inc = NULL; - ev_control.eval_list_of_points ( _type , - mads.get_true_barrier() , - mads.get_sgte_barrier() , - mads.get_pareto_front() , - stop , - stop_reason , - new_feas_inc , - new_infeas_inc , - success ); - - - _p.get_display_stats(); - - // restore stats style - _p.set_DISPLAY_STATS ( old_ds ); - _p.check ( false , // remove_history_file = false - false , // remove_solution_file = false - false ); // remove_stats_file = false - - - - // final displays: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "end of LH search (" << success << ")"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } - + + delete [] pts; + + nb_search_pts = ev_control.get_nb_eval_points(); + + // eval_list_of_points: + // -------------------- + new_feas_inc = new_infeas_inc = NULL; + ev_control.eval_list_of_points ( _type , + mads.get_true_barrier() , + mads.get_sgte_barrier() , + mads.get_pareto_front() , + stop , + stop_reason , + new_feas_inc , + new_infeas_inc , + success ); + + + _p.get_display_stats(); + + // restore stats style + _p.set_DISPLAY_STATS ( old_ds ); + _p.check ( false , // remove_history_file = false + false , // remove_solution_file = false + false ); // remove_stats_file = false + + + + // final displays: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "end of LH search (" << success << ")"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } + } /*-----------------------------------------------------------*/ @@ -259,67 +265,69 @@ void NOMAD::LH_Search::search ( NOMAD::Mads & mads , /* . private method */ /*-----------------------------------------------------------*/ void NOMAD::LH_Search::values_for_var_i ( int p , - const NOMAD::Double & delta_m , - const NOMAD::Double & delta_m_max , - const NOMAD::bb_input_type & bbit , - const NOMAD::Double & lb , - const NOMAD::Double & ub , - NOMAD::Point & x ) const + const NOMAD::Double & delta_m , + const NOMAD::Double & delta_m_max , + const NOMAD::bb_input_type & bbit , + const NOMAD::Double & lb , + const NOMAD::Double & ub , + NOMAD::Point & x ) const { - // categorical variables have already been treated as fixed variables: - if ( bbit == NOMAD::CATEGORICAL ) - return; - - int i; - NOMAD::Double v; - NOMAD::Random_Pickup rp (p); - bool rounding = ( bbit != NOMAD::CONTINUOUS ); - bool lb_def = lb.is_defined(); - bool ub_def = ub.is_defined(); - double w = ( ( lb_def && ub_def ) ? - ub.value()-lb.value() : 1.0 ) / p; - // main loop: - for ( i = 0 ; i < p ; ++i ) { - - // both bounds exist: - if ( lb_def && ub_def ) - v = lb + ( i + NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w; - - // one of the bounds does not exist: - else { - - // lb exists, and ub not: mapping [0;1] --> [lb;+INF[ - if ( lb_def ) - v = lb + 10 * delta_m_max * sqrt ( - log ( NOMAD::DEFAULT_EPSILON + - ( i + NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w ) ); - - // lb does not exist: - else { - - // ub exists, and lb not: mapping [0;1] --> ]-INF;ub] - if ( ub_def ) - v = ub - delta_m_max * 10 * - sqrt ( -log ( NOMAD::DEFAULT_EPSILON + - ( i +NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w ) ); - - // there are no bounds: mapping [0;1] --> ]-INF;+INF[ - else - v = (NOMAD::RNG::rand()%2 ? -1.0 : 1.0) * delta_m_max * 10 * - sqrt ( - log ( NOMAD::DEFAULT_EPSILON + - ( i + NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w ) ); - } + // categorical variables have already been treated as fixed variables: + if ( bbit == NOMAD::CATEGORICAL ) + return; + + int i; + NOMAD::Double v; + NOMAD::Random_Pickup rp (p); + bool rounding = ( bbit != NOMAD::CONTINUOUS ); + bool lb_def = lb.is_defined(); + bool ub_def = ub.is_defined(); + double w = ( ( lb_def && ub_def ) ? + ub.value()-lb.value() : 1.0 ) / p; + // main loop: + for ( i = 0 ; i < p ; ++i ) + { + + // both bounds exist: + if ( lb_def && ub_def ) + v = lb + ( i + NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w; + // one of the bounds does not exist: + else + { + + // lb exists, and ub not: mapping [0;1] --> [lb;+INF[ + if ( lb_def ) + v = lb + 10 * delta_m_max * sqrt ( - log ( NOMAD::DEFAULT_EPSILON + + ( i + NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w ) ); + + // lb does not exist: + else + { + + // ub exists, and lb not: mapping [0;1] --> ]-INF;ub] + if ( ub_def ) + v = ub - delta_m_max * 10 * + sqrt ( -log ( NOMAD::DEFAULT_EPSILON + + ( i +NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w ) ); + + // there are no bounds: mapping [0;1] --> ]-INF;+INF[ + else + v = (NOMAD::RNG::rand()%2 ? -1.0 : 1.0) * delta_m_max * 10 * + sqrt ( - log ( NOMAD::DEFAULT_EPSILON + + ( i + NOMAD::RNG::rand()/NOMAD::D_INT_MAX ) * w ) ); + } + } + + // rounding: + if ( rounding ) + v = v.round(); + + // projection to mesh (with ref=0): + v.project_to_mesh ( 0.0 , delta_m , lb , ub ); + + // affectation + permutation: + x[rp.pickup()] = v; } - - // rounding: - if ( rounding ) - v = v.round(); - - // projection to mesh (with ref=0): - v.project_to_mesh ( 0.0 , delta_m , lb , ub ); - - // affectation + permutation: - x[rp.pickup()] = v; - } } /*---------------------------------------------------------*/ @@ -328,43 +336,46 @@ void NOMAD::LH_Search::values_for_var_i ( int p /* (static) */ /*---------------------------------------------------------*/ bool NOMAD::LH_Search::LH_points ( int n , - int m , - int p , - const NOMAD::Point & lb , - const NOMAD::Point & ub , - std::vector<NOMAD::Eval_Point *> & pts ) { - if ( n <= 0 || - p <= 0 || - !lb.is_defined() || - !ub.is_defined() || - lb.size() != n || - ub.size() != n ) - return false; - - for ( size_t j = 0 ; j < pts.size() ; ++j ) - delete pts[j]; - pts.clear(); - - NOMAD::Eval_Point * x; - int i; - int pm1 = p-1; - NOMAD::Random_Pickup ** rps = new NOMAD::Random_Pickup *[n]; - - for ( int k = 0 ; k < p ; ++k ) { - x = new NOMAD::Eval_Point ( n , m ); - for ( i = 0 ; i < n ; ++i ) { - if ( k==0 ) - rps[i] = new NOMAD::Random_Pickup(p); - (*x)[i] = lb[i] + - (ub[i]-lb[i]) * - ( rps[i]->pickup() + NOMAD::RNG::rand()/(1.0+NOMAD::D_INT_MAX)) / p; - if ( k==pm1 ) - delete rps[i]; + int m , + int p , + const NOMAD::Point & lb , + const NOMAD::Point & ub , + std::vector<NOMAD::Eval_Point *> & pts ) +{ + if ( n <= 0 || + p <= 0 || + !lb.is_defined() || + !ub.is_defined() || + lb.size() != n || + ub.size() != n ) + return false; + + for ( size_t j = 0 ; j < pts.size() ; ++j ) + delete pts[j]; + pts.clear(); + + NOMAD::Eval_Point * x; + int i; + int pm1 = p-1; + NOMAD::Random_Pickup ** rps = new NOMAD::Random_Pickup *[n]; + + for ( int k = 0 ; k < p ; ++k ) + { + x = new NOMAD::Eval_Point ( n , m ); + for ( i = 0 ; i < n ; ++i ) + { + if ( k==0 ) + rps[i] = new NOMAD::Random_Pickup(p); + (*x)[i] = lb[i] + + (ub[i]-lb[i]) * + ( rps[i]->pickup() + NOMAD::RNG::rand()/(1.0+NOMAD::D_INT_MAX)) / p; + if ( k==pm1 ) + delete rps[i]; + } + pts.push_back(x); } - pts.push_back(x); - } - - delete [] rps; - - return true; + + delete [] rps; + + return true; } diff --git a/src/LH_Search.hpp b/src/LH_Search.hpp index c80ff2c..685141a 100644 --- a/src/LH_Search.hpp +++ b/src/LH_Search.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/L_Curve.cpp b/src/L_Curve.cpp index b712db1..0050f90 100644 --- a/src/L_Curve.cpp +++ b/src/L_Curve.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/L_Curve.hpp b/src/L_Curve.hpp index feac036..8330580 100644 --- a/src/L_Curve.hpp +++ b/src/L_Curve.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Mads.cpp b/src/Mads.cpp index 3788e3f..5232644 100644 --- a/src/Mads.cpp +++ b/src/Mads.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Mads.cpp - \brief MADS algorithm (implementation) - \author Sebastien Le Digabel - \date 2010-04-20 - \see Mads.hpp -*/ + \file Mads.cpp + \brief MADS algorithm (implementation) + \author Sebastien Le Digabel + \date 2010-04-20 + \see Mads.hpp + */ #include "Mads.hpp" /*-----------------------------------*/ @@ -51,17 +51,18 @@ bool NOMAD::Mads::_flag_reset_mesh = true; bool NOMAD::Mads::_flag_reset_barriers = true; bool NOMAD::Mads::_flag_p1_active = false; + /*---------------------------------------------------------*/ /* force quit (static, called by pressing ctrl-c) */ /*---------------------------------------------------------*/ void NOMAD::Mads::force_quit ( int signalValue ) { - NOMAD::Mads::_force_quit = true; - NOMAD::Evaluator_Control::force_quit(); - NOMAD::Evaluator::force_quit(); - + NOMAD::Mads::_force_quit = true; + NOMAD::Evaluator_Control::force_quit(); + NOMAD::Evaluator::force_quit(); + #ifdef USE_TGP - NOMAD::TGP_Output_Model::force_quit(); + NOMAD::TGP_Output_Model::force_quit(); #endif } @@ -69,14 +70,14 @@ void NOMAD::Mads::force_quit ( int signalValue ) /* access to the flags (static) */ /*---------------------------------------------------------*/ void NOMAD::Mads::get_flags ( bool & flag_check_bimads , - bool & flag_reset_mesh , - bool & flag_reset_barriers , - bool & flag_p1_active ) + bool & flag_reset_mesh , + bool & flag_reset_barriers , + bool & flag_p1_active ) { - flag_check_bimads = _flag_check_bimads; - flag_reset_mesh = _flag_reset_mesh; - flag_reset_barriers = _flag_reset_barriers; - flag_p1_active = _flag_p1_active; + flag_check_bimads = _flag_check_bimads; + flag_reset_mesh = _flag_reset_mesh; + flag_reset_barriers = _flag_reset_barriers; + flag_p1_active = _flag_p1_active; } /*---------------------------------------------------------*/ @@ -87,53 +88,53 @@ void NOMAD::Mads::get_flags ( bool & flag_check_bimads , /*---------------------------------------------------------*/ void NOMAD::Mads::init ( void ) { - - NOMAD::Mads::_force_quit = false; - - if ( !NOMAD::Slave::is_master() ) - return; - - // Mads::force_quit() will be called if ctrl-c is pressed: - signal ( SIGINT , NOMAD::Mads::force_quit ); + + NOMAD::Mads::_force_quit = false; + + if ( !NOMAD::Slave::is_master() ) + return; + + // Mads::force_quit() will be called if ctrl-c is pressed: + signal ( SIGINT , NOMAD::Mads::force_quit ); #ifndef WINDOWS - signal ( SIGPIPE , NOMAD::Mads::force_quit ); // (ctrl-c during a "| more") + signal ( SIGPIPE , NOMAD::Mads::force_quit ); // (ctrl-c during a "| more") #endif #ifdef USE_MPI - signal ( SIGTERM , NOMAD::Mads::force_quit ); + signal ( SIGTERM , NOMAD::Mads::force_quit ); #endif - - // random number generator seed initialization: - bool valid_seed=NOMAD::RNG::set_seed(_p.get_seed()); - if ( !valid_seed ) - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ ,"seed for random number generator not initialized properly!" ); - - // model searches initialization: + + // model searches initialization: if ( _p.has_model_search() ) { #ifdef USE_TGP - if ( _p.get_model_search(1) == NOMAD::TGP_MODEL ) - _model_search1 = new TGP_Model_Search ( _p ); + if ( _p.get_model_search(1) == NOMAD::TGP_MODEL ) + _model_search1 = new TGP_Model_Search ( _p ); #endif - if ( _p.get_model_search(1) == NOMAD::QUADRATIC_MODEL ) - _model_search1 = new Quad_Model_Search ( _p ); + if ( _p.get_model_search(1) == NOMAD::QUADRATIC_MODEL ) + _model_search1 = new Quad_Model_Search ( _p ); #ifdef USE_TGP - if ( _p.get_model_search(2) == NOMAD::TGP_MODEL ) - _model_search2 = new TGP_Model_Search ( _p ); + if ( _p.get_model_search(2) == NOMAD::TGP_MODEL ) + _model_search2 = new TGP_Model_Search ( _p ); #endif - if ( _p.get_model_search(2) == NOMAD::QUADRATIC_MODEL ) - _model_search2 = new Quad_Model_Search ( _p ); - } - + if ( _p.get_model_search(2) == NOMAD::QUADRATIC_MODEL ) + _model_search2 = new Quad_Model_Search ( _p ); + } + #ifdef USE_TGP - _ev_control.set_last_TGP_model ( NULL ); + _ev_control.set_last_TGP_model ( NULL ); #endif - - // VNS search initialization: - if ( _p.get_VNS_search() ) - _VNS_search = new VNS_Search ( _p ); - - // cache search initialization: - if ( _p.get_cache_search() ) - _cache_search = new Cache_Search ( _p ); + + // VNS search initialization: + if ( _p.get_VNS_search() ) + _VNS_search = new VNS_Search ( _p ); + + // cache search initialization: + if ( _p.get_cache_search() ) + _cache_search = new Cache_Search ( _p ); + + // Orthogonal mesh initialization + _mesh->reset(); + + } /*---------------------------------------------------------*/ @@ -141,634 +142,133 @@ void NOMAD::Mads::init ( void ) /*---------------------------------------------------------*/ NOMAD::Mads::~Mads ( void ) { - delete _pareto_front; - delete _model_search1; - delete _model_search2; - delete _VNS_search; - delete _cache_search; - delete _L_curve; - - if ( _extended_poll && !_user_ext_poll) - delete _extended_poll; + delete _pareto_front; + delete _model_search1; + delete _model_search2; + delete _VNS_search; + delete _cache_search; + delete _L_curve; + + if ( _extended_poll && !_user_ext_poll) + delete _extended_poll; } -/*---------------------------------------------------------*/ -/* reset */ -/*---------------------------------------------------------*/ -/* default values for parameters: keep_barriers = false */ -/* keep_stats = false */ -/*---------------------------------------------------------*/ +/*-------------------------------------------------------------*/ +/* reset */ +/*-------------------------------------------------------------*/ +/* default values for parameters: keep_barriers = false */ +/* keep_stats = false */ +/*-------------------------------------------------------------*/ void NOMAD::Mads::reset ( bool keep_barriers , bool keep_stats ) { - // evaluator control: + // evaluator control: #ifdef USE_TGP - _ev_control.set_last_TGP_model ( NULL ); + _ev_control.set_last_TGP_model ( NULL ); #endif - - // user search: - _user_search = NULL; - - // model search #1: - if ( _p.get_model_search(1) != NOMAD::NO_MODEL ) { - if ( _model_search1 ) - _model_search1->reset(); - else { - if ( _p.get_model_search(1) == NOMAD::TGP_MODEL ) { + + // user search: + _user_search = NULL; + + // model search #1: + if ( _p.get_model_search(1) != NOMAD::NO_MODEL ) + { + if ( _model_search1 ) + _model_search1->reset(); + else { + if ( _p.get_model_search(1) == NOMAD::TGP_MODEL ) + { #ifdef USE_TGP - _model_search1 = new TGP_Model_Search ( _p ) ; + _model_search1 = new TGP_Model_Search ( _p ) ; #endif - } - else - _model_search1 = new Quad_Model_Search ( _p ); - } - } - else { - delete _model_search1; - _model_search1 = NULL; - } - - // model search #2: - if ( _p.get_model_search(2) != NOMAD::NO_MODEL ) { - if ( _model_search2 ) - _model_search2->reset(); - else { - if ( _p.get_model_search(2) == NOMAD::TGP_MODEL ) { + } + else + _model_search1 = new Quad_Model_Search ( _p ); + } + } + else + { + delete _model_search1; + _model_search1 = NULL; + } + + // model search #2: + if ( _p.get_model_search(2) != NOMAD::NO_MODEL ) + { + if ( _model_search2 ) + _model_search2->reset(); + else + { + if ( _p.get_model_search(2) == NOMAD::TGP_MODEL ) + { #ifdef USE_TGP - _model_search2 = new TGP_Model_Search ( _p ) ; + _model_search2 = new TGP_Model_Search ( _p ) ; #endif - } - else - _model_search2 = new Quad_Model_Search ( _p ); - } - } - else { - delete _model_search2; - _model_search2 = NULL; - } - - // VNS search: - if ( _p.get_VNS_search() ) { - if ( _VNS_search ) - _VNS_search->reset(); - else - _VNS_search = new VNS_Search ( _p ); - } - else { - delete _VNS_search; - _VNS_search = NULL; - } - - // cache search: - if ( _p.get_cache_search() ) { - if ( _cache_search ) - _cache_search->reset(); - else - _cache_search = new Cache_Search ( _p ); - } - else { - delete _cache_search; - _cache_search = NULL; - } - - // barriers: - _flag_reset_barriers = !keep_barriers; - if ( _flag_reset_barriers ) { - _true_barrier.reset(); - _sgte_barrier.reset(); - } - - // stats: - if ( !keep_stats ) - _stats.reset(); - - // mesh: - NOMAD::Mesh::init ( _p.get_mesh_update_basis().value() , - _p.get_mesh_coarsening_exponent () , - _p.get_mesh_refining_exponent () , - _p.get_initial_mesh_index () );/*---------------------------------------------------------*/ - -} - -/* algorithm execution (single-objective) */ -/*---------------------------------------------------------*/ -NOMAD::stop_type NOMAD::Mads::run ( void ) -{ - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_gen_dd(); - NOMAD::stop_type stop_reason = NOMAD::UNKNOWN_STOP_REASON; - -#ifdef USE_MPI - - if ( NOMAD::Slave::get_nb_processes() < 2 ) - { - out << NOMAD::open_block("ERROR:") << "Incorrect command to run with MPI." << std::endl - << "Usage: mpirun -np p exeName" << std::endl ; - out << NOMAD::close_block(); - return stop_reason; - } + } + else + _model_search2 = new Quad_Model_Search ( _p ); + } + } + else + { + delete _model_search2; + _model_search2 = NULL; + } + // VNS search: + if ( _p.get_VNS_search() ) + { + if ( _VNS_search ) + _VNS_search->reset(); + else + _VNS_search = new VNS_Search ( _p ); + } + else { + delete _VNS_search; + _VNS_search = NULL; + } - // init the slaves: - bool stop_slaves_here = false; - - if ( NOMAD::Slave::is_master() ) { - if ( !NOMAD::Slave::are_running() ) { - NOMAD::Slave::init_slaves ( out ); - stop_slaves_here = true; - } - } - else { - NOMAD::Slave s ( _p , _ev_control.get_evaluator() ); - s.run(); - return stop_reason; - } - -#endif - - try { - - // check an extended poll if there are categorical - // variables and disable extended poll otherwise: - if ( _p.get_signature()->has_categorical() ) - { - - if ( _user_ext_poll && !_extended_poll ) - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , - "categorical variables: user extended poll object is NULL" ); - - if ( _p.get_extended_poll_enabled() && !_user_ext_poll ) - { - - if (!_extended_poll) - _extended_poll = new NOMAD::Extended_Poll ( _p ); // extended poll created only once with the signatures of _p - - std::string error_str; - if ( !_extended_poll->set_neighbors_exe ( error_str ) ) - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , error_str ); - } - } - else if ( _extended_poll ) - { - if ( !_user_ext_poll ) - delete _extended_poll; - _extended_poll = NULL; - } - - // check if Mads::run() has been called for multi-objective: - if ( NOMAD::Mads::_flag_check_bimads && _p.get_nb_obj() > 1 ) - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , - "Mads::run() called for multi-objective instead of Mads::multi_run()" ); - -#ifndef R_VERSION - if ( display_degree == NOMAD::NORMAL_DISPLAY || display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::open_block ( "MADS run" ); - - if ( display_degree == NOMAD::NORMAL_DISPLAY ) { - _ev_control.display_stats ( true , - out , - _p.get_display_stats() , - NULL , - false , - NULL ); - out << std::endl << std::endl; - } -#endif - - // barriers init: - if ( _flag_reset_barriers ) - { - _true_barrier.reset(); - _sgte_barrier.reset(); - } - - // evaluator control init: - _ev_control.reset(); - - // reset the extended poll: - if ( _extended_poll && _p.get_extended_poll_enabled() ) - _extended_poll->reset(); - - // mesh init/reset: - if ( _flag_reset_mesh ) - NOMAD::Mesh::init ( _p.get_mesh_update_basis().value() , - _p.get_mesh_coarsening_exponent () , - _p.get_mesh_refining_exponent () , - _p.get_initial_mesh_index () ); - - NOMAD::success_type success , last_success; - int nb_search_pts; - bool count_search; - bool stop = false; - const NOMAD::Eval_Point * new_feas_inc = NULL; - const NOMAD::Eval_Point * new_infeas_inc = NULL; - - stop_reason = NOMAD::NO_STOP; - - // x0 eval: - eval_x0 ( stop , stop_reason ); - - // phase one: if no feasible starting point: - bool phase_one_done = false; - if (stop && - stop_reason == NOMAD::X0_FAIL && - _p.has_EB_constraints() && - ( _stats.get_eval() > 0 || ( _p.get_opt_only_sgte() && _stats.get_sgte_eval() > 0 ) ) ) - { - - phase_one_done = true; - Phase_One_Search p1s ( _p ); - p1s.search ( *this , - nb_search_pts , - stop , - stop_reason , - success , - count_search , - new_feas_inc , - new_infeas_inc ); - } - - // initial Latin-Hypercube (LH) search: - if ( !stop && !phase_one_done && _p.get_LH_search_p0() > 0 ) { - - LH_Search lh ( _p , true , _flag_p1_active ); - int nb_search_pts; - - lh.search ( *this , - nb_search_pts , - stop , - stop_reason , - success , - count_search , - new_feas_inc , - new_infeas_inc ); - - if ( success == NOMAD::FULL_SUCCESS ) - _stats.add_LH_success(); - - if ( count_search ) - _stats.add_nb_LH_searches(); - - _stats.add_LH_pts ( nb_search_pts ); - } - - // no iterations allowed: - if ( !stop && _p.get_max_iterations() == 0 ) { - stop = true; - stop_reason = NOMAD::MAX_ITER_REACHED; - } - - // L_curve initialization: - delete _L_curve; - _L_curve = NULL; - const NOMAD::Double L_curve_target = _p.get_L_curve_target(); - if ( L_curve_target.is_defined() ) - { - _L_curve = new NOMAD::L_Curve ( L_curve_target ); - const NOMAD::Eval_Point * best_feasible = get_best_feasible(); - if ( best_feasible ) - _L_curve->insert ( _stats.get_bb_eval() , best_feasible->get_f() ); - } - - int max_cfi = _p.get_max_consecutive_failed_iterations(); - int nb_cfi = 0; - - success = last_success = NOMAD::UNSUCCESSFUL; - - // MADS iterations: - while ( !stop ) - { - - iteration ( stop , - stop_reason , - success , - new_feas_inc , - new_infeas_inc ); - - if ( success == NOMAD::UNSUCCESSFUL && last_success == NOMAD::UNSUCCESSFUL ) - ++nb_cfi; - else - nb_cfi = (success == NOMAD::UNSUCCESSFUL) ? 1 : 0; - - last_success = success; - - // check the consecutive number of failed iterations: - if ( max_cfi > 0 && nb_cfi > max_cfi ) - { - stop = true; - stop_reason = NOMAD::MAX_CONS_FAILED_ITER; - } - - } - - // parallel version: -#ifdef USE_MPI - - // asynchronous mode: wait for the evaluations in progress: - if ( _p.get_asynchronous() ) - { - std::list<const NOMAD::Eval_Point *> evaluated_pts; - _ev_control.wait_for_evaluations ( NOMAD::ASYNCHRONOUS , - _true_barrier , - _sgte_barrier , - _pareto_front , - stop , - stop_reason , - success , - evaluated_pts ); - } - - // update stats: - _stats.set_MPI_data_size ( NOMAD::Slave::get_data_sent() + - NOMAD::Slave::get_data_rcvd() ); - -#endif - - // final cache save (overwrite=true): - _ev_control.save_caches ( true ); - - // final displays: - const NOMAD::Eval_Point * bf = get_best_feasible(); - bool write_stats = bf && - ( bf->get_tag() != _ev_control.get_last_stats_tag() || - _stats.get_bb_eval() != _ev_control.get_last_stats_bbe() ); - - const std::string & stats_file_name = _p.get_stats_file_name(); - - if ( !stats_file_name.empty() ) - { - if ( write_stats && !_p.get_display_all_eval() ) - { - _ev_control.stats_file ( stats_file_name , bf , true , NULL ); - } - if ( !bf ) - { - std::ofstream fout ( (_p.get_problem_dir() + stats_file_name).c_str() ); - if ( fout.fail() ) - { - if ( out.get_gen_dd() != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY ) - out << std::endl - << "Warning (" << "Mads.cpp" << ", " << __LINE__ - << "): could not save information in stats file \'" - << stats_file_name << "\'" << std::endl << std::endl; - } - else - fout << "no feasible solution has been found in " - << _stats.get_bb_eval() << " evaluations" - << std::endl; - fout.close(); - } - } - - if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) + // cache search: + if ( _p.get_cache_search() ) + { + if ( _cache_search ) + _cache_search->reset(); + else + _cache_search = new Cache_Search ( _p ); + } + else + { + delete _cache_search; + _cache_search = NULL; + } + + // barriers: + _flag_reset_barriers = !keep_barriers; + if ( _flag_reset_barriers ) { - - // final stats: - if ( display_degree == NOMAD::NORMAL_DISPLAY && bf && write_stats && !_p.get_display_all_eval() ) - _ev_control.display_stats ( false, - out, - _p.get_display_stats() , - bf , - true , - NULL ); -#ifndef R_VERSION - std::ostringstream msg; - msg << "end of run (" << stop_reason << ")"; - out << std::endl << NOMAD::close_block ( msg.str() ); -#endif - } - - // mono-objective final displays: - if ( _p.get_nb_obj() == 1 ) { - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::open_block ( "NOMAD final display" ); - -#ifndef R_VERSION - display(); -#endif - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out.close_block(); - } - - } // end of the try block - - catch ( std::exception & e ) { - -#ifdef USE_MPI - if ( NOMAD::Slave::are_running() ) - NOMAD::Slave::stop_slaves ( out ); -#endif - - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , e.what() ); - } - - // stop the slaves: -#ifdef USE_MPI - if ( NOMAD::Slave::are_running() && stop_slaves_here ) - NOMAD::Slave::stop_slaves ( out ); -#endif - - return stop_reason; -} - -/*----------------------------------------------------------------------*/ -/* launch a single optimization for multi-objective optimization */ -/*----------------------------------------------------------------------*/ -/* . the display_degree is given as a parameter since it corresponds */ -/* to the original iterative display degree before all degrees have */ -/* been set to zero */ -/* . private method */ -/*----------------------------------------------------------------------*/ -void NOMAD::Mads::multi_launch_single_opt -( NOMAD::dd_type display_degree , - int mads_runs , - int overall_bbe , - NOMAD::Multi_Obj_Evaluator & ev , - int & stagnation_cnt , - NOMAD::Stats & multi_stats , - bool & stop , - NOMAD::stop_type & stop_reason ) -{ - // max number of bb evaluations for one MADS run: - int max_bbe = _p.get_max_bb_eval(); - - // size of the Pareto front before the MADS run: - int tmp = _pareto_front->size(); - - // current MADS run: - int cur_mads_run = multi_stats.get_mads_runs(); - - // displays: - const NOMAD::Display & out = _p.out(); - - if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) { - out << "MADS run " << std::setw(2) << cur_mads_run + 1; - if ( mads_runs > 0 ) - out << "/" << mads_runs; - out << " ..."; - } - - // run single-objective MADS (it also updates the Pareto front): - NOMAD::Mads::set_flag_check_bimads ( false ); - NOMAD::stop_type single_run_stop_reason = run(); - NOMAD::Mads::set_flag_check_bimads ( true ); - - if ( single_run_stop_reason == NOMAD::CTRL_C || - single_run_stop_reason == NOMAD::ERROR || - single_run_stop_reason == NOMAD::UNKNOWN_STOP_REASON || - single_run_stop_reason == NOMAD::X0_FAIL || - single_run_stop_reason == NOMAD::F_TARGET_REACHED || - single_run_stop_reason == NOMAD::P1_FAIL ) { - stop = true; - stop_reason = single_run_stop_reason; - } - - // update MULTI-MADS stats from MADS stats: - multi_stats.update ( _stats , false ); // for_search = false - multi_stats.add_mads_run(); - - int nb_new_pts = _pareto_front->size() - tmp; - int global_bbe = multi_stats.get_bb_eval(); - - // displays: - if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) { - - // display basic stats on the terminated run: - out << "... OK [bb eval=" << std::setw(3) << _stats.get_bb_eval() - << "] [overall bb eval=" << std::setw(5) << global_bbe - << "] [# dominant pts=" << std::setw(4) << _pareto_front->size() - << "] [# new pts=" << std::setw(4) << nb_new_pts << "]"; - - // display f1, f2, and f: - const NOMAD::Eval_Point * bf = get_best_feasible(); - if ( bf ) { - - const NOMAD::Point & bbo = bf->get_bb_outputs(); - - out << " [f1=" << bbo[ev.get_i1()] - << " f2=" << bbo[ev.get_i2()]; - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << " f=" << bf->get_f(); - out << "]"; - } - out << std::endl; - } - - if ( _stats.get_bb_eval() == 0 && nb_new_pts == 0 ) - ++stagnation_cnt; - else - stagnation_cnt = 0; - - // stop ? - if ( !stop ) - { - - // test the number of MADS runs: - if ( mads_runs > 0 ) - { - if ( multi_stats.get_mads_runs() >= mads_runs ) - { - stop = true; - stop_reason = NOMAD::MULTI_NB_MADS_RUNS_REACHED; - } - } - - // test if no new Pareto point has been generated for 50*n MADS runs: - else - { - if ( stagnation_cnt > 50 * _p.get_nb_free_variables() ) - { - stop = true; - stop_reason = NOMAD::MULTI_STAGNATION; - } - } - } - - if ( overall_bbe >= 0 && global_bbe >= overall_bbe ) { - stop = true; - stop_reason = NOMAD::MULTI_MAX_BB_REACHED; - } - - bool user_calls_enabled = _p.get_user_calls_enabled(); - - if ( !stop ) - { - - // ell is the mesh index on which the last run terminated: - // int ell = NOMAD::Mesh::get_mesh_index(); - - // reset MADS: - reset(); - - // this strategy deciding the initial mesh size - // was used with versions < 3.4 - // if ( cur_mads_run > 1 ) - // _p.set_INITIAL_MESH_INDEX ( (ell > 5) ? 5 : ell ); - - // modify MAX_BB_EVAL for single runs (in order to have - // less than overall_bbe blackbox evaluations): - if ( overall_bbe >= 0 && global_bbe + max_bbe > overall_bbe ) - _p.set_MAX_BB_EVAL ( overall_bbe - global_bbe ); - } - - // set the number of MADS runs for the general Stats object: - _stats.set_mads_runs ( multi_stats.get_mads_runs() ); - - // call the user-defined function Multi_Obj_Evaluator::update_mads_run(): - if ( user_calls_enabled ) - ev.update_mads_run ( _stats , - _ev_control , - _true_barrier , - _sgte_barrier , - *_pareto_front ); + _true_barrier.reset(); + _sgte_barrier.reset(); + } + + // stats: + if ( !keep_stats ) + _stats.reset(); + + + _mesh->reset(); + } -/*--------------------------------------------------------------------------*/ -/* compute and set the minimal poll size for multi-objective optimization */ -/* (private) */ -/*--------------------------------------------------------------------------*/ -void NOMAD::Mads::multi_set_min_poll_size ( const NOMAD::Point & lb , - const NOMAD::Point & ub , - const NOMAD::Point & delta_p_0 , - NOMAD::Double delta_j ) -{ - delta_j /= sqrt ( NOMAD::Mesh::get_mesh_update_basis() ); - - int n = delta_p_0.size(); - NOMAD::Point delta_p_min (n); - for ( int i = 0 ; i < n ; ++i ) { - - // set a relative value: - if ( lb[i].is_defined() && ub[i].is_defined() ) - delta_p_min[i] = delta_j * ( ub[i] - lb[i] ); - - // set an absolute value: - else - delta_p_min[i] = delta_j; - - // compare to delta_p_0: - if ( delta_p_min[i] > delta_p_0[i] ) - delta_p_min[i] = delta_p_0[i]; - } - - _p.set_MIN_POLL_SIZE ( delta_p_min ); -} - -/*---------------------------------------------------------*/ -/* algorithm execution (multi) */ +/* algorithm execution (single-objective) */ /*---------------------------------------------------------*/ -NOMAD::stop_type NOMAD::Mads::multi_run ( void ) +NOMAD::stop_type NOMAD::Mads::run ( void ) { - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_gen_dd(); - NOMAD::stop_type stop_reason = NOMAD::UNKNOWN_STOP_REASON; - - // init the slaves: - + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_gen_dd(); + NOMAD::stop_type stop_reason = NOMAD::UNKNOWN_STOP_REASON; + #ifdef USE_MPI - + if ( NOMAD::Slave::get_nb_processes() < 2 ) { out << NOMAD::open_block("ERROR:") << "Incorrect command to run with MPI." << std::endl @@ -777,427 +277,983 @@ NOMAD::stop_type NOMAD::Mads::multi_run ( void ) return stop_reason; } - bool stop_slaves_here = false; - - if ( NOMAD::Slave::is_master() ) { - if ( !NOMAD::Slave::are_running() ) { - NOMAD::Slave::init_slaves ( out ); - stop_slaves_here = true; - } - } - else { - NOMAD::Slave s ( _p , _ev_control.get_evaluator() ); - s.run(); - return stop_reason; - } - + + // init the slaves: + bool stop_slaves_here = false; + + if ( NOMAD::Slave::is_master() ) + { + if ( !NOMAD::Slave::are_running() ) + { + NOMAD::Slave::init_slaves ( out ); + stop_slaves_here = true; + } + } + else + { + NOMAD::Slave s ( _p , _ev_control.get_evaluator() ); + s.run(); + return stop_reason; + } + #endif - - try { - - // objective indexes: - NOMAD::Multi_Obj_Evaluator::set_obj_indexes ( _p.get_index_obj() ); - - // bounds: - const NOMAD::Point & lb = _p.get_lb(); - const NOMAD::Point & ub = _p.get_ub(); - - // MULTI-MADS stopping criteria: - int mads_runs = _p.get_multi_nb_mads_runs(); // max number of MADS runs - int overall_bbe = _p.get_multi_overall_bb_eval(); // max number of total bb eval. - bool use_delta_crit = _p.get_multi_use_delta_crit(); // use the delta term. crit. - int stagnation_cnt = 0; - - if ( mads_runs == 0 ) - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , - "Mads::multi_run(): parameter MULTI_NB_MADS_RUNS is not positive" ); - - if ( _p.get_nb_obj() != 2 ) - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , - "Mads::multi_run(): NOMAD current version handles a maximum of two objectives" ); - - // remember cache save period: - int old_csp = _p.get_cache_save_period(); - - // remember L_CURVE_TARGET: - NOMAD::Double old_lct = _p.get_L_curve_target(); - - // remember solution file: - std::string old_sol_file = _p.get_solution_file(); - - // remember the original LH search parameters: - int lh_p0 = _p.get_LH_search_p0(); - int lh_pi = _p.get_LH_search_pi(); - - // remember the original minimal poll size: - const NOMAD::Point original_min_poll_size = _p.get_min_poll_size(); - - // remember display degrees: - NOMAD::dd_type iter_dd = out.get_iter_dd(); - std::string old_dd; - out.get_display_degree ( old_dd ); - - // save list of starting points: - std::string x0_cache_file = _p.get_x0_cache_file(); - std::vector<NOMAD::Point *> x0s; + + try { - const std::vector<NOMAD::Point *> & x0s_tmp = _p.get_x0s(); - size_t nx0 = x0s_tmp.size() , k; - for ( k = 0 ; k < nx0 ; ++k ) - x0s.push_back ( new Point ( *x0s_tmp[k] ) ); - } - - // compute delta_p_0: - NOMAD::Point delta_p_0 ( _p.get_dimension() ); - _p.get_signature()->get_mesh().get_delta_p ( delta_p_0 , - _p.get_initial_mesh_index() ); - - if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) - out << std::endl << NOMAD::open_block ( "multi-MADS run" ) << std::endl; - - bool stop = false; - stop_reason = NOMAD::NO_STOP; - - // MULTI-MADS stats: - NOMAD::Stats multi_stats ( _stats ); - - // access to the evaluator (downcast to a Multi_Obj_Evaluator): - NOMAD::Multi_Obj_Evaluator * ev = - static_cast<NOMAD::Multi_Obj_Evaluator*> ( _ev_control.get_evaluator() ); - if ( !ev->is_multi_obj() ) - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , - "Mads::multi_run(): associated Evaluator object is not a Multi_Obj_Evaluator" ); - - // parameters modifications: - // ------------------------- - - // STATS_FILE: - const std::string old_stats_file_name = _p.get_stats_file_name(); - const std::list<std::string> old_stats_file = _p.get_stats_file(); - _p.reset_stats_file(); - - // MAX_BB_EVAL: - int max_bbe = _p.get_max_bb_eval(); - if ( overall_bbe >= 0 && ( max_bbe < 0 || overall_bbe < max_bbe ) ) - _p.set_MAX_BB_EVAL ( overall_bbe ); - - // disable display: - _p.set_DISPLAY_DEGREE ( NOMAD::NO_DISPLAY ); - - // disable solution file: - _p.set_SOLUTION_FILE ( "" ); - - // disable CACHE_SAVE_PERIOD: - _p.set_CACHE_SAVE_PERIOD ( -1 ); - - // disable L_CURVE_TARGET: - _p.set_L_CURVE_TARGET ( NOMAD::Double() ); - - // LH_SEARCH and MAX_BB_EVAL adjustment: - if ( lh_p0 > 0 ) { - _p.set_LH_SEARCH ( lh_p0 , 0 ); - if ( max_bbe >= 0 ) { - int bbe = max_bbe + lh_p0; - if ( overall_bbe >= 0 && bbe > overall_bbe ) - bbe = overall_bbe; - _p.set_MAX_BB_EVAL ( bbe ); - } - } - - // parameters validation: - _p.check ( true , // remove_history_file = true - true , // remove_solution_file = true - true ); // remove_stats_file = true - - // Pareto front initialization: - delete _pareto_front; - _pareto_front = new NOMAD::Pareto_Front; - - // initial optimizations ( minimize f1(x) or f2(x) ): - // -------------------------------------------------- - const NOMAD::Eval_Point * best_f2; - int i; - - for ( i = 0 ; i < 2 ; ++i ) - { - if ( stop ) - break; + // check an extended poll if there are categorical + // variables and disable extended poll otherwise: + if ( _p.get_signature()->has_categorical() ) + { + + if ( _user_ext_poll && !_extended_poll ) + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , + "categorical variables: user extended poll object is NULL" ); + + if ( _p.get_extended_poll_enabled() && !_user_ext_poll ) + { + if (!_extended_poll) + _extended_poll = new NOMAD::Extended_Poll ( _p ); // extended poll created only once with the signatures of _p + + std::string error_str; + if ( !_extended_poll->set_neighbors_exe ( error_str ) ) + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , error_str ); + } + } + else if ( _extended_poll ) + { + if ( !_user_ext_poll ) + delete _extended_poll; + _extended_poll = NULL; + } + + // check if Mads::run() has been called for multi-objective: + if ( NOMAD::Mads::_flag_check_bimads && _p.get_nb_obj() > 1 ) + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , + "Mads::run() called for multi-objective instead of Mads::multi_run()" ); - // minimize f2: - if ( i == 1 ) +#ifndef R_VERSION + if ( display_degree == NOMAD::NORMAL_DISPLAY || display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << NOMAD::open_block ( "MADS run" ); + + if ( display_degree == NOMAD::NORMAL_DISPLAY ) { + _ev_control.display_stats ( true , + out , + _p.get_display_stats() , + NULL , + false , + NULL ); + out << std::endl << std::endl; + } +#endif + + // barriers init: + if ( _flag_reset_barriers ) { + _true_barrier.reset(); + _sgte_barrier.reset(); + } - // new starting point: - best_f2 = _pareto_front->get_best_f2(); - if ( best_f2 ) - { - _p.set_EXTERN_SIGNATURE ( best_f2->get_signature() ); - _p.reset_X0(); - _p.set_X0 ( *best_f2 ); + // evaluator control init: + _ev_control.reset(); + + // reset the extended poll: + if ( _extended_poll && _p.get_extended_poll_enabled() ) + _extended_poll->reset(); + + // mesh init/reset: + if ( _flag_reset_mesh ) + _mesh->reset(); + + NOMAD::success_type success , last_success; + int nb_search_pts; + bool count_search; + bool stop = false; + const NOMAD::Eval_Point * new_feas_inc = NULL; + const NOMAD::Eval_Point * new_infeas_inc = NULL; + + stop_reason = NOMAD::NO_STOP; + + // x0 eval: + eval_x0 ( stop , stop_reason ); + + // phase one: if no feasible starting point: + bool phase_one_done = false; + if (stop && + stop_reason == NOMAD::X0_FAIL && + _p.has_EB_constraints() && + ( _stats.get_eval() > 0 || ( _p.get_opt_only_sgte() && _stats.get_sgte_eval() > 0 ) ) ) + { + + phase_one_done = true; + Phase_One_Search p1s ( _p ); + p1s.search ( *this , + nb_search_pts , + stop , + stop_reason , + success , + count_search , + new_feas_inc , + new_infeas_inc ); + + _mesh->reset(); + + } + + // initial Latin-Hypercube (LH) search: + if ( !stop && !phase_one_done && _p.get_LH_search_p0() > 0 ) + { + + LH_Search lh ( _p , true , _flag_p1_active ); + int nb_search_pts; + + lh.search ( *this , + nb_search_pts , + stop , + stop_reason , + success , + count_search , + new_feas_inc , + new_infeas_inc ); + + if ( success == NOMAD::FULL_SUCCESS ) + _stats.add_LH_success(); + + if ( count_search ) + _stats.add_nb_LH_searches(); + + _stats.add_LH_pts ( nb_search_pts ); + } + + // no iterations allowed: + if ( !stop && _p.get_max_iterations() == 0 ) + { + stop = true; + stop_reason = NOMAD::MAX_ITER_REACHED; + } + + // L_curve initialization: + delete _L_curve; + _L_curve = NULL; + const NOMAD::Double L_curve_target = _p.get_L_curve_target(); + if ( L_curve_target.is_defined() ) + { + _L_curve = new NOMAD::L_Curve ( L_curve_target ); + const NOMAD::Eval_Point * best_feasible = get_best_feasible(); + if ( best_feasible ) + _L_curve->insert ( _stats.get_bb_eval() , best_feasible->get_f() ); + } + + int max_cfi = _p.get_max_consecutive_failed_iterations(); + int nb_cfi = 0; + + success = last_success = NOMAD::UNSUCCESSFUL; + + // MADS iterations: + while ( !stop ) + { + + iteration ( stop , + stop_reason , + success , + new_feas_inc , + new_infeas_inc ); + + if ( success == NOMAD::UNSUCCESSFUL && last_success == NOMAD::UNSUCCESSFUL ) + ++nb_cfi; + else + nb_cfi = (success == NOMAD::UNSUCCESSFUL) ? 1 : 0; + + last_success = success; + + // check the consecutive number of failed iterations: + if ( max_cfi > 0 && nb_cfi > max_cfi ) + { + stop = true; + stop_reason = NOMAD::MAX_CONS_FAILED_ITER; } - // LH_SEARCH: - if ( lh_pi > 0 ) - _p.set_LH_SEARCH ( lh_pi , 0 ); - else if ( lh_p0 > 0 ) - _p.set_LH_SEARCH ( 0 , 0 ); - - // MAX_BB_EVAL: - if ( max_bbe >= 0 ) { - int bbe = max_bbe + ( (lh_pi > 0 ) ? lh_pi : 0 ); - if ( overall_bbe >= 0 ) { - if ( bbe > overall_bbe ) - bbe = overall_bbe; - int global_bbe = multi_stats.get_bb_eval(); - if ( global_bbe + bbe > overall_bbe ) - bbe = overall_bbe - global_bbe; + } + + // parallel version: +#ifdef USE_MPI + + // asynchronous mode: wait for the evaluations in progress: + if ( _p.get_asynchronous() ) + { + std::list<const NOMAD::Eval_Point *> evaluated_pts; + _ev_control.wait_for_evaluations ( NOMAD::ASYNCHRONOUS , + _true_barrier , + _sgte_barrier , + _pareto_front , + stop , + stop_reason , + success , + evaluated_pts ); + } + + // update stats: + _stats.set_MPI_data_size ( NOMAD::Slave::get_data_sent() + + NOMAD::Slave::get_data_rcvd() ); + +#endif + + // final cache save (overwrite=true): + _ev_control.save_caches ( true ); + + // final displays: + const NOMAD::Eval_Point * bf = get_best_feasible(); + bool write_stats = bf && + ( bf->get_tag() != _ev_control.get_last_stats_tag() || + _stats.get_bb_eval() != _ev_control.get_last_stats_bbe() ); + + const std::string & stats_file_name = _p.get_stats_file_name(); + + if ( !stats_file_name.empty() ) + { + if ( write_stats && !_p.get_display_all_eval() ) + { + _ev_control.stats_file ( stats_file_name , bf , true , NULL ); + } + if ( !bf && display_degree > NOMAD::MINIMAL_DISPLAY ) + { + std::ofstream fout ( (_p.get_problem_dir() + stats_file_name).c_str() ); + if ( fout.fail() ) + { + out << std::endl + << "Warning (" << "Mads.cpp" << ", " << __LINE__ + << "): could not save information in stats file \'" + << stats_file_name << "\'" << std::endl << std::endl; } - _p.set_MAX_BB_EVAL ( bbe ); + else + fout << "no feasible solution has been found after " + << _stats.get_bb_eval() << " evaluations" + << std::endl; + fout.close(); } + + } + + if ( display_degree > NOMAD::MINIMAL_DISPLAY) + { + + // final stats: + if ( display_degree == NOMAD::NORMAL_DISPLAY && bf && write_stats && !_p.get_display_all_eval() ) + _ev_control.display_stats ( false, + out, + _p.get_display_stats() , + bf , + true , + NULL ); +#ifndef R_VERSION + std::ostringstream msg; + msg << "end of run (" << stop_reason << ")"; + out << std::endl << NOMAD::close_block ( msg.str() ); +#endif + } + + // mono-objective final displays: + if ( _p.get_nb_obj() == 1 ) + { + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << NOMAD::open_block ( "NOMAD final display" ); + +#ifndef R_VERSION + display(); +#endif + + - if ( _p.to_be_checked() ) - _p.check ( false , // remove_history_file = false - true , // remove_solution_file = true - true ); // remove_stats_file = true + if ( display_degree == NOMAD::FULL_DISPLAY ) + out.close_block(); } - // set weights/reference: - ev->set_weights ( 1-i , i ); - ev->set_ref ( NULL ); + } // end of the try block + + catch ( std::exception & e ) + { - // launch the single optimization: - multi_launch_single_opt ( iter_dd , - mads_runs , - overall_bbe , - *ev , - stagnation_cnt , - multi_stats , - stop , - stop_reason ); - } - - const NOMAD::Point * ref; - const NOMAD::Pareto_Point * xj; - NOMAD::Double delta_j; - - // the LH search is disabled: - _p.set_LH_SEARCH ( 0 , 0 ); - - // MAX_BB_EVAL reset: - if ( max_bbe > 0 && ( lh_p0 > 0 || lh_pi > 0 ) ) +#ifdef USE_MPI + if ( NOMAD::Slave::are_running() ) + NOMAD::Slave::stop_slaves ( out ); +#endif + + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , e.what() ); + } + + // stop the slaves: +#ifdef USE_MPI + if ( NOMAD::Slave::are_running() && stop_slaves_here ) + NOMAD::Slave::stop_slaves ( out ); +#endif + + return stop_reason; +} + +/*----------------------------------------------------------------------*/ +/* launch a single optimization for multi-objective optimization */ +/*----------------------------------------------------------------------*/ +/* . the display_degree is given as a parameter since it corresponds */ +/* to the original iterative display degree before all degrees have */ +/* been set to zero */ +/* . private method */ +/*----------------------------------------------------------------------*/ +void NOMAD::Mads::multi_launch_single_opt +( NOMAD::dd_type display_degree , + int mads_runs , + int overall_bbe , + NOMAD::Multi_Obj_Evaluator & ev , + int & stagnation_cnt , + NOMAD::Stats & multi_stats , + bool & stop , + NOMAD::stop_type & stop_reason ) +{ + // max number of bb evaluations for one MADS run: + int max_bbe = _p.get_max_bb_eval(); + + // size of the Pareto front before the MADS run: + int tmp = _pareto_front->size(); + + // current MADS run: + int cur_mads_run = multi_stats.get_mads_runs(); + + // displays: + const NOMAD::Display & out = _p.out(); + + if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) + { + out << "MADS run " << std::setw(2) << cur_mads_run + 1; + if ( mads_runs > 0 ) + out << "/" << mads_runs; + out << " ..."; + } + + // run single-objective MADS (it also updates the Pareto front): + NOMAD::Mads::set_flag_check_bimads ( false ); + NOMAD::stop_type single_run_stop_reason = run(); + NOMAD::Mads::set_flag_check_bimads ( true ); + + if ( single_run_stop_reason == NOMAD::CTRL_C || + single_run_stop_reason == NOMAD::ERROR || + single_run_stop_reason == NOMAD::UNKNOWN_STOP_REASON || + single_run_stop_reason == NOMAD::X0_FAIL || + single_run_stop_reason == NOMAD::F_TARGET_REACHED || + single_run_stop_reason == NOMAD::P1_FAIL ) { - int bbe = max_bbe; - if ( overall_bbe >= 0 ) + stop = true; + stop_reason = single_run_stop_reason; + } + + // update MULTI-MADS stats from MADS stats: + multi_stats.update ( _stats , false ); // for_search = false + multi_stats.add_mads_run(); + + int nb_new_pts = _pareto_front->size() - tmp; + int global_bbe = multi_stats.get_bb_eval(); + + // displays: + if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) + { + + // display basic stats on the terminated run: + out << "... OK [bb eval=" << std::setw(3) << _stats.get_bb_eval() + << "] [overall bb eval=" << std::setw(5) << global_bbe + << "] [# dominant pts=" << std::setw(4) << _pareto_front->size() + << "] [# new pts=" << std::setw(4) << nb_new_pts << "]"; + + // display f1, f2, and f: + const NOMAD::Eval_Point * bf = get_best_feasible(); + if ( bf ) { - if ( bbe > overall_bbe ) - bbe = overall_bbe; - int global_bbe = multi_stats.get_bb_eval(); - if ( global_bbe + bbe > overall_bbe ) - bbe = overall_bbe - global_bbe; + const NOMAD::Point & bbo = bf->get_bb_outputs(); + + out << " [f1=" << bbo[ev.get_i1()] + << " f2=" << bbo[ev.get_i2()]; + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << " f=" << bf->get_f(); + out << "]"; } - _p.set_MAX_BB_EVAL ( bbe ); - } - - // MULTI-MADS main loop: - // --------------------- - const NOMAD::Eval_Point * x0_tmp; - - while ( !stop ) - { - - // get the reference point from the Pareto front: - ref = _pareto_front->get_ref ( xj , delta_j ); - - if ( !xj ) { - stop = true; - stop_reason = NOMAD::MULTI_NO_PARETO_PTS; - break; - } - - // use delta as stopping criterion: - if ( use_delta_crit ) { - if ( delta_j.is_defined() && delta_j > 0.0 ) - multi_set_min_poll_size ( lb , ub , delta_p_0 , delta_j ); - else - _p.set_MIN_POLL_SIZE ( original_min_poll_size ); - } - - // new starting point: - x0_tmp = xj->get_element(); - _p.set_EXTERN_SIGNATURE ( x0_tmp->get_signature() ); - _p.reset_X0(); - _p.set_X0 ( *x0_tmp ); - - _p.check ( false , // remove_history_file = false - true , // remove_solution_file = true - true ); // remove_stats_file = true - - // a reference point has been found: optimization - // with reference-based function: - if ( ref ) { - - // set reference: - ev->set_ref ( ref ); - - // launch the single optimization: - multi_launch_single_opt ( iter_dd , - mads_runs , - overall_bbe , - *ev , - stagnation_cnt , - multi_stats , - stop , - stop_reason ); - - delete ref; - ev->set_ref ( NULL ); - } - - // no reference available: two optimizations ( f1(x) and f2(x) ): - else { - - // for the stagnation check: - const NOMAD::Eval_Point * pp_before; - int stagnation_cnt_before , overall_bbe_before; - bool check_1 = false; - - // loop on f1 and f2: - for ( i = 0 ; i < 2 ; ++i ) { - - if ( stop ) - break; - - // minimize f2: - if ( i == 1 ) { - - // new starting point: - best_f2 = _pareto_front->get_best_f2(); - if ( best_f2 ) { - _p.set_EXTERN_SIGNATURE ( best_f2->get_signature() ); - _p.reset_X0(); - _p.set_X0 ( *best_f2 ); - } - else - _p.set_X0 ( *x0_tmp ); - - _p.check ( false , // remove_history_file = false - true , // remove_solution_file = true - true ); // remove_stats_file = true - } - - // set weights/reference: - ev->set_weights ( 1-i , i ); - ev->set_ref ( NULL ); - - stagnation_cnt_before = stagnation_cnt; - overall_bbe_before = overall_bbe; - pp_before = ( _pareto_front->size() == 1 ) ? - _pareto_front->begin() : NULL; - - // launch the single optimization: - multi_launch_single_opt ( iter_dd , - mads_runs , - overall_bbe , - *ev , - stagnation_cnt , - multi_stats , - stop , - stop_reason ); - - // stagnation check: - if ( stagnation_cnt > stagnation_cnt_before && - overall_bbe == overall_bbe_before && - _pareto_front->size() == 1 && - _pareto_front->begin() == pp_before ) { - - if ( i == 0 ) - check_1 = true; - else if ( check_1 ) { - stop = true; - stop_reason = NOMAD::MULTI_STAGNATION; - } - } - } - } - - } // end of MULTI-MADS main loop - // --------------------------- + out << std::endl; + } + + if ( _stats.get_bb_eval() == 0 && nb_new_pts == 0 ) + ++stagnation_cnt; + else + stagnation_cnt = 0; + + // stop ? + if ( !stop ) + { + + // test the number of MADS runs: + if ( mads_runs > 0 ) + { + if ( multi_stats.get_mads_runs() >= mads_runs ) + { + stop = true; + stop_reason = NOMAD::MULTI_NB_MADS_RUNS_REACHED; + } + } + + // test if no new Pareto point has been generated for 50*n MADS runs: + else + { + if ( stagnation_cnt > 50 * _p.get_nb_free_variables() ) + { + stop = true; + stop_reason = NOMAD::MULTI_STAGNATION; + } + } + } + + if ( overall_bbe >= 0 && global_bbe >= overall_bbe ) + { + stop = true; + stop_reason = NOMAD::MULTI_MAX_BB_REACHED; + } + + bool user_calls_enabled = _p.get_user_calls_enabled(); + + if ( !stop ) + { + + // ell is the mesh index on which the last run terminated: + // int ell = NOMAD::Mesh::get_mesh_index(); + + // reset MADS: + reset(); + + // this strategy deciding the initial mesh size + // was used with versions < 3.4 + // if ( cur_mads_run > 1 ) + // _p.set_INITIAL_MESH_INDEX ( (ell > 5) ? 5 : ell ); + + // modify MAX_BB_EVAL for single runs (in order to have + // less than overall_bbe blackbox evaluations): + if ( overall_bbe >= 0 && global_bbe + max_bbe > overall_bbe ) + _p.set_MAX_BB_EVAL ( overall_bbe - global_bbe ); + } + + // set the number of MADS runs for the general Stats object: + _stats.set_mads_runs ( multi_stats.get_mads_runs() ); + + // call the user-defined function Multi_Obj_Evaluator::update_mads_run(): + if ( user_calls_enabled ) + ev.update_mads_run ( _stats , + _ev_control , + _true_barrier , + _sgte_barrier , + *_pareto_front ); +} - // parameters re-initialization and final displays: - { - _p.reset_X0(); - size_t nx0 = x0s.size(); - if ( nx0 > 0 ) { - for ( size_t k = 0 ; k < nx0 ; ++k ) { - _p.set_X0 ( *x0s[k] ); - delete x0s[k]; - } - } - else if ( !x0_cache_file.empty() ) - _p.set_X0 ( x0_cache_file ); - } - _p.set_MAX_BB_EVAL ( max_bbe ); - _p.set_DISPLAY_DEGREE ( old_dd ); - _p.set_STATS_FILE ( old_stats_file_name , old_stats_file ); - _p.set_SOLUTION_FILE ( old_sol_file ); - _p.set_LH_SEARCH ( lh_p0 , lh_pi ); - _p.set_CACHE_SAVE_PERIOD ( old_csp ); - _p.set_L_CURVE_TARGET ( old_lct ); - - if ( use_delta_crit ) - _p.set_MIN_POLL_SIZE ( original_min_poll_size ); +/*--------------------------------------------------------------------------*/ +/* compute and set the minimal poll size for multi-objective optimization */ +/* (private) */ +/*--------------------------------------------------------------------------*/ +void NOMAD::Mads::multi_set_min_poll_size ( const NOMAD::Point & lb , + const NOMAD::Point & ub , + const NOMAD::Point & Delta_0 , + NOMAD::Double delta_j ) +{ - _p.check ( false , // remove_history_file = false - true , // remove_solution_file = true - true ); // remove_stats_file = true + delta_j /= sqrt ( _mesh->get_update_basis() ); + + int n = Delta_0.size(); + NOMAD::Point Delta_min (n); + + for ( int i = 0 ; i < n ; ++i ) + { + + // set a relative value: + if ( lb[i].is_defined() && ub[i].is_defined() ) + Delta_min[i] = delta_j * ( ub[i] - lb[i] ); + + // set an absolute value: + else + Delta_min[i] = delta_j; + + // compare to Delta_0: + if ( Delta_min[i] > Delta_0[i] ) + Delta_min[i] = Delta_0[i]; + } + + _p.set_MIN_POLL_SIZE ( Delta_min ); +} - // reset MADS stats from MULTI-MADS stats: - _stats = multi_stats; - - // final cache save (overwrite=true): - _ev_control.save_caches ( true ); +/*---------------------------------------------------------*/ +/* algorithm execution (multi) */ +/*---------------------------------------------------------*/ +NOMAD::stop_type NOMAD::Mads::multi_run ( void ) +{ + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_gen_dd(); + NOMAD::stop_type stop_reason = NOMAD::UNKNOWN_STOP_REASON; + + // init the slaves: -#ifndef R_VERSION - if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) { - std::ostringstream msg; - msg << "end of run (" << stop_reason << ")"; - out << std::endl << NOMAD::close_block ( msg.str() ) << std::endl; - } +#ifdef USE_MPI + + if ( NOMAD::Slave::get_nb_processes() < 2 ) + { + out << NOMAD::open_block("ERROR:") << "Incorrect command to run with MPI." << std::endl + << "Usage: mpirun -np p exeName" << std::endl ; + out << NOMAD::close_block(); + return stop_reason; + } + + bool stop_slaves_here = false; + + if ( NOMAD::Slave::is_master() ) + { + if ( !NOMAD::Slave::are_running() ) + { + NOMAD::Slave::init_slaves ( out ); + stop_slaves_here = true; + } + } + else + { + NOMAD::Slave s ( _p , _ev_control.get_evaluator() ); + s.run(); + return stop_reason; + } + #endif + + try { + + // objective indexes: + NOMAD::Multi_Obj_Evaluator::set_obj_indexes ( _p.get_index_obj() ); + + // bounds: + const NOMAD::Point & lb = _p.get_lb(); + const NOMAD::Point & ub = _p.get_ub(); + + // MULTI-MADS stopping criteria: + int mads_runs = _p.get_multi_nb_mads_runs(); // max number of MADS runs + int overall_bbe = _p.get_multi_overall_bb_eval(); // max number of total bb eval. + bool use_delta_crit = _p.get_multi_use_delta_crit(); // use the delta term. crit. + int stagnation_cnt = 0; + + if ( mads_runs == 0 ) + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , + "Mads::multi_run(): parameter MULTI_NB_MADS_RUNS is not positive" ); + + if ( _p.get_nb_obj() != 2 ) + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , + "Mads::multi_run(): NOMAD current version handles a maximum of two objectives" ); + + // remember cache save period: + int old_csp = _p.get_cache_save_period(); + + // remember L_CURVE_TARGET: + NOMAD::Double old_lct = _p.get_L_curve_target(); + + // remember solution file: + std::string old_sol_file = _p.get_solution_file(); + + // remember the original LH search parameters: + int lh_p0 = _p.get_LH_search_p0(); + int lh_pi = _p.get_LH_search_pi(); + + // remember the original minimal poll size: + const NOMAD::Point original_min_poll_size = _p.get_min_poll_size(); + + // remember display degrees: + NOMAD::dd_type iter_dd = out.get_iter_dd(); + std::string old_dd; + out.get_display_degree ( old_dd ); + + // save list of starting points: + std::string x0_cache_file = _p.get_x0_cache_file(); + std::vector<NOMAD::Point *> x0s; + { + const std::vector<NOMAD::Point *> & x0s_tmp = _p.get_x0s(); + size_t nx0 = x0s_tmp.size() , k; + for ( k = 0 ; k < nx0 ; ++k ) + x0s.push_back ( new Point ( *x0s_tmp[k] ) ); + } + + NOMAD::Point Delta_0 = _mesh->get_initial_poll_size (); + + + if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) + out << std::endl << NOMAD::open_block ( "multi-MADS run" ) << std::endl; + + bool stop = false; + stop_reason = NOMAD::NO_STOP; + + // MULTI-MADS stats: + NOMAD::Stats multi_stats ( _stats ); + + // access to the evaluator (downcast to a Multi_Obj_Evaluator): + NOMAD::Multi_Obj_Evaluator * ev = + static_cast<NOMAD::Multi_Obj_Evaluator*> ( _ev_control.get_evaluator() ); + if ( !ev->is_multi_obj() ) + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , + "Mads::multi_run(): associated Evaluator object is not a Multi_Obj_Evaluator" ); + + // parameters modifications: + // ------------------------- + + // STATS_FILE: + const std::string old_stats_file_name = _p.get_stats_file_name(); + const std::list<std::string> old_stats_file = _p.get_stats_file(); + _p.reset_stats_file(); + + // MAX_BB_EVAL: + int max_bbe = _p.get_max_bb_eval(); + if ( overall_bbe >= 0 && ( max_bbe < 0 || overall_bbe < max_bbe ) ) + _p.set_MAX_BB_EVAL ( overall_bbe ); + + // disable display: + _p.set_DISPLAY_DEGREE ( NOMAD::NO_DISPLAY ); + + // disable solution file: + _p.set_SOLUTION_FILE ( "" ); + + // disable CACHE_SAVE_PERIOD: + _p.set_CACHE_SAVE_PERIOD ( -1 ); + + // disable L_CURVE_TARGET: + _p.set_L_CURVE_TARGET ( NOMAD::Double() ); + + // LH_SEARCH and MAX_BB_EVAL adjustment: + if ( lh_p0 > 0 ) + { + _p.set_LH_SEARCH ( lh_p0 , 0 ); + if ( max_bbe >= 0 ) + { + int bbe = max_bbe + lh_p0; + if ( overall_bbe >= 0 && bbe > overall_bbe ) + bbe = overall_bbe; + _p.set_MAX_BB_EVAL ( bbe ); + } + } + + // parameters validation: + _p.check ( true , // remove_history_file = true + true , // remove_solution_file = true + true ); // remove_stats_file = true + + // Pareto front initialization: + delete _pareto_front; + _pareto_front = new NOMAD::Pareto_Front; + + // Problem has categorical variables ? (Si why this flag is needed below) + bool hasCategoricalVar=_p.get_signature()->has_categorical(); + + // initial optimizations ( minimize f1(x) or f2(x) ): + // -------------------------------------------------- + const NOMAD::Eval_Point * best_f2; + int i; + + for ( i = 0 ; i < 2 ; ++i ) + { + + if ( stop ) + break; + + // minimize f2: + if ( i == 1 ) + { + + // new starting point: + best_f2 = _pareto_front->get_best_f2(); + if ( best_f2 ) + { + _p.set_EXTERN_SIGNATURE ( best_f2->get_signature() ); + _p.reset_X0(); + _p.set_X0 ( *best_f2 ); + } + + // LH_SEARCH: + if ( lh_pi > 0 ) + _p.set_LH_SEARCH ( lh_pi , 0 ); + else if ( lh_p0 > 0 ) + _p.set_LH_SEARCH ( 0 , 0 ); + + // MAX_BB_EVAL: + if ( max_bbe >= 0 ) + { + int bbe = max_bbe + ( (lh_pi > 0 ) ? lh_pi : 0 ); + if ( overall_bbe >= 0 ) + { + if ( bbe > overall_bbe ) + bbe = overall_bbe; + int global_bbe = multi_stats.get_bb_eval(); + if ( global_bbe + bbe > overall_bbe ) + bbe = overall_bbe - global_bbe; + } + _p.set_MAX_BB_EVAL ( bbe ); + } + + if ( _p.to_be_checked() ) + _p.check ( false , // remove_history_file = false + true , // remove_solution_file = true + true ); // remove_stats_file = true + + _mesh=_p.get_signature()->get_mesh(); + + } + + // set weights/reference: + ev->set_weights ( 1-i , i ); + ev->set_ref ( NULL ); + + // launch the single optimization: + multi_launch_single_opt ( iter_dd , + mads_runs , + overall_bbe , + *ev , + stagnation_cnt , + multi_stats , + stop , + stop_reason ); + } + + const NOMAD::Point * ref; + const NOMAD::Pareto_Point * xj; + NOMAD::Double delta_j; + + // the LH search is disabled: + _p.set_LH_SEARCH ( 0 , 0 ); + + // MAX_BB_EVAL reset: + if ( max_bbe > 0 && ( lh_p0 > 0 || lh_pi > 0 ) ) + { + int bbe = max_bbe; + if ( overall_bbe >= 0 ) + { + if ( bbe > overall_bbe ) + bbe = overall_bbe; + + int global_bbe = multi_stats.get_bb_eval(); + if ( global_bbe + bbe > overall_bbe ) + bbe = overall_bbe - global_bbe; + } + _p.set_MAX_BB_EVAL ( bbe ); + } + + // MULTI-MADS main loop: + // --------------------- + const NOMAD::Eval_Point * x0_tmp; + + while ( !stop ) + { + + // get the reference point from the Pareto front: + ref = _pareto_front->get_ref ( xj , delta_j ); + + if ( !xj ) + { + stop = true; + stop_reason = NOMAD::MULTI_NO_PARETO_PTS; + break; + } + + // use delta as stopping criterion: + if ( use_delta_crit ) + { + if ( delta_j.is_defined() && delta_j > 0.0 ) + multi_set_min_poll_size ( lb , ub , Delta_0 , delta_j ); + else + _p.set_MIN_POLL_SIZE ( original_min_poll_size ); + } + + // new starting point: + x0_tmp = xj->get_element(); + _p.set_EXTERN_SIGNATURE ( x0_tmp->get_signature() ); + _p.reset_X0(); + _p.set_X0 ( *x0_tmp ); + + _p.check ( false , // remove_history_file = false + true , // remove_solution_file = true + true ); // remove_stats_file = true + + // a reference point has been found: optimization + // with reference-based function: + if ( ref ) + { + + // set reference: + ev->set_ref ( ref ); + + // launch the single optimization: + multi_launch_single_opt ( iter_dd , + mads_runs , + overall_bbe , + *ev , + stagnation_cnt , + multi_stats , + stop , + stop_reason ); + + delete ref; + ev->set_ref ( NULL ); + } + + // no reference available: two optimizations ( f1(x) and f2(x) ): + else + { + + // for the stagnation check: + const NOMAD::Eval_Point * pp_before; + int stagnation_cnt_before , overall_bbe_before; + bool check_1 = false; + + // loop on f1 and f2: + for ( i = 0 ; i < 2 ; ++i ) + { + + if ( stop ) + break; + + // minimize f2: + if ( i == 1 ) + { + + // new starting point: + best_f2 = _pareto_front->get_best_f2(); + if ( best_f2 ) + { + _p.set_EXTERN_SIGNATURE ( best_f2->get_signature() ); + _p.reset_X0(); + _p.set_X0 ( *best_f2 ); + } + else + _p.set_X0 ( *x0_tmp ); + + _p.check ( false , // remove_history_file = false + true , // remove_solution_file = true + true ); // remove_stats_file = true + } + + // set weights/reference: + ev->set_weights ( 1-i , i ); + ev->set_ref ( NULL ); + + stagnation_cnt_before = stagnation_cnt; + overall_bbe_before = overall_bbe; + pp_before = ( _pareto_front->size() == 1 ) ? + _pareto_front->begin() : NULL; + + // launch the single optimization: + multi_launch_single_opt ( iter_dd , + mads_runs , + overall_bbe , + *ev , + stagnation_cnt , + multi_stats , + stop , + stop_reason ); + + // stagnation check: + if ( stagnation_cnt > stagnation_cnt_before && + overall_bbe == overall_bbe_before && + _pareto_front->size() == 1 && + _pareto_front->begin() == pp_before ) + { + + if ( i == 0 ) + check_1 = true; + else if ( check_1 ) + { + stop = true; + stop_reason = NOMAD::MULTI_STAGNATION; + } + } + } + } + + } // end of MULTI-MADS main loop + // --------------------------- + + + // parameters re-initialization and final displays: + if ( ! hasCategoricalVar ) // Dimension may change when categorical variables are present. This may pose problem for the check. Hence we add a test -> when categorical variables are present, the parameters are not set back to their initial state at the end of the multi-objective optimization. + { + _p.reset_X0(); + size_t nx0 = x0s.size(); + if ( nx0 > 0 ) + { + for ( size_t k = 0 ; k < nx0 ; ++k ) + { + _p.set_X0 ( *x0s[k] ); + delete x0s[k]; + } + } + else if ( !x0_cache_file.empty() ) + _p.set_X0 ( x0_cache_file ); + + if ( use_delta_crit ) + _p.set_MIN_POLL_SIZE ( original_min_poll_size ); - // multi-objective final displays: - if ( _p.get_nb_obj() > 1 ) { - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out.open_block ( "NOMAD final display" ); - - display(); - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out.close_block(); - } + } + _p.set_MAX_BB_EVAL ( max_bbe ); + _p.set_DISPLAY_DEGREE ( old_dd ); + _p.set_STATS_FILE ( old_stats_file_name , old_stats_file ); + _p.set_SOLUTION_FILE ( old_sol_file ); + _p.set_LH_SEARCH ( lh_p0 , lh_pi ); + _p.set_CACHE_SAVE_PERIOD ( old_csp ); + _p.set_L_CURVE_TARGET ( old_lct ); - } // end of the try block - - catch ( std::exception & e ) { - + + _p.check ( false , // remove_history_file = false + true , // remove_solution_file = true + true ); // remove_stats_file = true + + // reset MADS stats from MULTI-MADS stats: + _stats = multi_stats; + + // final cache save (overwrite=true): + _ev_control.save_caches ( true ); + +#ifndef R_VERSION + if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) + { + std::ostringstream msg; + msg << "end of run (" << stop_reason << ")"; + out << std::endl << NOMAD::close_block ( msg.str() ) << std::endl; + } +#endif + + + // multi-objective final displays: + if ( _p.get_nb_obj() > 1 ) + { + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out.open_block ( "NOMAD final display" ); + + display(); + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out.close_block(); + } + + } // end of the try block + + catch ( std::exception & e ) + { + #ifdef USE_MPI - if ( NOMAD::Slave::are_running() ) - NOMAD::Slave::stop_slaves ( out ); + if ( NOMAD::Slave::are_running() ) + NOMAD::Slave::stop_slaves ( out ); #endif - - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , e.what() ); - } - - // stop the slaves: + + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , e.what() ); + } + + // stop the slaves: #ifdef USE_MPI - if ( NOMAD::Slave::are_running() && stop_slaves_here ) - NOMAD::Slave::stop_slaves ( out ); + if ( NOMAD::Slave::are_running() && stop_slaves_here ) + NOMAD::Slave::stop_slaves ( out ); #endif - - return stop_reason; + + return stop_reason; } /*---------------------------------------------------------*/ @@ -1209,152 +1265,172 @@ void NOMAD::Mads::iteration ( bool & stop , const NOMAD::Eval_Point *& new_feas_inc , const NOMAD::Eval_Point *& new_infeas_inc ) { - - bool forbid_poll_size_stop = false; - - // force quit (by pressing ctrl-c): - if ( !stop && NOMAD::Mads::_force_quit ) - { - stop = true; - stop_reason = NOMAD::CTRL_C; - return; - } - - // poll center selection: - ( ( _p.get_opt_only_sgte() ) ? - _sgte_barrier : _true_barrier ).select_poll_center ( success ); - - // displays: - const NOMAD::Display & out = _p.out(); - if ( out.get_iter_dd() == NOMAD::FULL_DISPLAY ) - out << std::endl - << NOMAD::open_block ( "MADS iteration " - + NOMAD::itos ( _stats.get_iterations() ) ) - << std::endl; - display_iteration_begin(); - - // SEARCH: - // ------- + + bool forbid_poll_size_stop = false; + + // force quit (by pressing ctrl-c): + if ( !stop && NOMAD::Mads::_force_quit ) + { + stop = true; + stop_reason = NOMAD::CTRL_C; + return; + } + + // poll center selection: + ( ( _p.get_opt_only_sgte() ) ? + _sgte_barrier : _true_barrier ).select_poll_center ( success ); + + // displays: + const NOMAD::Display & out = _p.out(); + if ( out.get_iter_dd() == NOMAD::FULL_DISPLAY ) + out << std::endl + << NOMAD::open_block ( "MADS iteration " + + NOMAD::itos ( _stats.get_iterations() ) ) + << std::endl; + display_iteration_begin(); + + // SEARCH: + // ------- search ( stop , stop_reason , success , new_feas_inc , new_infeas_inc ); - // POLL: - // ----- - if ( success != NOMAD::FULL_SUCCESS ) - poll ( stop , - stop_reason , - success , - new_feas_inc , - new_infeas_inc , - forbid_poll_size_stop ); - - // UPDATES: - // -------- - int old_ell = NOMAD::Mesh::get_mesh_index(); - - if ( !stop ) - { - - // mesh update: - NOMAD::Mesh::update ( success ); - - // check the min mesh/poll sizes stopping criteria: - _p.get_signature()->get_mesh().check_min_mesh_sizes ( _p.get_max_mesh_index() , - NOMAD::Mesh::get_mesh_index(), - stop , - stop_reason ); - - // if the Delta_k^p stopping criterion is met with integer variables, - // the last set of directions must have a minimal coordinate of 1; - // otherwise the stopping criterion is disabled at this iteration: - if ( forbid_poll_size_stop && stop && stop_reason == NOMAD::DELTA_P_MIN_REACHED ) + // POLL: + // ----- + if ( success != NOMAD::FULL_SUCCESS ) + poll ( stop , + stop_reason , + success , + new_feas_inc , + new_infeas_inc , + forbid_poll_size_stop ); + + // UPDATES: + // -------- + + NOMAD::Point old_r=_mesh->get_mesh_indices(); + + if ( !stop ) { - stop = false; - stop_reason = NOMAD::NO_STOP; - } - - // display: - if ( _p.out().get_iter_dd() == NOMAD::FULL_DISPLAY ) - _p.out() << std::endl << NOMAD::open_block ( "Mesh update" ) - << "previous mesh index: " << old_ell << std::endl - << "new mesh index : " << NOMAD::Mesh::get_mesh_index() << std::endl - << NOMAD::close_block() << std::endl; - - // periodic cache save (overwrite=false): - if ( _p.get_cache_save_period() > 0 && - _stats.get_iterations()%_p.get_cache_save_period() == - _p.get_cache_save_period() - 1 ) - _ev_control.save_caches ( false ); - } - - // number of iterations: - _stats.add_iteration(); - if ( !stop && - _p.get_max_iterations() > 0 && - _stats.get_iterations() >= _p.get_max_iterations() ) - { - stop = true; - stop_reason = NOMAD::MAX_ITER_REACHED; - } - - // max cache memory: - if ( !stop && - _p.get_max_cache_memory() > 0.0 && - _ev_control.get_cache().size_of() > 1048576*_p.get_max_cache_memory() ) - { - stop = true; - stop_reason = NOMAD::MAX_CACHE_MEMORY_REACHED; - } - - // L_CURVE_TARGET stopping criterion: - if ( _L_curve && !stop ) - { - int bbe = _stats.get_bb_eval(); - if ( success == NOMAD::FULL_SUCCESS ) + // OrthogonalMesh update using success status and direction of success (when present) + if ( new_feas_inc ) + { + _mesh=new_feas_inc->get_signature()->get_mesh(); + _mesh->update ( success, new_feas_inc->get_direction() ); + } + else if ( new_infeas_inc ) + { + _mesh=new_infeas_inc->get_signature()->get_mesh(); + _mesh->update ( success, new_infeas_inc->get_direction()); + } + else + _mesh->update ( success ); + + + _mesh->check_min_mesh_sizes( stop , stop_reason ); + + // if the Delta_k^p stopping criterion is met with integer variables, + // the last set of directions must have a minimal coordinate of 1; + // otherwise the stopping criterion is disabled at this iteration: + if ( forbid_poll_size_stop && stop && stop_reason == NOMAD::DELTA_P_MIN_REACHED ) + { + stop = false; + stop_reason = NOMAD::NO_STOP; + } + + // display: + if ( _p.out().get_iter_dd() == NOMAD::FULL_DISPLAY ) + { + _p.out() << std::endl << NOMAD::open_block ( "Orthogonal mesh update" ) + << "previous mesh indices: ( " << old_r << " )" << std::endl + << "new mesh indices : ( " << _mesh->get_mesh_indices() << " )" << std::endl + << NOMAD::close_block() << std::endl; + } + + // periodic cache save (overwrite=false): + if ( _p.get_cache_save_period() > 0 && + _stats.get_iterations()%_p.get_cache_save_period() == + _p.get_cache_save_period() - 1 ) + _ev_control.save_caches ( false ); + } + + // number of iterations: + _stats.add_iteration(); + if ( !stop && + _p.get_max_iterations() > 0 && + _stats.get_iterations() >= _p.get_max_iterations() ) { - if ( new_feas_inc ) - _L_curve->insert ( bbe , new_feas_inc->get_f() ); - } - else if ( success == NOMAD::UNSUCCESSFUL && _L_curve->check_stop ( bbe ) ) + stop = true; + stop_reason = NOMAD::MAX_ITER_REACHED; + } + + // max cache memory: + if ( !stop && + _p.get_max_cache_memory() > 0.0 && + _ev_control.get_cache().size_of() > 1048576*_p.get_max_cache_memory() ) { - stop = true; - stop_reason = NOMAD::L_CURVE_TARGET_REACHED; - } - } - - // call the user-defined function Evaluator::update_iteration(): - if ( _p.get_user_calls_enabled() ) - { - bool stop_before = stop; - _ev_control.get_evaluator()->update_iteration ( success , - _stats , - _ev_control , - _true_barrier , - _sgte_barrier , - *_pareto_front , - stop ); - if ( !stop_before && stop ) - stop_reason = NOMAD::USER_STOPPED; - } - - // if the algorithms stops, we set the mesh index to the value - // it had before the mesh update: - if ( stop ) - Mesh::set_mesh_index ( old_ell ); - - // displays at the end of an iteration: - display_iteration_end ( stop , - stop_reason , - success , - new_feas_inc , - new_infeas_inc ); + stop = true; + stop_reason = NOMAD::MAX_CACHE_MEMORY_REACHED; + } + + // L_CURVE_TARGET stopping criterion: + if ( _L_curve && !stop ) + { + int bbe = _stats.get_bb_eval(); + if ( success == NOMAD::FULL_SUCCESS ) + { + if ( new_feas_inc ) + _L_curve->insert ( bbe , new_feas_inc->get_f() ); + } + else if ( success == NOMAD::UNSUCCESSFUL && _L_curve->check_stop ( bbe ) ) + { + stop = true; + stop_reason = NOMAD::L_CURVE_TARGET_REACHED; + } + } + + // call the user-defined function Evaluator::update_iteration(): + if ( _p.get_user_calls_enabled() ) + { + bool stop_before = stop; + + NOMAD::Pareto_Front * pf = ( ( _pareto_front ) ? _pareto_front:(new NOMAD::Pareto_Front) ); + + _ev_control.get_evaluator()->update_iteration ( success , + _stats , + _ev_control , + _true_barrier , + _sgte_barrier , + *pf , + stop ); + + if ( ! _pareto_front ) + delete pf; + + + if ( !stop_before && stop ) + stop_reason = NOMAD::USER_STOPPED; + } + + // if the algorithms stops, we set the mesh index to the value + // it had before the mesh update: + if ( stop ) + { + _mesh->set_mesh_indices( old_r ); + } + + // displays at the end of an iteration: + display_iteration_end ( stop , + stop_reason , + success , + new_feas_inc , + new_infeas_inc ); - // displays: - if ( out.get_iter_dd() == NOMAD::FULL_DISPLAY ) - out << std::endl - << NOMAD::close_block ( "end of iteration " - + NOMAD::itos ( _stats.get_iterations()-1 ) ); + // displays: + if ( out.get_iter_dd() == NOMAD::FULL_DISPLAY ) + out << std::endl + << NOMAD::close_block ( "end of iteration " + + NOMAD::itos ( _stats.get_iterations()-1 ) ); } /*---------------------------------------------------------*/ @@ -1384,8 +1460,7 @@ void NOMAD::Mads::poll ( bool & stop , const NOMAD::Eval_Point * x; - int k; - int offset = 0; + size_t offset = 0; std::vector<NOMAD::Signature *> signatures; @@ -1423,17 +1498,14 @@ void NOMAD::Mads::poll ( bool & stop , { // add the poll center signature signatures.push_back(poll_center->get_signature()); - + // Creation of the poll directions set_poll_directions ( dirs[i_pc] , i_pc , offset , *poll_center , stop , stop_reason ); // Reduction is applied only to achieve ortho n+1 - reducePollToNDir=dirs_have_orthomads_np1(dirs[i_pc]); - - + reducePollToNDir=dirs_have_orthomads_np1(dirs[i_pc]); + // creation of the poll trial points in the evaluator control: - k = 0; - if (reducePollToNDir) { @@ -1443,46 +1515,46 @@ void NOMAD::Mads::poll ( bool & stop , _ev_control_for_sorting.clear_eval_lop(); - // Sort the directions only if mesh is not max - if (NOMAD::Mesh::mesh_index_is_not_max() ) - { - - // 1st sorting of points based on feas. or infeas. success direction. IMPORTANT removes out of bounds -> this justifies to proceede in two steps - set_poll_trial_points(dirs[i_pc],offset,*poll_center,stop,stop_reason,true); - if (stop) - { - delete[] dirs; - delete[] reducedPollDirs; - return; - } - + // Sort the directions only if mesh is not finest + if ( ! _mesh->is_finest() ) + { + + // 1st sorting of points based on feas. or infeas. success direction. IMPORTANT removes out of bounds -> this justifies to proceede in two steps + set_poll_trial_points(dirs[i_pc],offset,*poll_center,stop,stop_reason,true); + if (stop) + { + delete[] dirs; + delete[] reducedPollDirs; + return; + } + #ifdef USE_MPI - // asynchronous mode: wait for truth evaluations in progress: - if ( _p.get_asynchronous() ) - { - std::list<const NOMAD::Eval_Point *> eval_pts; - _ev_control.wait_for_evaluations ( NOMAD::ASYNCHRONOUS , - _true_barrier , - _sgte_barrier , - _pareto_front , - stop , - stop_reason , - success , - eval_pts ); - } + // asynchronous mode: wait for truth evaluations in progress: + if ( _p.get_asynchronous() ) + { + std::list<const NOMAD::Eval_Point *> eval_pts; + _ev_control.wait_for_evaluations ( NOMAD::ASYNCHRONOUS , + _true_barrier , + _sgte_barrier , + _pareto_front , + stop , + stop_reason , + success , + eval_pts ); + } #endif - - // 2nd sorting of points based on model and surrogate if available - _ev_control_for_sorting.ordering_lop( NOMAD::POLL,stop,stop_reason,_true_barrier,_sgte_barrier ); - if (stop) - { - delete[] dirs; - delete[] reducedPollDirs; - return; - } - } + + // 2nd sorting of points based on model and surrogate if available + _ev_control_for_sorting.ordering_lop( NOMAD::POLL,stop,stop_reason,_true_barrier,_sgte_barrier ); + if (stop) + { + delete[] dirs; + delete[] reducedPollDirs; + return; + } + } + - // reduce the number of poll direction using dir indices from ev_control_for_sorting and original poll directions (reducedPollDirs) bool hasBeenReduced=set_reduced_poll_to_n_directions(reducedPollDirs[i_pc],*poll_center); @@ -1498,6 +1570,13 @@ void NOMAD::Mads::poll ( bool & stop , set_poll_trial_points(dirs[i_pc],offset,*poll_center,stop,stop_reason,false); offset = dirs[i_pc].size(); + if (!reducePollToNDir) + { + // 2nd sorting of points based on model and surrogate if available + _ev_control.ordering_lop( NOMAD::POLL,stop,stop_reason,_true_barrier,_sgte_barrier ); + } + + } if (stop) @@ -1527,7 +1606,7 @@ void NOMAD::Mads::poll ( bool & stop , + NOMAD::itos ( poll_pts.size() ) + " poll trial points." ); else - out << std::endl << NOMAD::open_block ( "re-ordered and reduced (dynamic directions maybe added after evaluations) list of " + out << std::endl << NOMAD::open_block ( "re-ordered and reduced (dynamic directions may be added after evaluations) list of " + NOMAD::itos ( poll_pts.size() ) + " poll trial points" ); @@ -1580,7 +1659,7 @@ void NOMAD::Mads::poll ( bool & stop , offset=0; while ( true ) { - if ( poll_center && dirs_have_orthomads_np1(reducedPollDirs[i_pc])) + if ( poll_center && NOMAD::Mads::dirs_have_orthomads_np1(reducedPollDirs[i_pc])) { std::list<NOMAD::Direction> dyn_dirs; @@ -1598,10 +1677,10 @@ void NOMAD::Mads::poll ( bool & stop , *evaluated_pts ); } #endif - + bool hasNewDynDir=get_dynamic_directions (reducedPollDirs[i_pc], - dyn_dirs, - *poll_center); + dyn_dirs, + *poll_center); // Set new poll points obtained dynamically @@ -1622,7 +1701,7 @@ void NOMAD::Mads::poll ( bool & stop , return; } } - offset = static_cast<int>(dyn_dirs.size()); + offset = dyn_dirs.size(); } // loop increment: if ( i_pc == NOMAD::PRIMARY ) @@ -1780,36 +1859,41 @@ void NOMAD::Mads::poll ( bool & stop , bool NOMAD::Mads::set_reduced_poll_to_n_directions(std::list<NOMAD::Direction> & dirs, const NOMAD::Eval_Point & poll_center) { - NOMAD::Signature * cur_signature=poll_center.get_signature(); - int n = cur_signature->get_n(); - int n_cat=cur_signature->get_n_categorical(); + NOMAD::Signature * cur_signature = poll_center.get_signature(); + size_t n = cur_signature->get_n()-cur_signature->get_nb_fixed_variables() ; + + // No direction for categorical variables + size_t n_cat = cur_signature->get_n_categorical(); // Verify that enough directions for reduction are provided - if (static_cast<int>(dirs.size())<n-n_cat) + if ( dirs.size()<n-n_cat ) return false; // Maximum number of direction groups std::list<NOMAD::Direction>::iterator itDirs; - int maxDirGroupIndex=0; - int dgi; + size_t maxDirGroupIndex=0; + size_t dgi; for (itDirs=dirs.begin();itDirs!=dirs.end() ; ++itDirs) { dgi=(*itDirs).get_dir_group_index(); if (dgi>maxDirGroupIndex) maxDirGroupIndex=dgi; } - + + std::list<NOMAD::Direction> TmpDirs(dirs); + dirs.clear(); + // Loop on each direction group for (dgi=0;dgi<=maxDirGroupIndex;++dgi) { - + // Get all poll directions with a given direction group index + Get a vector of unique indices for those directions std::vector<NOMAD::Direction> pollDirs; std::vector<int> pollDirIndices; bool containsOrthoMads=false; - for (itDirs=dirs.begin();itDirs!=dirs.end() ; ++itDirs) + for (itDirs=TmpDirs.begin();itDirs!=TmpDirs.end() ; ++itDirs) { - if ((*itDirs).get_dir_group_index()==dgi) + if ( static_cast<size_t>((*itDirs).get_dir_group_index()) == dgi ) { pollDirs.push_back(*itDirs); pollDirIndices.push_back((*itDirs).get_index()); @@ -1819,9 +1903,10 @@ bool NOMAD::Mads::set_reduced_poll_to_n_directions(std::list<NOMAD::Direction> & } - // Sorted directions only if mesh_index_is_not_max - std::vector<NOMAD::Direction> sortedDirs(pollDirs); - if ( NOMAD::Mesh::mesh_index_is_not_max()) + std::list<NOMAD::Direction> sortedDirs; + std::list<NOMAD::Direction>::iterator itSortedDirs; + // Sort the directions only if mesh is not finest + if ( !_mesh->is_finest() ) { const std::set<NOMAD::Priority_Eval_Point> & LOP=_ev_control_for_sorting.get_eval_lop(); @@ -1830,20 +1915,26 @@ bool NOMAD::Mads::set_reduced_poll_to_n_directions(std::list<NOMAD::Direction> & throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , "Mads::set_reduced_poll_to_n_directions(): the _ev_control_for_sorting does not have a list of evaluation points." ); - + // Get all directions from ev_control ordered lop (list of evaluation points) with a given direction group index and given poll center - // Get a vector of unique indices for those directions - std::vector<int> sortedDirIndices; + // Get a set of unique indices of those directions + std::list<int> sortedDirIndices; + std::set<int> indices; + std::list<int>::iterator itSortedDirIndices; std::set<NOMAD::Priority_Eval_Point>::const_iterator citLOP; for (citLOP=LOP.begin();citLOP!=LOP.end();++citLOP) { const NOMAD::Eval_Point *eval_point=(*citLOP).get_point(); - if (eval_point->get_direction()->get_dir_group_index()==dgi && - *(eval_point->get_poll_center())==poll_center) - { - sortedDirIndices.push_back(eval_point->get_direction()->get_index()); - } - + if ( static_cast<size_t>(eval_point->get_direction()->get_dir_group_index()) == dgi && + *(eval_point->get_poll_center())==poll_center) + { + int index=eval_point->get_direction()->get_index(); + if ( indices.size() == 0 || indices.find(index) == indices.end() ) // if the index is already in indices no need to add it in sortedDirIndices to avoid duplicate. + sortedDirIndices.push_back(index); + indices.insert(index); // If the index is already in the set IT IS NOT INSERTED --> set of unique sort integers + + } + } if ( sortedDirIndices.size()==0 ) @@ -1854,57 +1945,69 @@ bool NOMAD::Mads::set_reduced_poll_to_n_directions(std::list<NOMAD::Direction> & // --> complete sorted direction with remaining directions in poll dirs // // 2 - Add poll directions (from tmpDirs) in the same order as sorted direction indices (from ev_control) - std::vector<int>::iterator itSortedDirIndices,itPollDirIndices; + std::vector<int>::iterator itPollDirIndices; std::vector<NOMAD::Direction>::iterator itPollDirs=pollDirs.begin(); - int pos,maxPos=0; - for (itPollDirIndices=pollDirIndices.begin();itPollDirIndices!=pollDirIndices.end();++itPollDirIndices,++itPollDirs) + size_t pos; + for ( itSortedDirIndices = sortedDirIndices.begin() ; itSortedDirIndices != sortedDirIndices.end() ; ++itSortedDirIndices) { - itSortedDirIndices=std::find(sortedDirIndices.begin(),sortedDirIndices.end(),(*itPollDirIndices)); - if (itSortedDirIndices!=sortedDirIndices.end()) + itPollDirIndices=find(pollDirIndices.begin(),pollDirIndices.end(),*itSortedDirIndices); + if ( itPollDirIndices!=pollDirIndices.end() ) { - pos=distance(sortedDirIndices.begin(),itSortedDirIndices); - sortedDirs[pos]=*itPollDirs; - if (pos > maxPos) maxPos=pos; + pos=distance(pollDirIndices.begin(),itPollDirIndices); + itPollDirs=pollDirs.begin(); + std::advance(itPollDirs,pos); + sortedDirs.push_back(*itPollDirs); } - else // Handle the case where poll direction not in sorted directions - sortedDirs[maxPos+1]=*itPollDirs; - } + } + // 3 - complete with remaining pollDirs directions + if ( sortedDirs.size() != pollDirs.size() ) + { + itPollDirs=pollDirs.begin(); + for ( itPollDirIndices = pollDirIndices.begin() ; itPollDirIndices != pollDirIndices.end() ; ++itPollDirIndices,++itPollDirs) + { + itSortedDirIndices=find(sortedDirIndices.begin(),sortedDirIndices.end(),*itPollDirIndices); + if ( itSortedDirIndices == sortedDirIndices.end() ) + // Handle the case where poll direction not in sorted directions --> put it at the end + sortedDirs.push_back(*itPollDirs); + } + } + } + else + sortedDirs.assign(pollDirs.begin(),pollDirs.end()); - // Make a spanning set of directions + // Make a spanning set of directions (this is slightly different Ortho n+1 paper but still we have the garantee that Dk grows asymptotically dense because D^o_k has not been sorted if mesh_index_is_max) // Sequentially add sorted directions that increase the rank in two situations: - // - If mesh_index_is_not_max -> consider all directions for adding -> n directions - // - If mesh index_is_max but some ORTHO MADS directions are present -> only consider ortho mads dir for adding -> n directions + // - If mesh is not finest -> consider all directions for adding -> n directions + // - If mesh is finest but some ORTHO MADS directions are present -> only consider ortho mads dir for adding -> n directions // - Else, all directions are considered -> more than n directions // See paper Ortho n+1 paper for details - std::vector<NOMAD::Direction>::iterator itSortedDirs; - dirs.clear(); - int currentRank=0; + + + size_t currentRank=get_rank_from_dirs(dirs); for (itSortedDirs=sortedDirs.begin();itSortedDirs!=sortedDirs.end();++itSortedDirs) { dirs.push_back(*itSortedDirs); - - if (NOMAD::Mesh::mesh_index_is_not_max() || (!NOMAD::Mesh::mesh_index_is_not_max() && containsOrthoMads)) + if ( !_mesh->is_finest() || ( _mesh->is_finest() && containsOrthoMads)) { - int rank=get_rank_from_dirs(dirs); + size_t rank=get_rank_from_dirs(dirs); if (rank>currentRank && rank<=n-n_cat && NOMAD::dir_is_orthomads((*itSortedDirs).get_type())) currentRank++; else dirs.pop_back(); } } - + } const NOMAD::Display & out = _p.out(); NOMAD::dd_type display_degree = out.get_poll_dd(); - - if ( static_cast<int>(dirs.size())!=n-n_cat ) + if ( dirs.size()!=n-n_cat ) { if (display_degree == NOMAD::FULL_DISPLAY ) { out << std::endl << NOMAD::open_block ( "The number of reduced directions is lower than n-n_categorical: "); - out << dirs.size() << std::endl; + out << dirs.size() << ". No reduction is performed." << std::endl; out << NOMAD::close_block(); } return false; @@ -1921,25 +2024,28 @@ int NOMAD::Mads::get_rank_from_dirs(const std::list<NOMAD::Direction> & dirs) return 0; std::list<NOMAD::Direction>::const_iterator it=dirs.begin(); - int m=(*it).size(); - int n=dirs.size(); + size_t m=(*it).size(); + size_t n=dirs.size(); double ** M = new double *[m]; - for (int i=0 ; i<m ; ++i ) { + for (size_t i=0 ; i<m ; ++i ) + { it=dirs.begin(); M[i] = new double[n]; - for (int j = 0 ; j < n ; ++j ){ - M[i][j] = (*it)[i].value() ; + for (size_t j = 0 ; j < n ; ++j ) + { + M[i][j] = (*it)[static_cast<int>(i)].value() ; ++it; } } int rank=NOMAD::get_rank(M,m,n); - for (int i = 0 ; i < m ; ++i ) { - delete M[i]; + for (size_t i = 0 ; i < m ; ++i ) + { + delete[] M[i]; } - delete M; + delete[] M; return rank; } @@ -1949,8 +2055,8 @@ int NOMAD::Mads::get_rank_from_dirs(const std::list<NOMAD::Direction> & dirs) /* (private) */ /*---------------------------------------------------------------------------------------*/ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll_center , - const std::list<NOMAD::Direction> & dirs , - NOMAD::Point & prospect_point ) + const std::list<NOMAD::Direction> & dirs , + NOMAD::Point & prospect_point ) { const NOMAD::Display & out = _p.out(); @@ -1961,18 +2067,17 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll // active cache: const NOMAD::Cache & cache = get_cache(); - // mesh index and poll size: - int mesh_index = NOMAD::Mesh::get_mesh_index(); - NOMAD::Point delta_p,delta_m; + NOMAD::Point delta,Delta; NOMAD::Signature * signature=poll_center.get_signature(); - signature->get_mesh().get_delta_p ( delta_p , mesh_index ); - signature->get_mesh().get_delta_m ( delta_m , mesh_index ); + _mesh->get_delta ( delta ); + _mesh->get_Delta ( Delta ); // compute the interpolation radius: points in Y must be at - // a max distance of ms_radius_factor times Delta^p_k: - NOMAD::Point interpolation_radius = delta_p; + // a max distance of ms_radius_factor times Delta^k: + NOMAD::Point interpolation_radius = Delta; interpolation_radius *= _p.get_model_quad_radius_factor(); + // Epsilon for quad model hypercube scaling NOMAD::Double epsilon = _p.get_model_np1_quad_epsilon(); @@ -1980,9 +2085,9 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll out << std::endl << NOMAD::open_block ( "Quadratic model for (n+1)th prospect point") << std::endl << "model construction for " << ev_type << std::endl << "nbr of cache pts: " << cache.size() << std::endl - << "mesh index : " << mesh_index << std::endl + << "mesh indices : ( " << _mesh->get_mesh_indices () << " )" << std::endl << "poll center : ( " << poll_center << " )" << std::endl - << "poll size : ( " << delta_p << " )" << std::endl + << "poll size : ( " << Delta << " )" << std::endl << "interpol. radius: ( " << interpolation_radius << " )" << std::endl << "epsilon hypercube: ( " << epsilon << " )" << std::endl;; #endif @@ -2022,7 +2127,7 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll #endif // define scaling with rotation: obtain an hypercube [0,1]^n formed by truncated directions - model.define_scaling_by_directions ( dirs, delta_m,epsilon); + model.define_scaling_by_directions ( dirs, delta ,epsilon); #ifdef DEBUG out << std::endl; @@ -2032,7 +2137,7 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll // error check: if ( model.get_error_flag() ) tmp_stats.add_construction_error(); - + // no model error: else { @@ -2049,7 +2154,7 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll model.display_Y_error ( out ); #endif - + // count model: if ( ev_type == NOMAD::TRUTH ) tmp_stats.add_nb_truth(); @@ -2099,9 +2204,6 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll // parameters creation: NOMAD::Parameters model_param ( out ); - // random seed: - model_param.set_SEED ( _p.get_seed() + 10 ); - // number of variables: model_param.set_DIMENSION ( n ); @@ -2114,7 +2216,7 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll // starting points: model_param.set_X0 ( NOMAD::Point ( n , 500.0 ) ); - + // fixed variables: for ( i = 0 ; i < n ; ++i ) if ( model.variable_is_fixed(i) || _p.variable_is_fixed(i) ) @@ -2128,14 +2230,12 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll // display: model_param.set_DISPLAY_DEGREE ( NOMAD::NO_DISPLAY ); - // mesh: - int mesh_index = NOMAD::Mesh::get_mesh_index(); - int min_mesh_index = NOMAD::Mesh::get_min_mesh_index(); - int max_mesh_index = NOMAD::Mesh::get_max_mesh_index(); - int max_halton_index = NOMAD::Mesh::get_max_halton_index(); - - NOMAD::Mesh::init ( 4.0 , 1 , -1 , 0 ); - + // mesh: use isotropic mesh + model_param.set_ANISOTROPIC_MESH ( false ); + model_param.set_MESH_UPDATE_BASIS ( 4.0 ); + model_param.set_MESH_COARSENING_EXPONENT ( 1 ); + model_param.set_MESH_REFINING_EXPONENT ( -1 ); + model_param.set_INITIAL_MESH_INDEX ( 0 ); model_param.set_INITIAL_MESH_SIZE ( NOMAD::Point ( n , 100.0 ) ); // maximum number of evaluations: @@ -2164,7 +2264,7 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll NOMAD::Point ub ( n , 1000.0 ); model_param.set_LOWER_BOUND ( lb ); model_param.set_UPPER_BOUND ( ub ); - + try { @@ -2176,33 +2276,30 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll if (model_param.get_nb_obj()==2) ev =new NOMAD::Multi_Obj_Quad_Model_Evaluator( model_param , model ); else - ev=new NOMAD::Single_Obj_Quad_Model_Evaluator(model_param, model); + ev=new NOMAD::Single_Obj_Quad_Model_Evaluator( model_param , model ); // algorithm creation and execution: NOMAD::Mads mads ( model_param , ev ); + + NOMAD::Phase_One_Evaluator * p1ev=NULL; + if ( model_param.get_nb_obj() >= 2 && ! flag_check_bimads ) + { + p1ev = new NOMAD::Phase_One_Evaluator ( model_param , *ev ); + mads.get_evaluator_control().set_evaluator ( p1ev ); + } NOMAD::stop_type st = mads.run(); delete ev; - + if (p1ev) + delete p1ev; + // reset flags: NOMAD::Mads::set_flag_check_bimads ( flag_check_bimads ); NOMAD::Mads::set_flag_reset_mesh ( flag_reset_mesh ); NOMAD::Mads::set_flag_reset_barriers ( flag_reset_barriers ); NOMAD::Mads::set_flag_p1_active ( flag_p1_active ); - // reset mesh to what it was before: - NOMAD::Mesh::init ( _p.get_mesh_update_basis().value() , - _p.get_mesh_coarsening_exponent() , - _p.get_mesh_refining_exponent() , - _p.get_initial_mesh_index() ); - - NOMAD::Mesh::set_max_halton_index ( max_halton_index ); - NOMAD::Mesh::set_mesh_index ( mesh_index ); - NOMAD::Mesh::set_min_mesh_index ( min_mesh_index ); - NOMAD::Mesh::set_max_mesh_index ( max_mesh_index ); - - // check the stopping criterion: if ( st == NOMAD::CTRL_C || st == NOMAD::MAX_CACHE_MEMORY_REACHED ) { std::ostringstream oss; @@ -2216,6 +2313,7 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll { NOMAD::Display out_tmp = out; out_tmp.set_degrees ( NOMAD::NORMAL_DISPLAY ); + out_tmp.open_block("Optimization results"); mads.display ( out_tmp ); } @@ -2288,13 +2386,14 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll out << "( " << prospect_point << " )" << std::endl; else out << "failure" << std::endl; - } - - if ( _p.get_display_degree() == NOMAD::FULL_DISPLAY ) - { + out << NOMAD::close_block() << std::endl; } +#ifdef DEBUG + out << NOMAD::close_block() << std::endl; +#endif + return !error; } @@ -2303,62 +2402,65 @@ bool NOMAD::Mads::optimize_quad_model ( const NOMAD::Eval_Point & poll /* set the poll directions based on signatures (private) */ /*----------------------------------------------------------------*/ void NOMAD::Mads::set_poll_directions ( std::list<NOMAD::Direction> & dirs , - NOMAD::poll_type i_pc , - int offset , - const NOMAD::Eval_Point & poll_center , - bool & stop , - NOMAD::stop_type & stop_reason ) + NOMAD::poll_type i_pc , + size_t offset , + const NOMAD::Eval_Point & poll_center , + bool & stop , + NOMAD::stop_type & stop_reason ) { - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_poll_dd(); - - std::list<NOMAD::Direction>::const_iterator it , end; - - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - if ( i_pc == NOMAD::SECONDARY ) - out << "secondary "; - out << "poll center: ( "; - poll_center.Point::display ( out, " ", 2, NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - } - - // get the poll center's signature: - NOMAD::Signature * cur_signature = poll_center.get_signature(); - - if ( !cur_signature ) - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , - "Mads::poll(): could not get the poll center's signature" ); - - int n = cur_signature->get_n(); - - if ( n != poll_center.size() ) - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , - "Mads::poll(): the poll center has an incompatible signature" ); + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_poll_dd(); + + std::list<NOMAD::Direction>::const_iterator it , end; + + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + if ( i_pc == NOMAD::SECONDARY ) + out << "secondary "; + out << "poll center: ( "; + poll_center.Point::display ( out, " ", 2, NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + + // get the poll center's signature: + NOMAD::Signature * cur_signature = poll_center.get_signature(); + + if ( !cur_signature ) + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , + "Mads::poll(): could not get the poll center's signature" ); + + int n = cur_signature->get_n(); + + if ( n != poll_center.size() ) + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , + "Mads::poll(): the poll center has an incompatible signature" ); + + // get directions from the signature: + cur_signature->get_directions ( dirs , + i_pc , + poll_center ); + - // get directions from the signature: - cur_signature->get_directions ( dirs , - i_pc , - poll_center , - NOMAD::Mesh::get_mesh_index() ); - - int k = 0; - for ( it = dirs.begin() ; it != dirs.end() ; ++it, k++ ) - it->set_index ( offset + k ); - - if ( !stop && dirs.empty() ) - { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "Mads::poll(): could not get directions: stop" - << std::endl << NOMAD::close_block() << std::endl; - stop = true; - stop_reason = NOMAD::MESH_PREC_REACHED; - return; + + size_t k = 0; + for ( it = dirs.begin() ; it != dirs.end() ; ++it, ++k ) + it->set_index ( static_cast<int>(offset + k) ); + - } - - // displays: + if ( !stop && dirs.empty() ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "Mads::poll(): could not get directions: stop" + << std::endl << NOMAD::close_block() << std::endl; + stop = true; + stop_reason = NOMAD::MESH_PREC_REACHED; + return; + + } + + + // displays: if ( display_degree == NOMAD::FULL_DISPLAY ) { end = dirs.end(); @@ -2386,7 +2488,7 @@ bool NOMAD::Mads::dirs_have_orthomads_np1( const std::list<NOMAD::Direction> & d { std::list<NOMAD::Direction>::const_iterator it , end = dirs.end(); for ( it = dirs.begin() ; it != end ; ++it ) - if ( (*it).get_type()==NOMAD::ORTHO_NP1_QUAD || + if ( (*it).get_type()==NOMAD::ORTHO_NP1_QUAD || (*it).get_type()==NOMAD::ORTHO_NP1_NEG) return true; return false; @@ -2412,13 +2514,12 @@ bool NOMAD::Mads::dir_from_model_opt( const std::list<NOMAD::Direction> & dirs) /* set the poll trial points based on poll directions (private) */ /*----------------------------------------------------------------*/ void NOMAD::Mads::set_poll_trial_points (std::list<NOMAD::Direction> &dirs, - int offset, + size_t offset, const NOMAD::Eval_Point & poll_center, bool & stop, NOMAD::stop_type &stop_reason, bool sorting) { - int mesh_index = NOMAD::Mesh::get_mesh_index(); NOMAD::Signature * cur_signature=poll_center.get_signature(); NOMAD::poll_center_type pc_type=( poll_center.is_feasible ( _p.get_h_min() ) ) ? NOMAD::FEASIBLE : NOMAD::INFEASIBLE; @@ -2434,7 +2535,6 @@ void NOMAD::Mads::set_poll_trial_points (std::list<NOMAD::Direction> &dirs, const NOMAD::Display & out = _p.out(); NOMAD::dd_type display_degree = out.get_poll_dd(); - int k=0; for ( it = dirs.begin() ; it != dirs.end() ; ++it ) { @@ -2445,23 +2545,14 @@ void NOMAD::Mads::set_poll_trial_points (std::list<NOMAD::Direction> &dirs, // equal to 1 with dir=1: the variables are set to 0 (1+1=0 in binary): for (int i = 0 ; i < n ; ++i ) (*pt)[i] = ( bbit[i]==NOMAD::BINARY && (*dir)[i]==1.0 && (poll_center)[i]==1.0 ) ? 0.0 : (*pt)[i] = (poll_center)[i] + (*dir)[i]; + - // we check that the new poll trial point is different than the poll center - // (this happens when the mesh size becomes too small): - if ( !stop && pt->Point::operator == ( poll_center ) ) - { + if ( pt->Point::operator == ( poll_center ) ) delete pt; - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "Mads::poll(): could not generate poll trial points: stop" - << std::endl << NOMAD::close_block() << std::endl; - stop = true; - stop_reason = NOMAD::MESH_PREC_REACHED; - return; - } - + else + { pt->set_signature ( cur_signature ); pt->set_direction ( dir ); - pt->set_mesh_index ( &mesh_index ); pt->set_poll_center_type ( pc_type ); pt->set_poll_center ( &poll_center ); @@ -2472,7 +2563,7 @@ void NOMAD::Mads::set_poll_trial_points (std::list<NOMAD::Direction> &dirs, NOMAD::Random_Pickup rp ( nb_dirs ); pt->set_rand_eval_priority ( rp.pickup() ); } - + if (!sorting) _ev_control.add_eval_point ( pt , display_degree , @@ -2491,10 +2582,21 @@ void NOMAD::Mads::set_poll_trial_points (std::list<NOMAD::Direction> &dirs, NOMAD::Double() , NOMAD::Double() ); } - + ++k; + } } + if ( k==0 ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "Mads::poll(): could not generate poll trial points: stop" + << std::endl << NOMAD::close_block() << std::endl; + stop = true; + stop_reason = NOMAD::MESH_PREC_REACHED; + } + + return; } @@ -2503,36 +2605,38 @@ void NOMAD::Mads::set_poll_trial_points (std::list<NOMAD::Direction> &dirs, /* compute the poll directions dynamically (private) */ /*-------------------------------------------------------------*/ bool NOMAD::Mads::get_dynamic_directions (const std::list<NOMAD::Direction> & dirs, - std::list<NOMAD::Direction> & newDirs, - const NOMAD::Eval_Point & poll_center ) + std::list<NOMAD::Direction> & newDirs, + const NOMAD::Eval_Point & poll_center ) { const NOMAD::Signature * cur_signature=poll_center.get_signature(); - int n=cur_signature->get_n(); - int n_cat=cur_signature->get_n_categorical(); + size_t n = cur_signature->get_n()-cur_signature->get_nb_fixed_variables(); + size_t n_cat = cur_signature->get_n_categorical(); const NOMAD::Display & out = _p.out(); NOMAD::dd_type display_degree = out.get_poll_dd(); // Dynamic completion only if sufficient directions provided: (n-n_cat)->(n-n_cat)+1 - if (static_cast<int>(dirs.size())<n-n_cat) + if ( dirs.size() < n-n_cat ) return false; - + // Get the maximum number of direction groups std::list<NOMAD::Direction>::const_iterator itDir; int maxDirGroupIndex=0; int dgi; - for (itDir=dirs.begin();itDir!=dirs.end() ; ++itDir) { + for (itDir=dirs.begin();itDir!=dirs.end() ; ++itDir) + { dgi=(*itDir).get_dir_group_index(); - if (dgi>maxDirGroupIndex) maxDirGroupIndex=dgi; + if (dgi>maxDirGroupIndex) + maxDirGroupIndex=dgi; } // Loop on each direction group to obtain a new direction for (dgi=0;dgi<=maxDirGroupIndex;++dgi) { int maxIndex=0; - + // 1 - Search directions having the same direction group index std::list<NOMAD::Direction> rDirs; std::list<NOMAD::Double>::iterator it_fv; @@ -2541,7 +2645,7 @@ bool NOMAD::Mads::get_dynamic_directions (const std::list<NOMAD::Direction> & di if ((*itDir).get_index()>maxIndex) maxIndex=(*itDir).get_index(); if ((*itDir).get_dir_group_index()==dgi) - rDirs.push_back(*itDir); + rDirs.push_back(*itDir); } // 2 - add a dynamic direction from a quad model optimization or sum of direction negatives @@ -2553,18 +2657,27 @@ bool NOMAD::Mads::get_dynamic_directions (const std::list<NOMAD::Direction> & di } } - if ( display_degree == NOMAD::FULL_DISPLAY ) { - out << std::endl - << NOMAD::open_block ( "Added (n+1)th poll direction(s) (include mesh size parameter)" ); - for ( itDir = newDirs.begin() ; itDir != newDirs.end() ; ++itDir ) { + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + out << std::endl; + if ( newDirs.size()!= 0 ) + out << NOMAD::open_block ( "Added (n+1)th poll direction(s) (include mesh size parameter)" ); + else + out << NOMAD::open_block ( "Cannot generate a (n+1)th poll direction" ); + + for ( itDir = newDirs.begin() ; itDir != newDirs.end() ; ++itDir ) + { out << "dir "; - out.display_int_w ( (*itDir).get_index() , newDirs.size() ); + out.display_int_w ( (*itDir).get_index() , static_cast<int>(newDirs.size()) ); out << " : " << *itDir << std::endl; } out.close_block(); out << std::endl; } + + if ( newDirs.size()==0 ) + return false; return true; @@ -2581,13 +2694,13 @@ bool NOMAD::Mads::get_dynamic_directions (const std::list<NOMAD::Direction> & di /* function evaluations in Mesh Adaptive Direct Search Algorithms*/ /*----------------------------------------------------------------*/ NOMAD::Direction NOMAD::Mads::get_single_dynamic_direction (const std::list<NOMAD::Direction> & dirs, - const NOMAD::Eval_Point & poll_center) + const NOMAD::Eval_Point & poll_center) { const NOMAD::Signature * cur_signature=poll_center.get_signature(); int n=cur_signature->get_n(); NOMAD::Direction Vb1( n , 0.0 ,NOMAD::UNDEFINED_DIRECTION); - + std::vector<NOMAD::Double> alpha; NOMAD::Double f_pc=(poll_center.is_feasible(_p.get_h_min())) ? poll_center.get_f():poll_center.get_h(); @@ -2622,15 +2735,15 @@ NOMAD::Direction NOMAD::Mads::get_single_dynamic_direction (const std::list<NOMA // Update the new directions depending on the input_types const std::vector<NOMAD::bb_input_type> & input_types=cur_signature->get_input_types(); - int mesh_index = NOMAD::Mesh::get_mesh_index(); - NOMAD::Point delta_p; - cur_signature->get_mesh().get_delta_p ( delta_p , mesh_index ); - NOMAD::Point delta_m; - cur_signature->get_mesh().get_delta_m ( delta_m , mesh_index ); + + NOMAD::Point delta,Delta; + _mesh->get_delta ( delta ); + _mesh->get_Delta ( Delta ); bool isZero=true; for (int i=0; i<n; ++i) { - NOMAD::Double v=V[i].value(),vb1=Vb1[i].value(),dm=delta_m[i].value(),dp=delta_p[i].value(); + NOMAD::Double v=V[i].value(),vb1=Vb1[i].value(),dm=delta[i].value(),dp=Delta[i].value(); + // Continous variables ---> rounding towards mesh node. if (input_types[i]==NOMAD::CONTINUOUS) { @@ -2680,48 +2793,55 @@ NOMAD::Direction NOMAD::Mads::get_single_dynamic_direction (const std::list<NOMA /*----------------------------------------------------------------*/ void NOMAD::Mads::check_directions ( bool & forbid_poll_size_stop ) { - if ( !_p.get_min_poll_size_defined() ) { - - NOMAD::Double v , min; - const NOMAD::Point * dir; - int i , n; - - const NOMAD::Signature * signature; - - const std::set<NOMAD::Priority_Eval_Point> & poll_pts = _ev_control.get_eval_lop(); - std::set<NOMAD::Priority_Eval_Point>::const_iterator end = poll_pts.end() , it; - for ( it = poll_pts.begin() ; it != end ; ++it ) { - - signature = it->get_point()->get_signature(); - - if ( signature ) { - - dir = it->get_point()->get_direction(); - - if ( dir ) { - - n = dir->size(); - - if ( n == signature->get_n() ) { - - const std::vector<NOMAD::bb_input_type> & bbit - = signature->get_input_types(); - - for ( i = 0 ; i < n ; ++i ) { - if ( bbit[i] == NOMAD::INTEGER ) { - v = (*dir)[i].abs(); - if ( v.is_defined() && v > 0.0 && ( !min.is_defined() || v < min ) ) - min = v; - } - } - } - } - } - } - - if ( min.is_defined() && min > 1.0 ) - forbid_poll_size_stop = true; - } + if ( !_p.get_min_poll_size_defined() ) + { + + NOMAD::Double v , min; + const NOMAD::Point * dir; + int i , n; + + const NOMAD::Signature * signature; + + const std::set<NOMAD::Priority_Eval_Point> & poll_pts = _ev_control.get_eval_lop(); + std::set<NOMAD::Priority_Eval_Point>::const_iterator end = poll_pts.end() , it; + for ( it = poll_pts.begin() ; it != end ; ++it ) + { + + signature = it->get_point()->get_signature(); + + if ( signature ) + { + + dir = it->get_point()->get_direction(); + + if ( dir ) + { + + n = dir->size(); + + if ( n == signature->get_n() ) + { + + const std::vector<NOMAD::bb_input_type> & bbit + = signature->get_input_types(); + + for ( i = 0 ; i < n ; ++i ) + { + if ( bbit[i] == NOMAD::INTEGER ) + { + v = (*dir)[i].abs(); + if ( v.is_defined() && v > 0.0 && ( !min.is_defined() || v < min ) ) + min = v; + } + } + } + } + } + } + + if ( min.is_defined() && min > 1.0 ) + forbid_poll_size_stop = true; + } } /*---------------------------------------------------------*/ @@ -2731,23 +2851,23 @@ void NOMAD::Mads::check_directions ( bool & forbid_poll_size_stop ) void NOMAD::Mads::update_success_directions ( const NOMAD::Eval_Point * new_inc , bool feasible ) const { - if ( new_inc && new_inc->get_direction() ) + if ( new_inc && new_inc->get_direction() ) { - - const NOMAD::Direction * dir = new_inc->get_direction(); - NOMAD::Signature * signature = new_inc->get_signature(); + const NOMAD::Direction * dir = new_inc->get_direction(); + NOMAD::Signature * signature = new_inc->get_signature(); - if ( !signature ) - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , - "Mads::update_success_directions(): new incumbent has no signature" ); - - if ( feasible ) - new_inc->get_signature()->set_feas_success_dir ( *dir ); - else - new_inc->get_signature()->set_infeas_success_dir ( *dir ); - - } + + if ( !signature ) + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , + "Mads::update_success_directions(): new incumbent has no signature" ); + + if ( feasible ) + new_inc->get_signature()->set_feas_success_dir ( *dir ); + else + new_inc->get_signature()->set_infeas_success_dir ( *dir ); + + } } @@ -2760,240 +2880,259 @@ void NOMAD::Mads::search ( bool & stop , const NOMAD::Eval_Point *& new_feas_inc , const NOMAD::Eval_Point *& new_infeas_inc ) { - int nb_search_pts; - bool count_search; - int mads_iteration = _stats.get_iterations(); - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_search_dd(); - NOMAD::success_type last_it_success = success; - success = NOMAD::UNSUCCESSFUL; - - // first display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::open_block ( "MADS search" ); - - // 1. speculative search: - if ( _p.get_speculative_search() ) - { - if ( new_feas_inc || new_infeas_inc ) + int nb_search_pts; + bool count_search; + int mads_iteration = _stats.get_iterations(); + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_search_dd(); + NOMAD::success_type last_it_success = success; + success = NOMAD::UNSUCCESSFUL; + + // first display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << NOMAD::open_block ( "MADS search" ); + + // 1. speculative search: + if ( _p.get_speculative_search() ) { - Speculative_Search ss ( _p ); - - ss.search ( *this , - nb_search_pts , - stop , - stop_reason , - success , - count_search , - new_feas_inc , - new_infeas_inc ); - - if ( success == NOMAD::FULL_SUCCESS ) - _stats.add_spec_success(); - if ( count_search ) - _stats.add_nb_spec_searches(); - _stats.add_spec_pts ( nb_search_pts ); - } - } - - // 2. user search: - if ( success != NOMAD::FULL_SUCCESS && _user_search ) { - - // initial user search display: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << NOMAD::USER_SEARCH; - out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; - } - - // the search: - _user_search->search ( *this , - nb_search_pts , - stop , - stop_reason , - success , - count_search , - new_feas_inc , - new_infeas_inc ); - - // update stats: - if ( success == NOMAD::FULL_SUCCESS ) - _stats.add_usr_srch_success(); - if ( count_search ) - _stats.add_nb_usr_searches(); - _stats.add_usr_srch_pts ( nb_search_pts ); - - // final user search display: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "end of " << NOMAD::USER_SEARCH << " (" << success << ")"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } - } - - // 3. cache search: - if ( success != NOMAD::FULL_SUCCESS && _p.get_cache_search() ) { - - // the search: - _cache_search->search ( *this , - nb_search_pts , - stop , - stop_reason , - success , - count_search , - new_feas_inc , - new_infeas_inc ); - - // update stats: - if ( success == NOMAD::FULL_SUCCESS ) - _stats.add_CS_success(); - if ( count_search ) - _stats.add_nb_cache_searches(); - _stats.add_CS_pts ( nb_search_pts ); - } - - // 4. Model Searches (stats are updated inside the searches): - if ( success != NOMAD::FULL_SUCCESS && _p.has_model_search() ) { - + if ( new_feas_inc || new_infeas_inc ) + { + Speculative_Search ss ( _p ); + + ss.search ( *this , + nb_search_pts , + stop , + stop_reason , + success , + count_search , + new_feas_inc , + new_infeas_inc ); + + if ( success == NOMAD::FULL_SUCCESS ) + _stats.add_spec_success(); + if ( count_search ) + _stats.add_nb_spec_searches(); + _stats.add_spec_pts ( nb_search_pts ); + } + } + + // 2. user search: + if ( success != NOMAD::FULL_SUCCESS && _user_search ) + { + + // initial user search display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << NOMAD::USER_SEARCH; + out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; + } + + // the search: + _user_search->search ( *this , + nb_search_pts , + stop , + stop_reason , + success , + count_search , + new_feas_inc , + new_infeas_inc ); + + // update stats: + if ( success == NOMAD::FULL_SUCCESS ) + _stats.add_usr_srch_success(); + if ( count_search ) + _stats.add_nb_usr_searches(); + _stats.add_usr_srch_pts ( nb_search_pts ); + + // final user search display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "end of " << NOMAD::USER_SEARCH << " (" << success << ")"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } + } + + // 3. cache search: + if ( success != NOMAD::FULL_SUCCESS && _p.get_cache_search() ) + { + + // the search: + _cache_search->search ( *this , + nb_search_pts , + stop , + stop_reason , + success , + count_search , + new_feas_inc , + new_infeas_inc ); + + // update stats: + if ( success == NOMAD::FULL_SUCCESS ) + _stats.add_CS_success(); + if ( count_search ) + _stats.add_nb_cache_searches(); + _stats.add_CS_pts ( nb_search_pts ); + } + + // 4. Model Searches (stats are updated inside the searches): + if ( success != NOMAD::FULL_SUCCESS && _p.has_model_search() ) + { + #ifdef USE_MPI - // asynchronous mode: wait for the evaluations in progress: - if ( _p.get_asynchronous() ) { - std::list<const NOMAD::Eval_Point *> evaluated_pts; - _ev_control.wait_for_evaluations ( NOMAD::ASYNCHRONOUS , - _true_barrier , - _sgte_barrier , - _pareto_front , - stop , - stop_reason , - success , - evaluated_pts ); - } + // asynchronous mode: wait for the evaluations in progress: + if ( _p.get_asynchronous() ) + { + std::list<const NOMAD::Eval_Point *> evaluated_pts; + _ev_control.wait_for_evaluations ( NOMAD::ASYNCHRONOUS , + _true_barrier , + _sgte_barrier , + _pareto_front , + stop , + stop_reason , + success , + evaluated_pts ); + } #endif - - // model search #1: - _model_search1->search ( *this , - nb_search_pts , - stop , - stop_reason , - success , - count_search , - new_feas_inc , - new_infeas_inc ); - - // save the TGP model for the model ordering: - if ( _p.get_model_search(1) == NOMAD::TGP_MODEL ) { + + // model search #1: + _model_search1->search ( *this , + nb_search_pts , + stop , + stop_reason , + success , + count_search , + new_feas_inc , + new_infeas_inc ); + + // save the TGP model for the model ordering: + if ( _p.get_model_search(1) == NOMAD::TGP_MODEL ) + { #ifdef USE_TGP - _ev_control.set_last_TGP_model - ( static_cast<NOMAD::TGP_Model_Search *>(_model_search1)->get_model() ); + _ev_control.set_last_TGP_model + ( static_cast<NOMAD::TGP_Model_Search *>(_model_search1)->get_model() ); #endif - } - // model search #2: - if ( success != NOMAD::FULL_SUCCESS && _model_search2 ) { - + } + // model search #2: + if ( success != NOMAD::FULL_SUCCESS && _model_search2 ) + { + #ifdef USE_MPI - // asynchronous mode: wait for the evaluations in progress: - if ( _p.get_asynchronous() ) { - std::list<const NOMAD::Eval_Point *> evaluated_pts; - _ev_control.wait_for_evaluations ( NOMAD::ASYNCHRONOUS , - _true_barrier , - _sgte_barrier , - _pareto_front , - stop , - stop_reason , - success , - evaluated_pts ); - } + // asynchronous mode: wait for the evaluations in progress: + if ( _p.get_asynchronous() ) + { + std::list<const NOMAD::Eval_Point *> evaluated_pts; + _ev_control.wait_for_evaluations ( NOMAD::ASYNCHRONOUS , + _true_barrier , + _sgte_barrier , + _pareto_front , + stop , + stop_reason , + success , + evaluated_pts ); + } #endif - _model_search2->search ( *this , - nb_search_pts , - stop , - stop_reason , - success , - count_search , - new_feas_inc , - new_infeas_inc ); - - // save the TGP model for the model ordering: - if ( _p.get_model_search(2) == NOMAD::TGP_MODEL ) { + _model_search2->search ( *this , + nb_search_pts , + stop , + stop_reason , + success , + count_search , + new_feas_inc , + new_infeas_inc ); + + // save the TGP model for the model ordering: + if ( _p.get_model_search(2) == NOMAD::TGP_MODEL ) + { #ifdef USE_TGP - _ev_control.set_last_TGP_model - ( static_cast<NOMAD::TGP_Model_Search *>(_model_search2)->get_model() ); + _ev_control.set_last_TGP_model + ( static_cast<NOMAD::TGP_Model_Search *>(_model_search2)->get_model() ); #endif - } - } - } - - // 5. VNS search: - if ( _p.get_VNS_search() && - success != NOMAD::FULL_SUCCESS && - last_it_success == NOMAD::UNSUCCESSFUL && - NOMAD::Mesh::get_mesh_index() >= 0 && - _stats.get_iterations() > 0 ) { - - // check the VNS_trigger criterion: - int bbe = _stats.get_bb_eval(); - if ( bbe==0 || - _stats.get_VNS_bb_eval() / static_cast<float>(bbe) < _p.get_VNS_trigger() ) { - + } + } + } + + // 5. VNS search: + if ( _p.get_VNS_search() && + success != NOMAD::FULL_SUCCESS && + last_it_success == NOMAD::UNSUCCESSFUL && + _mesh->is_finer_than_initial() && + _stats.get_iterations() > 0 ) + { + + // check the VNS_trigger criterion: + int bbe = _stats.get_bb_eval(); + if ( bbe==0 || + _stats.get_VNS_bb_eval() / static_cast<float>(bbe) < _p.get_VNS_trigger() ) + { + #ifdef USE_MPI - // asynchronous mode: wait for the evaluations in progress: - if ( _p.get_asynchronous() ) { - std::list<const NOMAD::Eval_Point *> evaluated_pts; - _ev_control.wait_for_evaluations ( NOMAD::ASYNCHRONOUS , - _true_barrier , - _sgte_barrier , - _pareto_front , - stop , - stop_reason , - success , - evaluated_pts ); - } + // asynchronous mode: wait for the evaluations in progress: + if ( _p.get_asynchronous() ) + { + std::list<const NOMAD::Eval_Point *> evaluated_pts; + _ev_control.wait_for_evaluations ( NOMAD::ASYNCHRONOUS , + _true_barrier , + _sgte_barrier , + _pareto_front , + stop , + stop_reason , + success , + evaluated_pts ); + } #endif - - _VNS_search->search ( *this , - nb_search_pts , - stop , - stop_reason , - success , - count_search , - new_feas_inc , - new_infeas_inc ); - - if ( success == NOMAD::FULL_SUCCESS ) - _stats.add_VNS_success(); - if ( count_search ) - _stats.add_nb_VNS_searches(); - _stats.add_VNS_pts ( nb_search_pts ); - } - } - - // 6. Latin-Hypercube (LH) search: - if ( success != NOMAD::FULL_SUCCESS && _p.get_LH_search_pi() > 0 ) { - - // for the first iteration: do not perform the - // search if there was an initial LH search: - if ( mads_iteration > 0 || _p.get_LH_search_p0() <= 0 ) { - - LH_Search lh ( _p , false , _flag_p1_active ); - - lh.search ( *this , - nb_search_pts , - stop , - stop_reason , - success , - count_search , - new_feas_inc , - new_infeas_inc ); - if ( success == NOMAD::FULL_SUCCESS ) - _stats.add_LH_success(); - if ( count_search ) - _stats.add_nb_LH_searches(); - _stats.add_LH_pts ( nb_search_pts ); - } - } - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << NOMAD::close_block ( "end of search" ); + + _VNS_search->search ( *this , + nb_search_pts , + stop , + stop_reason , + success , + count_search , + new_feas_inc , + new_infeas_inc ); + + if ( success == NOMAD::FULL_SUCCESS ) + _stats.add_VNS_success(); + + if ( count_search ) + _stats.add_nb_VNS_searches(); + + _stats.add_VNS_pts ( nb_search_pts ); + } + } + + // 6. Latin-Hypercube (LH) search: + if ( success != NOMAD::FULL_SUCCESS && _p.get_LH_search_pi() > 0 ) + { + + // for the first iteration: do not perform the + // search if there was an initial LH search: + if ( mads_iteration > 0 || _p.get_LH_search_p0() <= 0 ) { + + LH_Search lh ( _p , false , _flag_p1_active ); + + lh.search ( *this , + nb_search_pts , + stop , + stop_reason , + success , + count_search , + new_feas_inc , + new_infeas_inc ); + + if ( success == NOMAD::FULL_SUCCESS ) + _stats.add_LH_success(); + + if ( count_search ) + _stats.add_nb_LH_searches(); + + _stats.add_LH_pts ( nb_search_pts ); + } + } + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << NOMAD::close_block ( "end of search" ); } /*---------------------------------------------------------*/ @@ -3002,195 +3141,201 @@ void NOMAD::Mads::search ( bool & stop , void NOMAD::Mads::eval_x0 ( bool & stop , NOMAD::stop_type & stop_reason ) { - const std::vector<NOMAD::Point *> & x0s = _p.get_x0s(); - const std::string & x0_cache_file = _p.get_x0_cache_file(); - if ( x0s.empty() && x0_cache_file.empty() ) - return; - - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_gen_dd(); - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::open_block ( "starting point evaluation" ); - - NOMAD::Eval_Point * pt; - size_t k; - int m = _p.get_bb_nb_outputs(); - int n = _p.get_dimension(); - std::ostringstream err; - - // x0s from vector Parameters::_x0s: - // --------------------------------- - size_t x0s_size = x0s.size(); - for ( k = 0 ; k < x0s_size ; ++k ) { - - // the current starting point has to be in dimension n: - if ( x0s[k]->size() != n ) { - err << "starting point ( " << *x0s[k] << " ) is not of dimension " << n; - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , err.str() ); - } - - // creation of the Eval_Point: - pt = new NOMAD::Eval_Point; - pt->set ( *x0s[k] , m ); - pt->set_signature ( _p.get_signature() ); - - _ev_control.add_eval_point ( pt , - display_degree , - false , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() ); - } - - // x0 from a cache file: - // --------------------- - if ( !x0_cache_file.empty() ) { - - NOMAD::Cache & cache = _ev_control.get_cache(); - const NOMAD::Eval_Point * x; - - // another cache file (this file won't be modified): - if ( x0_cache_file != _p.get_cache_file() ) { - - NOMAD::Cache x0_cache ( out , ( _p.get_opt_only_sgte() ) ? NOMAD::SGTE : - NOMAD::TRUTH ); - std::string file_name = _p.get_problem_dir() + x0_cache_file; - - if ( !x0_cache.load ( file_name , NULL , display_degree==NOMAD::FULL_DISPLAY ) ) { - err << "could not load (or create) the cache file " << file_name; - throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , err.str() ); - } - - // we copy all the temporary cache points - // into the list of points to be evaluated: - x = x0_cache.begin(); - while ( x ) { - - pt = new NOMAD::Eval_Point; - pt->set ( *x , m ); - - if ( x->get_signature() ) - pt->set_signature ( x->get_signature() ); - else if ( x->size() == n ) - pt->set_signature ( _p.get_signature() ); - - if ( pt->get_signature() ) - _ev_control.add_eval_point ( pt , - display_degree , - false , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() ); - else { - if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) - out << std::endl << "Warning (" << "Mads.cpp" << ", " << __LINE__ - << "): could not use the starting point " << *pt - << " (no signature)" << std::endl << std::endl; - delete pt; + const std::vector<NOMAD::Point *> & x0s = _p.get_x0s(); + const std::string & x0_cache_file = _p.get_x0_cache_file(); + if ( x0s.empty() && x0_cache_file.empty() ) + return; + + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_gen_dd(); + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << NOMAD::open_block ( "starting point evaluation" ); + + NOMAD::Eval_Point * pt; + size_t k; + int m = _p.get_bb_nb_outputs(); + int n = _p.get_dimension(); + std::ostringstream err; + + // x0s from vector Parameters::_x0s: + // --------------------------------- + size_t x0s_size = x0s.size(); + for ( k = 0 ; k < x0s_size ; ++k ) + { + + // the current starting point has to be in dimension n: + if ( x0s[k]->size() != n ) + { + err << "starting point ( " << *x0s[k] << " ) is not of dimension " << n; + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , err.str() ); + } + + // creation of the Eval_Point: + pt = new NOMAD::Eval_Point; + pt->set ( *x0s[k] , m ); + pt->set_signature ( _p.get_signature() ); + + _ev_control.add_eval_point ( pt , + display_degree , + false , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() ); } - - x = x0_cache.next(); - } - - // insertion of this temporary cache in the algorithm's cache: - cache.insert ( x0_cache ); - } - - // x0 cache file and the algorithm's cache file are the same: - else { - - x = cache.begin(); - while ( x ) { - pt = &NOMAD::Cache::get_modifiable_point ( *x ); - - if ( x->get_signature() ) - pt->set_signature ( x->get_signature() ); - else if ( x->size() == n ) - pt->set_signature ( _p.get_signature() ); - - if ( pt->get_signature() ) - _ev_control.add_eval_point ( pt , - display_degree , - false , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() ); - else { - if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) - out << std::endl << "Warning (" << "Mads.cpp" << ", " << __LINE__ - << "): could not use the starting point " << *pt - << "(no signature)" << std::endl; + + // x0 from a cache file: + // --------------------- + if ( !x0_cache_file.empty() ) + { + + NOMAD::Cache & cache = _ev_control.get_cache(); + const NOMAD::Eval_Point * x; + + // another cache file (this file won't be modified): + if ( x0_cache_file != _p.get_cache_file() ) + { + + NOMAD::Cache x0_cache ( out , ( _p.get_opt_only_sgte() ) ? NOMAD::SGTE : NOMAD::TRUTH ); + std::string file_name = _p.get_problem_dir() + x0_cache_file; + + if ( !x0_cache.load ( file_name , NULL , display_degree==NOMAD::FULL_DISPLAY ) ) + { + err << "could not load (or create) the cache file " << file_name; + throw NOMAD::Exception ( "Mads.cpp" , __LINE__ , err.str() ); + } + + // we copy all the temporary cache points + // into the list of points to be evaluated: + x = x0_cache.begin(); + while ( x ) + { + + pt = new NOMAD::Eval_Point; + pt->set ( *x , m ); + + if ( x->get_signature() ) + pt->set_signature ( x->get_signature() ); + else if ( x->size() == n ) + pt->set_signature ( _p.get_signature() ); + + if ( pt->get_signature() ) + _ev_control.add_eval_point ( pt , + display_degree , + false , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() ); + else + { + if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) + out << std::endl << "Warning (" << "Mads.cpp" << ", " << __LINE__ + << "): could not use the starting point " << *pt + << " (no signature)" << std::endl << std::endl; + delete pt; + } + + x = x0_cache.next(); + } + + // insertion of this temporary cache in the algorithm's cache: + cache.insert ( x0_cache ); + } + + // x0 cache file and the algorithm's cache file are the same: + else { + + x = cache.begin(); + while ( x ) { + pt = &NOMAD::Cache::get_modifiable_point ( *x ); + + if ( x->get_signature() ) + pt->set_signature ( x->get_signature() ); + else if ( x->size() == n ) + pt->set_signature ( _p.get_signature() ); + + if ( pt->get_signature() ) + _ev_control.add_eval_point ( pt , + display_degree , + false , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() ); + else { + if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) + out << std::endl << "Warning (" << "Mads.cpp" << ", " << __LINE__ + << "): could not use the starting point " << *pt + << "(no signature)" << std::endl; + } + x = cache.next(); + } + } } - x = cache.next(); - } - } - } - - // display of all starting points: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - - const std::set<NOMAD::Priority_Eval_Point> & pts = _ev_control.get_eval_lop(); - - // one starting point: - if ( pts.size() == 1 ) { - out << std::endl << "x0 eval point: ( "; - pts.begin()->get_point()->Point::display ( out , - " " , - 2 , - NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - } - - // several starting points: - else - _ev_control.display_eval_lop ( NOMAD::X0_EVAL ); - } - - NOMAD::success_type success; - const NOMAD::Eval_Point * new_feas_inc = NULL; - const NOMAD::Eval_Point * new_infeas_inc = NULL; - - // eval_list_of_points (x0): - // ------------------------- - _ev_control.eval_list_of_points ( NOMAD::X0_EVAL , - _true_barrier , - _sgte_barrier , - _pareto_front , - stop , - stop_reason , - new_feas_inc , - new_infeas_inc , - success ); - if ( !stop && - ( success == NOMAD::UNSUCCESSFUL || - (!new_feas_inc && !new_infeas_inc ) || - ( _p.get_barrier_type() == NOMAD::EB && - !get_active_barrier().get_best_feasible() ) ) ) { - stop = true; - stop_reason = NOMAD::X0_FAIL; - } - - - // displays: - display_iteration_end ( stop , - stop_reason , - success , - new_feas_inc , - new_infeas_inc ); - - // stop the algorithm if no iterations are allowed: - if ( !stop && _p.get_max_iterations() == 0 ) - { - stop = true; - stop_reason = NOMAD::MAX_ITER_REACHED; - } - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::close_block ( "end of starting point evaluation" ); + + // display of all starting points: + if ( display_degree == NOMAD::FULL_DISPLAY ) { + + const std::set<NOMAD::Priority_Eval_Point> & pts = _ev_control.get_eval_lop(); + + // one starting point: + if ( pts.size() == 1 ) { + out << std::endl << "x0 eval point: ( "; + pts.begin()->get_point()->Point::display ( out , + " " , + 2 , + NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + + // several starting points: + else + _ev_control.display_eval_lop ( NOMAD::X0_EVAL ); + } + + NOMAD::success_type success; + const NOMAD::Eval_Point * new_feas_inc = NULL; + const NOMAD::Eval_Point * new_infeas_inc = NULL; + + // eval_list_of_points (x0): + // ------------------------- + _ev_control.eval_list_of_points ( NOMAD::X0_EVAL , + _true_barrier , + _sgte_barrier , + _pareto_front , + stop , + stop_reason , + new_feas_inc , + new_infeas_inc , + success ); + if ( !stop && + ( success == NOMAD::UNSUCCESSFUL || + (!new_feas_inc && !new_infeas_inc ) || + ( _p.get_barrier_type() == NOMAD::EB && + !get_active_barrier().get_best_feasible() ) ) ) { + stop = true; + stop_reason = NOMAD::X0_FAIL; + } + + + // displays: + display_iteration_end ( stop , + stop_reason , + success , + new_feas_inc , + new_infeas_inc ); + + // stop the algorithm if no iterations are allowed: + if ( !stop && _p.get_max_iterations() == 0 ) + { + stop = true; + stop_reason = NOMAD::MAX_ITER_REACHED; + } + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << NOMAD::close_block ( "end of starting point evaluation" ); } /*---------------------------------------------------------*/ @@ -3198,69 +3343,72 @@ void NOMAD::Mads::eval_x0 ( bool & stop , /*---------------------------------------------------------*/ void NOMAD::Mads::display_pareto_front ( void ) const { - if ( !_pareto_front ) - return; - - const std::string & stats_file_name = _p.get_stats_file_name(); - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_gen_dd(); - - // loop on the Pareto points: - if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) - out << std::endl << NOMAD::open_block ( "Pareto front" ) << std::endl; - - const NOMAD::Eval_Point * cur = _pareto_front->begin(); - while ( cur ) { - - if ( cur->is_eval_ok() && cur->is_feasible ( _p.get_h_min() ) ) { - - const std::list<int> & index_obj = _p.get_index_obj(); - std::list<int>::const_iterator it , end = index_obj.end(); - const NOMAD::Point & bbo = cur->get_bb_outputs(); - int i = 0; - NOMAD::Point multi_obj ( static_cast<int>(index_obj.size()) ); - - for ( it = index_obj.begin() ; it != end ; ++it ) - multi_obj[i++] = bbo[*it]; - - if ( !stats_file_name.empty() ) - _ev_control.stats_file ( stats_file_name , cur , true , &multi_obj ); - - if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY && !_p.get_display_stats().empty() ) - _ev_control.display_stats ( false , - out , - _p.get_display_stats() , - cur , - true , - &multi_obj ); - } - cur = _pareto_front->next(); - } - - if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) - out << NOMAD::close_block(); - - // other stats: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - - out << std::endl << "number of pts : " << _pareto_front->size() << std::endl; - - NOMAD::Double delta , surf; - _pareto_front->get_delta_surf ( delta , surf , - _p.get_multi_f_bounds() ); // f1_min, f1_max, - // f2_min, f2_max - out << "delta_j : " << delta << std::endl - << "surf : "; - if ( surf.is_defined() ) - out << 100*surf << "%" << std::endl; - else - out << NOMAD::Double() - << " (define valid MULTI_F_BOUNDS values to access this output)" - << std::endl; - } - else if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) - out << std::endl << "number of Pareto points: " << _pareto_front->size() - << std::endl; + if ( !_pareto_front ) + return; + + const std::string & stats_file_name = _p.get_stats_file_name(); + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_gen_dd(); + + // loop on the Pareto points: + if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) + out << std::endl << NOMAD::open_block ( "Pareto front" ) << std::endl; + + const NOMAD::Eval_Point * cur = _pareto_front->begin(); + while ( cur ) + { + + if ( cur->is_eval_ok() && cur->is_feasible ( _p.get_h_min() ) ) + { + + const std::list<int> & index_obj = _p.get_index_obj(); + std::list<int>::const_iterator it , end = index_obj.end(); + const NOMAD::Point & bbo = cur->get_bb_outputs(); + int i = 0; + NOMAD::Point multi_obj ( static_cast<int>(index_obj.size()) ); + + for ( it = index_obj.begin() ; it != end ; ++it ) + multi_obj[i++] = bbo[*it]; + + if ( !stats_file_name.empty() ) + _ev_control.stats_file ( stats_file_name , cur , true , &multi_obj ); + + if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY && !_p.get_display_stats().empty() ) + _ev_control.display_stats ( false , + out , + _p.get_display_stats() , + cur , + true , + &multi_obj ); + } + cur = _pareto_front->next(); + } + + if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) + out << NOMAD::close_block(); + + // other stats: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + + out << std::endl << "number of pts : " << _pareto_front->size() << std::endl; + + NOMAD::Double delta , surf; + _pareto_front->get_delta_surf ( delta , surf , + _p.get_multi_f_bounds() ); // f1_min, f1_max, + // f2_min, f2_max + out << "delta_j : " << delta << std::endl + << "surf : "; + if ( surf.is_defined() ) + out << 100*surf << "%" << std::endl; + else + out << NOMAD::Double() + << " (define valid MULTI_F_BOUNDS values to access this output)" + << std::endl; + } + else if ( display_degree != NOMAD::NO_DISPLAY && display_degree != NOMAD::MINIMAL_DISPLAY) + out << std::endl << "number of Pareto points: " << _pareto_front->size() + << std::endl; } /*---------------------------------------------------------*/ @@ -3275,7 +3423,8 @@ void NOMAD::Mads::display ( const NOMAD::Display & out ) const // 0. no display: // -------------- - if ( display_degree == NOMAD::NO_DISPLAY || display_degree == NOMAD::MINIMAL_DISPLAY) { + if ( display_degree == NOMAD::NO_DISPLAY || display_degree == NOMAD::MINIMAL_DISPLAY) + { // there may be a pareto front to write as a stats file: if ( _pareto_front && @@ -3342,11 +3491,11 @@ void NOMAD::Mads::display ( const NOMAD::Display & out ) const { out << std::endl << NOMAD::open_block ( "miscellaneous" ) - << "mesh index : min=" - << NOMAD::Mesh::get_min_mesh_index() << ", max=" - << NOMAD::Mesh::get_max_mesh_index() << ", last=" - << NOMAD::Mesh::get_mesh_index() << std::endl; - + << "mesh indices : min= (" + << _mesh->get_min_mesh_indices() << " ), max = (" + << _mesh->get_max_mesh_indices() << " ), last= ( " + << _mesh->get_mesh_indices() << " ) " << std::endl; + if ( bimv ) { out << "best infeasible solution (min. violation): ( "; @@ -3388,7 +3537,8 @@ void NOMAD::Mads::display ( const NOMAD::Display & out ) const out << "stat avg : " << _stats.get_stat_avg() << std::endl; // Pareto front (multi-objective optimization): - if ( _pareto_front ) { + if ( _pareto_front ) + { out << "number of MADS runs : " << _stats.get_mads_runs() << std::endl; if ( _pareto_front->empty() ) out << "Pareto front : empty" << std::endl; @@ -3412,7 +3562,7 @@ void NOMAD::Mads::display ( const NOMAD::Display & out ) const << " f=" << bimv->get_f() << std::endl; } - out << "best feasible solution : "; + out << "best feasible solution : "; if ( bf ) { @@ -3423,7 +3573,7 @@ void NOMAD::Mads::display ( const NOMAD::Display & out ) const } else out << "no feasible solution has been found" << std::endl; - + } } out.close_block(); @@ -3435,17 +3585,17 @@ void NOMAD::Mads::display ( const NOMAD::Display & out ) const /*---------------------------------------------------------*/ void NOMAD::Mads::display_model_stats ( const NOMAD::Display & out ) const { - if ( _model_search1 ) - out << std::endl << NOMAD::open_block ( "model search #1 stats" ) - << *_model_search1 << NOMAD::close_block(); - if ( _model_search2 ) - out << std::endl << NOMAD::open_block ( "model search #2 stats" ) - << *_model_search2 << NOMAD::close_block(); - if ( _p.get_model_eval_sort() != NOMAD::NO_MODEL ) { - out << std::endl << NOMAD::open_block ( "model ordering stats" ); - _ev_control.display_model_ordering_stats ( out ); - out << NOMAD::close_block(); - } + if ( _model_search1 ) + out << std::endl << NOMAD::open_block ( "model search #1 stats" ) + << *_model_search1 << NOMAD::close_block(); + if ( _model_search2 ) + out << std::endl << NOMAD::open_block ( "model search #2 stats" ) + << *_model_search2 << NOMAD::close_block(); + if ( _p.get_model_eval_sort() != NOMAD::NO_MODEL ) { + out << std::endl << NOMAD::open_block ( "model ordering stats" ); + _ev_control.display_model_ordering_stats ( out ); + out << NOMAD::close_block(); + } } /*---------------------------------------------------------*/ @@ -3454,12 +3604,16 @@ void NOMAD::Mads::display_model_stats ( const NOMAD::Display & out ) const /*---------------------------------------------------------*/ void NOMAD::Mads::display_deltas ( const NOMAD::Signature & s ) const { - NOMAD::Point delta_m , delta_p; - s.get_mesh().get_delta_m ( delta_m , NOMAD::Mesh::get_mesh_index() ); - s.get_mesh().get_delta_p ( delta_p , NOMAD::Mesh::get_mesh_index() ); - _p.out() << "mesh size : ( " << delta_m << " )" << std::endl - << "poll size : ( " << delta_p << " )" - << std::endl; + + NOMAD::Point delta,Delta; + + _mesh->get_delta(delta); + _mesh->get_Delta(Delta); + if (delta.is_defined() && Delta.is_defined()) + _p.out() << "mesh size : ( " << delta << " )" << std::endl + << "poll size : ( " << Delta << " )" << std::endl + << "mesh indices : ( " << _mesh->get_mesh_indices() << " )" << std::endl; + } /*-------------------------------------------------------*/ @@ -3467,74 +3621,72 @@ void NOMAD::Mads::display_deltas ( const NOMAD::Signature & s ) const /*-------------------------------------------------------*/ void NOMAD::Mads::display_iteration_begin ( void ) const { - const NOMAD::Display & out = _p.out(); - if ( out.get_iter_dd() != NOMAD::FULL_DISPLAY ) - return; - - // incumbents: - const NOMAD::Eval_Point * bf = get_best_feasible(); - const NOMAD::Eval_Point * bi = get_best_infeasible(); - const NOMAD::Signature * s1 = NULL; - - out << "blackbox evaluations : " << _stats.get_bb_eval() << std::endl; + const NOMAD::Display & out = _p.out(); + if ( out.get_iter_dd() != NOMAD::FULL_DISPLAY ) + return; + + // incumbents: + const NOMAD::Eval_Point * bf = get_best_feasible(); + const NOMAD::Eval_Point * bi = get_best_infeasible(); + const NOMAD::Signature * s1 = NULL; + + out << "blackbox evaluations : " << _stats.get_bb_eval() << std::endl; #ifdef USE_MPI - if ( _p.get_asynchronous() ) - out << "eval. in progress : " << _ev_control.get_nb_eval_in_progress() - << std::endl; + if ( _p.get_asynchronous() ) + out << "eval. in progress : " << _ev_control.get_nb_eval_in_progress() + << std::endl; #endif - out << "best feas. solution : "; - if ( bf ) { - out << "( "; - bf->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); - out << " ) h=" << bf->get_h() - << " f=" << bf->get_f() - << std::endl; - } - else - out << "none" << std::endl; - out << "best infeas. solution: "; - if ( bi ) { - out << "( "; - bi->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); - out << " ) h=" << bi->get_h() - << " f=" << bi->get_f() - << std::endl; - } - else - out << "none" << std::endl; - - out << "poll center : "; - const NOMAD::Eval_Point * poll_center = get_active_barrier().get_poll_center(); - if ( poll_center ) { - out << "( "; - poll_center->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - - s1 = poll_center->get_signature(); - if (s1) - display_deltas ( *s1 ); - } - else - out << "none" << std::endl; - - const NOMAD::Eval_Point * sec_poll_center + out << "best feas. solution : "; + if ( bf ) { + out << "( "; + bf->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); + out << " ) h=" << bf->get_h() + << " f=" << bf->get_f() + << std::endl; + } + else + out << "none" << std::endl; + out << "best infeas. solution: "; + if ( bi ) { + out << "( "; + bi->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); + out << " ) h=" << bi->get_h() + << " f=" << bi->get_f() + << std::endl; + } + else + out << "none" << std::endl; + + out << "poll center : "; + const NOMAD::Eval_Point * poll_center = get_active_barrier().get_poll_center(); + if ( poll_center ) { + out << "( "; + poll_center->Point::display ( out , " " , 2 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + + s1 = poll_center->get_signature(); + if (s1) + display_deltas ( *s1 ); + } + else + out << "none" << std::endl; + + const NOMAD::Eval_Point * sec_poll_center = get_active_barrier().get_sec_poll_center(); - - if ( sec_poll_center ) { - out << "sec. poll center : ( "; - sec_poll_center->Point::display ( out , - " " , - 2 , - NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - const NOMAD::Signature * s2 = sec_poll_center->get_signature(); - if ( s2 && (!s1 || s1 != s2) ) - display_deltas ( *s2 ); - } - - out << "mesh index : " << NOMAD::Mesh::get_mesh_index() << std::endl - << "h_max : " - << get_active_barrier().get_h_max() << std::endl; + + if ( sec_poll_center ) { + out << "sec. poll center : ( "; + sec_poll_center->Point::display ( out , + " " , + 2 , + NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + const NOMAD::Signature * s2 = sec_poll_center->get_signature(); + if ( s2 && (!s1 || s1 != s2) ) + display_deltas ( *s2 ); + } + out << "h_max : " + << get_active_barrier().get_h_max() << std::endl; } /*---------------------------------------------------------*/ @@ -3542,37 +3694,37 @@ void NOMAD::Mads::display_iteration_begin ( void ) const /*---------------------------------------------------------*/ void NOMAD::Mads::display_iteration_end ( bool stop , - NOMAD::stop_type stop_reason , - NOMAD::success_type success , - const NOMAD::Eval_Point * new_feas_inc , - const NOMAD::Eval_Point * new_infeas_inc ) const + NOMAD::stop_type stop_reason , + NOMAD::success_type success , + const NOMAD::Eval_Point * new_feas_inc , + const NOMAD::Eval_Point * new_infeas_inc ) const { - const NOMAD::Display & out = _p.out(); - - if ( out.get_iter_dd() != NOMAD::FULL_DISPLAY ) - return; - - out << std::endl - << "terminate MADS : "; - out.display_yes_or_no ( stop ); - out << std::endl; - if ( stop ) { - out << "termination cause : " << stop_reason; - if ( stop_reason==NOMAD::X0_FAIL && - !_flag_p1_active && - _p.has_EB_constraints() ) - out << " (phase one will be performed)"; - out << std::endl; - } - out << "iteration status : " << success << std::endl; - out << "new feas. incumbent : "; - if ( new_feas_inc ) - out << *new_feas_inc; - else - out << "none" << std::endl; - out << "new infeas. incumbent: "; - if ( new_infeas_inc ) - out << *new_infeas_inc; - else - out << "none" << std::endl; + const NOMAD::Display & out = _p.out(); + + if ( out.get_iter_dd() != NOMAD::FULL_DISPLAY ) + return; + + out << std::endl + << "terminate MADS : "; + out.display_yes_or_no ( stop ); + out << std::endl; + if ( stop ) { + out << "termination cause : " << stop_reason; + if ( stop_reason==NOMAD::X0_FAIL && + !_flag_p1_active && + _p.has_EB_constraints() ) + out << " (phase one will be performed)"; + out << std::endl; + } + out << "iteration status : " << success << std::endl; + out << "new feas. incumbent : "; + if ( new_feas_inc ) + out << *new_feas_inc; + else + out << "none" << std::endl; + out << "new infeas. incumbent: "; + if ( new_infeas_inc ) + out << *new_infeas_inc; + else + out << "none" << std::endl; } diff --git a/src/Mads.hpp b/src/Mads.hpp index 750061d..c44819e 100644 --- a/src/Mads.hpp +++ b/src/Mads.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -52,551 +52,559 @@ #include "L_Curve.hpp" #include "Extended_Poll.hpp" +#include "XMesh.hpp" +#include "SMesh.hpp" + #ifdef USE_TGP #include "TGP_Model_Search.hpp" #endif namespace NOMAD { - - // forward declaration of Extended_Poll: - class Extended_Poll; - - /// The MADS algorithm. - class Mads : private NOMAD::Uncopyable { - - private: - - static bool _force_quit; ///< Forces NOMAD to terminate if Ctrl-C is pressed. - - NOMAD::Parameters & _p; ///< Parameters. - NOMAD::Stats _stats; ///< Statistics. - NOMAD::Evaluator_Control _ev_control; ///< Evaluator control. - NOMAD::Evaluator_Control _ev_control_for_sorting; ///< Evaluator control. - NOMAD::Barrier _true_barrier; ///< Barrier for true function evaluations. - NOMAD::Barrier _sgte_barrier; ///< Barrier for surrogate evaluations. - - /// Pareto front for multi-objective optimization. - NOMAD::Pareto_Front * _pareto_front; - - /// User search defined with NOMAD::Mads::set_user_search(). - NOMAD::Search * _user_search; - - NOMAD::Search * _model_search1; ///< Model search #1. - NOMAD::Search * _model_search2; ///< Model search #2. - - NOMAD::Search * _VNS_search; ///< VNS search. - NOMAD::Search * _cache_search; ///< Cache search. - NOMAD::L_Curve * _L_curve; ///< L-curve target. - NOMAD::Extended_Poll * _extended_poll; ///< Extended poll for categorical variables. - bool _user_ext_poll; ///< Flag for user-defined extended poll. - - // MADS flags (these are not parameters as users do not modify them): - - static bool _flag_check_bimads; ///< Flag for the multi-objective test in \c run(). - static bool _flag_reset_mesh; ///< Reset or not the mesh before a MADS run. - static bool _flag_reset_barriers; ///< Reset or not the barriers before a MADS run. - static bool _flag_p1_active; ///< Flag equal to \c true if phase one is active. - - /*-----------------------------------------------------------------------------*/ - - /// Initializations. - void init ( void ); - - /// Starting point evaluation. - /** - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - */ - void eval_x0 ( bool & stop , NOMAD::stop_type & stop_reason ); - - /// One MADS iteration. - /** - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - \param success Success for this iteration -- \b OUT. - \param new_feas_inc Pointer to the new feasible incumbent -- \b OUT. - \param new_infeas_inc Pointer to the new infeasible incumbent -- \b OUT. - */ - void iteration ( bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::success_type & success , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc ); - - /// The search step. - /** - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - \param success Success for this step -- \b OUT. - \param new_feas_inc Pointer to the new feasible incumbent -- \b OUT. - \param new_infeas_inc Pointer to the new infeasible incumbent -- \b OUT. - */ - void search ( bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::success_type & success , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc ); - - /// The poll step. - /** - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - \param success Success for this step -- \b OUT. - \param new_feas_inc Pointer to the new feasible incumbent -- \b OUT. - \param new_infeas_inc Pointer to the new infeasible incumbent -- \b OUT. - \param forbid_poll_size_stop Boolean used to check if the min poll - size stopping criterion has to be - disabled for integer variables -- \b OUT. - */ - void poll ( bool & stop, - NOMAD::stop_type & stop_reason, - NOMAD::success_type & success, - const NOMAD::Eval_Point *& new_feas_inc, - const NOMAD::Eval_Point *& new_infeas_inc, - bool & forbid_poll_size_stop ); - - /// Sets the poll trial points from poll direction, poll center and mesh size - /** - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - \param dirs List of directions for the poll -- \b IN. - \param poll_center the poll center (can be null) -- \b IN. - \param offset Dir index offset for primary and sec. poll center -- \b IN. - \param sorting If true than the points are for sorting -- \b IN. - */ - void set_poll_trial_points ( std::list<NOMAD::Direction> & dirs, - int offset, - const NOMAD::Eval_Point & poll_center, - bool & stop, - NOMAD::stop_type &stop_reason, - bool sorting); - - - /// Compute a prospect point by optimization on quadratic models. - /** - \param poll_center The poll center -- \b IN. - \param dirs The directions that delimit the hypercube for optimization -- \b IN. - \param prospect_point The prospect point -- \b OUT. - \return A flag equal to \c true if the prospect direction has been computed. - */ - bool optimize_quad_model ( const NOMAD::Eval_Point & poll_center , - const std::list<NOMAD::Direction> & dirs , - NOMAD::Point & prospect_point ) ; - - /// Sets the poll directions from signature, poll center and mesh size - /** - \param dirs List of directions for the poll -- \b OUT. - \param i_pc Poll type -- \b IN. - \param offset Dir index offset for primary and sec. poll center -- \b IN. - \param poll_center The poll center -- \b IN. - \param stop Stop flag, true if cannot get direction -- \b IN/OUT. - \param stop_reason Stop type -- \b OUT. - */ - void set_poll_directions ( std::list<NOMAD::Direction> & dirs , - NOMAD::poll_type i_pc , - int offset , - const NOMAD::Eval_Point & poll_center , - bool & stop , - NOMAD::stop_type & stop_reason ); - - /// Reduce the number of poll directions -> n - /** - \param dirs List of directions for the poll -- \b IN/OUT. - \param poll_center the poll center -- \b IN. - \return success for this step. - */ - bool set_reduced_poll_to_n_directions(std::list<NOMAD::Direction> & dirs, - const NOMAD::Eval_Point & poll_center); - - /// Compute the rank of a list of directions - /** - \param dirs List of directions for the poll -- \b IN/OUT. - \return rank>0 of the dirs if successfull or 0 if rank cannot be evaluated - */ - int get_rank_from_dirs(const std::list<NOMAD::Direction> & dirs); - - - /// Check the directions after the poll step. - /** - \param forbid_poll_size_stop Boolean equal to \c true if - the \c MIN_POLL_SIZE parameter is valid for - the last set of poll directions -- \b OUT. - */ - void check_directions ( bool & forbid_poll_size_stop ); - - /// Update of the success directions. - /** - - Occurs after the poll. - \param new_inc Pointer to the new incumbent -- \b IN (may be \c NULL). - \param feasible Flag equal to \c true if the incumbent is feasible -- \b IN. - */ - void update_success_directions ( const NOMAD::Eval_Point * new_inc , - bool feasible ) const; - - /// Launch a single-objective MADS run for multi-objective optimization. - /** - \param display_degree Display degree -- \b IN. - \param mads_runs Total number of MADS runs to execute -- \b IN. - \param overall_bbe Global maximum number of blackbox evaluations -- \b IN. - \param ev Evaluator for multi-objective -- \b IN/OUT. - \param stagnation_cnt Counter to detect a stagnation -- \b IN/OUT. - \param multi_stats Stats for multi-objective -- \b IN/OUT. - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - */ - void multi_launch_single_opt ( NOMAD::dd_type display_degree , - int mads_runs , - int overall_bbe , - NOMAD::Multi_Obj_Evaluator & ev , - int & stagnation_cnt , - NOMAD::Stats & multi_stats , - bool & stop , - NOMAD::stop_type & stop_reason ); - - /// Compute and set the minimal poll size for multi-objective optimization. - /** - \param lb Lower bounds -- \b IN. - \param ub Upper bounds -- \b IN. - \param delta_p_0 Initial poll size -- \b IN. - \param delta_j Delta criterion for multi-objective -- \b IN/OUT. - */ - void multi_set_min_poll_size ( const NOMAD::Point & lb , - const NOMAD::Point & ub , - const NOMAD::Point & delta_p_0 , - NOMAD::Double delta_j ); - - // Display mesh and poll sizes for a given signature. - /** - \param s The signature -- \b IN. - */ - void display_deltas ( const NOMAD::Signature & s ) const; - - /// Displays at the beginning of an iteration. - void display_iteration_begin ( void ) const; - - /// Displays at the end of an iteration. - /** - \param stop Stop flag -- \b IN. - \param stop_reason Stop reason -- \b IN. - \param success Iteration success -- \b IN. - \param new_feas_inc Pointer to the new feasible incumbent -- \b IN. - \param new_infeas_inc Pointer to the new infeasible incumbent -- \b IN. - */ - void display_iteration_end ( bool stop , - NOMAD::stop_type stop_reason , - NOMAD::success_type success , - const NOMAD::Eval_Point * new_feas_inc , - const NOMAD::Eval_Point * new_infeas_inc ) const; - - - /// Determine dynamic directions from a set of directions. - /** - - The computed opposite directions already include Delta^k_m. - \param dirs List of existing directions (no snap to bounds) -- \b IN. - \param newDirs New dynamic directions -- \b OUT. - \param poll_center Poll center -- \b IN. - \return true if new dynamic direction generated false otherwise - */ - bool get_dynamic_directions (const std::list<NOMAD::Direction> & dirs, - std::list<NOMAD::Direction> & newDirs, - const NOMAD::Eval_Point & poll_center) ; - - - - /// Check if a set of directions include Ortho-MADS N+1 direction. - /** - \param dirs List of directions -- \b IN. - \return A boolean equal to \c true if at - least one direction in the set is - of type Ortho-MADS N+1. - */ - bool dirs_have_orthomads_np1 ( const std::list<NOMAD::Direction> & dirs ); - - - /// Check if a dir needs to be obtained from model optimization - /** - \param dirs List of directions -- \b IN. - \return A boolean equal to \c true if all directions are of type Ortho-MADS N+1 QUAD. - */ - bool dir_from_model_opt( const std::list<NOMAD::Direction> & dirs); - - - /// get a single direction using quad model optimization or sum of negatives - /** - \param dirs Reduced poll directions (no snap to bounds) -- \b IN. - \param poll_center Poll center -- \b IN. - \return new direction - */ - NOMAD::Direction get_single_dynamic_direction (const std::list<NOMAD::Direction> & dirs, - const NOMAD::Eval_Point & poll_center) ; - - - /*-----------------------------------------------------------------------------*/ - - public: - - /// Constructor #1. - /** - - Basic version. - \param p Parameters -- \b IN. - \param ev A pointer to the evaluator -- \b IN - -- \b optional (default = \c NULL). - */ - Mads ( NOMAD::Parameters & p , NOMAD::Evaluator * ev = NULL ) - : _p ( p ) , - _stats ( p.get_sgte_cost() ) , - _ev_control ( p , _stats , ev , NULL , NULL ) , - _ev_control_for_sorting( p , _stats , _ev_control.get_evaluator() , &(_ev_control.get_cache()) , &(_ev_control.get_sgte_cache()) ) , - _true_barrier ( p , NOMAD::TRUTH ) , - _sgte_barrier ( p , NOMAD::SGTE ) , - _pareto_front ( NULL ) , - _user_search ( NULL ) , - _model_search1 ( NULL ) , - _model_search2 ( NULL ) , - _VNS_search ( NULL ) , - _cache_search ( NULL ) , - _L_curve ( NULL ) , - _extended_poll ( NULL ) , - _user_ext_poll ( false ) { init(); } - - /// Constructor #2. - /** - - Advanced version. - \param p Parameters -- \b IN. - \param ev A pointer to the evaluator -- \b IN (may be \c NULL). - \param extended_poll A pointer to a NOMAD::Extended_Poll object - -- \b IN (may be \c NULL). - \param cache A pointer to a cache -- \b IN (may be \c NULL). - \param sgte_cache A pointer to a cache for surrogates - -- \b IN (may be \c NULL). - */ - Mads ( NOMAD::Parameters & p , - NOMAD::Evaluator * ev , // may be NULL - NOMAD::Extended_Poll * extended_poll , // may be NULL - NOMAD::Cache * cache , // may be NULL - NOMAD::Cache * sgte_cache ) // may be NULL - : _p ( p ) , - _stats ( p.get_sgte_cost() ) , - _ev_control ( p , _stats , ev , cache , sgte_cache ) , - _ev_control_for_sorting( p , _stats , _ev_control.get_evaluator() , cache , sgte_cache ) , - _true_barrier ( p , NOMAD::TRUTH ) , - _sgte_barrier ( p , NOMAD::SGTE ) , - _pareto_front ( NULL ) , - _user_search ( NULL ) , - _model_search1 ( NULL ) , - _model_search2 ( NULL ) , - _VNS_search ( NULL ) , - _cache_search ( NULL ) , - _L_curve ( NULL ) , - _extended_poll ( extended_poll ) , - _user_ext_poll ( (extended_poll!=NULL) ) { init(); } - - /// Destructor. - virtual ~Mads ( void ); - - /// Algorithm execution for single-objective. - /** - \return Stop reason. - */ - NOMAD::stop_type run ( void ); - - /// Algorithm execution for multi-objective. - /** - \return Stop reason. - */ - NOMAD::stop_type multi_run ( void ); - - /// Force quit. - /** - Called by pressing Ctrl-C. - \param signalValue Signal value -- \b IN. - */ - static void force_quit ( int signalValue ); - - /// Reset. - /** - - Also resets the user search. - \param keep_barriers A boolean equal to \c true if NOMAD::Barrier objects - have to be reseted - -- \b IN -- \b optional (default = \c false). - \param keep_stats A boolean equal to \c true if the stats object - has to be reseted - -- \b IN -- \b optional (default = \c false). - */ - void reset ( bool keep_barriers = false , bool keep_stats = false ); - - /// Set user search. - /** - \param us A pointer to the user search -- \b IN. - */ - void set_user_search ( NOMAD::Search * us ) { _user_search = us; } - - /// Set an extern Pareto front. - /** - \param pf A pointer to a Pareto front -- \b IN. - */ - void set_pareto_front ( NOMAD::Pareto_Front * pf ) { _pareto_front = pf; } - - /// Set the flag for the multi-objective test. - /** - \param fcb The flag for the multi-objective test -- \b IN. - */ - static void set_flag_check_bimads ( bool fcb ) { _flag_check_bimads = fcb; } - - /// Set the flag \c _flag_reset_mesh. - /** - \param frm The flag -- \b IN. - */ - static void set_flag_reset_mesh ( bool frm ) { _flag_reset_mesh = frm; } - - /// Set the flag \c _flag_reset_barriers. - /** - \param frb The flag -- \b IN. - */ - static void set_flag_reset_barriers ( bool frb ) { _flag_reset_barriers = frb; } - - /// Set the flag \c _flag_p1_active -- \b IN. - /** - \param fpa The flag. - */ - static void set_flag_p1_active ( bool fpa ) { _flag_p1_active = fpa; } - - /// Access to the flags. - /** - \param flag_check_bimads Multi-objective flag -- \b OUT. - \param flag_reset_mesh Mesh reset flag -- \b OUT. - \param flag_reset_barriers Reset barriers flag -- \b OUT. - \param flag_p1_active Phase one flag -- \b OUT. - */ - static void get_flags ( bool & flag_check_bimads , - bool & flag_reset_mesh , - bool & flag_reset_barriers , - bool & flag_p1_active ); - - /// Access to the stats. - /** - \return The stats. - */ - NOMAD::Stats & get_stats ( void ) { return _stats; } - - /// Access to the evaluator control. - /** - \return The evaluator control. - */ - NOMAD::Evaluator_Control & get_evaluator_control ( void ) { return _ev_control; } - - /// Access to the barrier for true function evaluations. - /** - \return The barrier for the true function evaluations. - */ - NOMAD::Barrier & get_true_barrier ( void ) { return _true_barrier; } - - /// Access to the barrier for surrogate evaluations. - /** - \return The barrier for the surrogates. - */ - NOMAD::Barrier & get_sgte_barrier ( void ) { return _sgte_barrier; } - - /// Access to the NOMAD::Extended_Poll object. - /** - \return A pointer to \c _extended_poll. - */ - NOMAD::Extended_Poll * get_extended_poll ( void ) const { return _extended_poll; } - - - - /// Access to the Pareto front. - /** - \return A pointer to the Pareto front. - */ - NOMAD::Pareto_Front * get_pareto_front ( void ) const { return _pareto_front; } - - /// Access to the active cache (truth or surrogate). - /** - \return The active cache. - */ - const NOMAD::Cache & get_cache ( void ) const - { - return ( _p.get_opt_only_sgte() ) ? - _ev_control.get_sgte_cache() : _ev_control.get_cache(); - } - - /// Access to the active barrier (truth or surrogate). - /** - \return The active barrier. - */ - const NOMAD::Barrier & get_active_barrier ( void ) const - { - return ( _p.get_opt_only_sgte() ) ? _sgte_barrier : _true_barrier; - } - - /// Access to the best feasible point. - /** - \return A pointer to the best feasible point; - \return \c NULL if there is no feasible point. - */ - const NOMAD::Eval_Point * get_best_feasible ( void ) const - { - return get_active_barrier().get_best_feasible(); - } - - /// Access to the best infeasible point. - /** - \return A pointer to the best infeasible point; - \return \c NULL if there is no infeasible point. - */ - const NOMAD::Eval_Point * get_best_infeasible( void ) const - { - return get_active_barrier().get_best_infeasible(); - } - - /// Access to the best infeasible point with minimun constraint violation. - /** - \return A pointer to the best infeasible point with min. viol.; - \return \c NULL if there is no infeasible point. - */ - const NOMAD::Eval_Point * get_best_infeasible_min_viol ( void ) const - { - return get_active_barrier().get_best_infeasible_min_viol(); - } - - /// Display model stats. - /** - \param out The NOMAD::Display object -- \b IN. - */ - void display_model_stats ( const NOMAD::Display & out ) const; - - /// Display the Pareto front. - /** - Displays the front at the standard output or in a stats file. - */ - void display_pareto_front ( void ) const; - - /// Display. - /** - \param out The NOMAD::Display object -- \b IN. - */ - void display ( const NOMAD::Display & out ) const; - - /// Display. - /** - Uses the NOMAD::Display object of the NOMAD::Parameters class. - */ - void display ( void ) const { display ( _p.out() ); } - }; - - /// Display a NOMAD::Mads object. - /** + + // forward declaration of Extended_Poll: + class Extended_Poll; + + /// The MADS algorithm. + class Mads : private NOMAD::Uncopyable { + + private: + + static bool _force_quit; ///< Forces NOMAD to terminate if Ctrl-C is pressed. + + NOMAD::Parameters & _p; ///< Parameters. + NOMAD::Stats _stats; ///< Statistics. + NOMAD::Evaluator_Control _ev_control; ///< Evaluator control. + NOMAD::Evaluator_Control _ev_control_for_sorting; ///< Evaluator control. + NOMAD::Barrier _true_barrier; ///< Barrier for true function evaluations. + NOMAD::Barrier _sgte_barrier; ///< Barrier for surrogate evaluations. + + NOMAD::OrthogonalMesh * _mesh; ///< Access to the OrthogonalMesh + + /// Pareto front for multi-objective optimization. + NOMAD::Pareto_Front * _pareto_front; + + /// User search defined with NOMAD::Mads::set_user_search(). + NOMAD::Search * _user_search; + + NOMAD::Search * _model_search1; ///< Model search #1. + NOMAD::Search * _model_search2; ///< Model search #2. + + NOMAD::Search * _VNS_search; ///< VNS search. + NOMAD::Search * _cache_search; ///< Cache search. + NOMAD::L_Curve * _L_curve; ///< L-curve target. + NOMAD::Extended_Poll * _extended_poll; ///< Extended poll for categorical variables. + bool _user_ext_poll; ///< Flag for user-defined extended poll. + + // MADS flags (these are not parameters as users do not modify them): + + static bool _flag_check_bimads; ///< Flag for the multi-objective test in \c run(). + static bool _flag_reset_mesh; ///< Reset or not the mesh before a MADS run. + static bool _flag_reset_barriers; ///< Reset or not the barriers before a MADS run. + static bool _flag_p1_active; ///< Flag equal to \c true if phase one is active. + + /*-----------------------------------------------------------------------------*/ + + /// Initializations. + void init ( void ); + + /// Starting point evaluation. + /** + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + */ + void eval_x0 ( bool & stop , NOMAD::stop_type & stop_reason ); + + /// One MADS iteration. + /** + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + \param success Success for this iteration -- \b OUT. + \param new_feas_inc Pointer to the new feasible incumbent -- \b OUT. + \param new_infeas_inc Pointer to the new infeasible incumbent -- \b OUT. + */ + void iteration ( bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::success_type & success , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc ); + + /// The search step. + /** + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + \param success Success for this step -- \b OUT. + \param new_feas_inc Pointer to the new feasible incumbent -- \b OUT. + \param new_infeas_inc Pointer to the new infeasible incumbent -- \b OUT. + */ + void search ( bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::success_type & success , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc ); + + /// The poll step. + /** + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + \param success Success for this step -- \b OUT. + \param new_feas_inc Pointer to the new feasible incumbent -- \b OUT. + \param new_infeas_inc Pointer to the new infeasible incumbent -- \b OUT. + \param forbid_poll_size_stop Boolean used to check if the min poll + size stopping criterion has to be + disabled for integer variables -- \b OUT. + */ + void poll ( bool & stop, + NOMAD::stop_type & stop_reason, + NOMAD::success_type & success, + const NOMAD::Eval_Point *& new_feas_inc, + const NOMAD::Eval_Point *& new_infeas_inc, + bool & forbid_poll_size_stop ); + + /// Sets the poll trial points from poll direction, poll center and mesh size + /** + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + \param dirs List of directions for the poll -- \b IN. + \param poll_center the poll center (can be null) -- \b IN. + \param offset Dir index offset for primary and sec. poll center -- \b IN. + \param sorting If true than the points are for sorting -- \b IN. + */ + void set_poll_trial_points ( std::list<NOMAD::Direction> & dirs, + size_t offset, + const NOMAD::Eval_Point & poll_center, + bool & stop, + NOMAD::stop_type &stop_reason, + bool sorting); + + + /// Compute a prospect point by optimization on quadratic models. + /** + \param poll_center The poll center -- \b IN. + \param dirs The directions that delimit the hypercube for optimization -- \b IN. + \param prospect_point The prospect point -- \b OUT. + \return A flag equal to \c true if the prospect direction has been computed. + */ + bool optimize_quad_model ( const NOMAD::Eval_Point & poll_center , + const std::list<NOMAD::Direction> & dirs , + NOMAD::Point & prospect_point ) ; + + + /// Sets the poll directions from signature, poll center and mesh size + /** + \param dirs List of directions for the poll -- \b OUT. + \param i_pc Poll type -- \b IN. + \param offset Dir index offset for primary and sec. poll center -- \b IN. + \param poll_center The poll center -- \b IN. + \param stop Stop flag, true if cannot get direction -- \b IN/OUT. + \param stop_reason Stop type -- \b OUT. + */ + void set_poll_directions ( std::list<NOMAD::Direction> & dirs , + NOMAD::poll_type i_pc , + size_t offset , + const NOMAD::Eval_Point & poll_center , + bool & stop , + NOMAD::stop_type & stop_reason ); + + /// Reduce the number of poll directions -> n + /** + \param dirs List of directions for the poll -- \b IN/OUT. + \param poll_center the poll center -- \b IN. + \return success for this step. + */ + bool set_reduced_poll_to_n_directions(std::list<NOMAD::Direction> & dirs, + const NOMAD::Eval_Point & poll_center); + + /// Compute the rank of a list of directions + /** + \param dirs List of directions for the poll -- \b IN/OUT. + \return rank>0 of the dirs if successfull or 0 if rank cannot be evaluated + */ + int get_rank_from_dirs(const std::list<NOMAD::Direction> & dirs); + + + /// Check the directions after the poll step. + /** + \param forbid_poll_size_stop Boolean equal to \c true if + the \c MIN_POLL_SIZE parameter is valid for + the last set of poll directions -- \b OUT. + */ + void check_directions ( bool & forbid_poll_size_stop ); + + /// Update of the success directions. + /** + - Occurs after the poll. + \param new_inc Pointer to the new incumbent -- \b IN (may be \c NULL). + \param feasible Flag equal to \c true if the incumbent is feasible -- \b IN. + */ + void update_success_directions ( const NOMAD::Eval_Point * new_inc , + bool feasible ) const; + + /// Launch a single-objective MADS run for multi-objective optimization. + /** + \param display_degree Display degree -- \b IN. + \param mads_runs Total number of MADS runs to execute -- \b IN. + \param overall_bbe Global maximum number of blackbox evaluations -- \b IN. + \param ev Evaluator for multi-objective -- \b IN/OUT. + \param stagnation_cnt Counter to detect a stagnation -- \b IN/OUT. + \param multi_stats Stats for multi-objective -- \b IN/OUT. + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + */ + void multi_launch_single_opt ( NOMAD::dd_type display_degree , + int mads_runs , + int overall_bbe , + NOMAD::Multi_Obj_Evaluator & ev , + int & stagnation_cnt , + NOMAD::Stats & multi_stats , + bool & stop , + NOMAD::stop_type & stop_reason ); + + /// Compute and set the minimal poll size for multi-objective optimization. + /** + \param lb Lower bounds -- \b IN. + \param ub Upper bounds -- \b IN. + \param delta_p_0 Initial poll size -- \b IN. + \param delta_j Delta criterion for multi-objective -- \b IN/OUT. + */ + void multi_set_min_poll_size ( const NOMAD::Point & lb , + const NOMAD::Point & ub , + const NOMAD::Point & delta_p_0 , + NOMAD::Double delta_j ); + + // Display mesh and poll sizes for a given signature. + /** + \param s The signature -- \b IN. + */ + void display_deltas ( const NOMAD::Signature & s ) const; + + /// Displays at the beginning of an iteration. + void display_iteration_begin ( void ) const; + + /// Displays at the end of an iteration. + /** + \param stop Stop flag -- \b IN. + \param stop_reason Stop reason -- \b IN. + \param success Iteration success -- \b IN. + \param new_feas_inc Pointer to the new feasible incumbent -- \b IN. + \param new_infeas_inc Pointer to the new infeasible incumbent -- \b IN. + */ + void display_iteration_end ( bool stop , + NOMAD::stop_type stop_reason , + NOMAD::success_type success , + const NOMAD::Eval_Point * new_feas_inc , + const NOMAD::Eval_Point * new_infeas_inc ) const; + + + /// Determine dynamic directions from a set of directions. + /** + - The computed opposite directions already include Delta^k_m. + \param dirs List of existing directions (no snap to bounds) -- \b IN. + \param newDirs New dynamic directions -- \b OUT. + \param poll_center Poll center -- \b IN. + \return true if new dynamic direction generated false otherwise + */ + bool get_dynamic_directions (const std::list<NOMAD::Direction> & dirs, + std::list<NOMAD::Direction> & newDirs, + const NOMAD::Eval_Point & poll_center) ; + + + + /// Check if a set of directions include Ortho-MADS N+1 direction. + /** + \param dirs List of directions -- \b IN. + \return A boolean equal to \c true if at + least one direction in the set is + of type Ortho-MADS N+1. + */ + bool dirs_have_orthomads_np1 ( const std::list<NOMAD::Direction> & dirs ); + + + /// Check if a dir needs to be obtained from model optimization + /** + \param dirs List of directions -- \b IN. + \return A boolean equal to \c true if all directions are of type Ortho-MADS N+1 QUAD. + */ + bool dir_from_model_opt( const std::list<NOMAD::Direction> & dirs); + + + /// get a single direction using quad model optimization or sum of negatives + /** + \param dirs Reduced poll directions (no snap to bounds) -- \b IN. + \param poll_center Poll center -- \b IN. + \return new direction + */ + NOMAD::Direction get_single_dynamic_direction (const std::list<NOMAD::Direction> & dirs, + const NOMAD::Eval_Point & poll_center) ; + + + /*-----------------------------------------------------------------------------*/ + + public: + + /// Constructor #1. + /** + - Basic version. + \param p Parameters -- \b IN. + \param ev A pointer to the evaluator -- \b IN + -- \b optional (default = \c NULL). + */ + Mads ( NOMAD::Parameters & p , NOMAD::Evaluator * ev = NULL ) + : _p ( p ) , + _stats ( p.get_sgte_cost() ) , + _ev_control ( p , _stats , ev , NULL , NULL ) , + _ev_control_for_sorting( p , _stats , _ev_control.get_evaluator() , &(_ev_control.get_cache()) , &(_ev_control.get_sgte_cache()) ) , + _true_barrier ( p , NOMAD::TRUTH ) , + _sgte_barrier ( p , NOMAD::SGTE ) , + _mesh ( p.get_signature()->get_mesh() ) , + _pareto_front ( NULL ) , + _user_search ( NULL ) , + _model_search1 ( NULL ) , + _model_search2 ( NULL ) , + _VNS_search ( NULL ) , + _cache_search ( NULL ) , + _L_curve ( NULL ) , + _extended_poll ( NULL ) , + _user_ext_poll ( false ) { init(); } + + /// Constructor #2. + /** + - Advanced version. + \param p Parameters -- \b IN. + \param ev A pointer to the evaluator -- \b IN (may be \c NULL). + \param extended_poll A pointer to a NOMAD::Extended_Poll object + -- \b IN (may be \c NULL). + \param cache A pointer to a cache -- \b IN (may be \c NULL). + \param sgte_cache A pointer to a cache for surrogates + -- \b IN (may be \c NULL). + */ + Mads ( NOMAD::Parameters & p , + NOMAD::Evaluator * ev , // may be NULL + NOMAD::Extended_Poll * extended_poll , // may be NULL + NOMAD::Cache * cache , // may be NULL + NOMAD::Cache * sgte_cache ) // may be NULL + : _p ( p ) , + _stats ( p.get_sgte_cost() ) , + _ev_control ( p , _stats , ev , cache , sgte_cache ) , + _ev_control_for_sorting( p , _stats , _ev_control.get_evaluator() , cache , sgte_cache ) , + _true_barrier ( p , NOMAD::TRUTH ) , + _sgte_barrier ( p , NOMAD::SGTE ) , + _mesh ( p.get_signature()->get_mesh() ) , + _pareto_front ( NULL ) , + _user_search ( NULL ) , + _model_search1 ( NULL ) , + _model_search2 ( NULL ) , + _VNS_search ( NULL ) , + _cache_search ( NULL ) , + _L_curve ( NULL ) , + _extended_poll ( extended_poll ) , + _user_ext_poll ( (extended_poll!=NULL) ) { init(); } + + /// Destructor. + virtual ~Mads ( void ); + + /// Algorithm execution for single-objective. + /** + \return Stop reason. + */ + NOMAD::stop_type run ( void ); + + /// Algorithm execution for multi-objective. + /** + \return Stop reason. + */ + NOMAD::stop_type multi_run ( void ); + + /// Force quit. + /** + Called by pressing Ctrl-C. + \param signalValue Signal value -- \b IN. + */ + static void force_quit ( int signalValue ); + + /// Reset. + /** + - Also resets the user search. + \param keep_barriers A boolean equal to \c true if NOMAD::Barrier objects + have to be reseted + -- \b IN -- \b optional (default = \c false). + \param keep_stats A boolean equal to \c true if the stats object + has to be reseted + -- \b IN -- \b optional (default = \c false). + */ + void reset ( bool keep_barriers = false , bool keep_stats = false ); + + /// Set user search. + /** + \param us A pointer to the user search -- \b IN. + */ + void set_user_search ( NOMAD::Search * us ) { _user_search = us; } + + /// Set an extern Pareto front. + /** + \param pf A pointer to a Pareto front -- \b IN. + */ + void set_pareto_front ( NOMAD::Pareto_Front * pf ) { _pareto_front = pf; } + + /// Set the flag for the multi-objective test. + /** + \param fcb The flag for the multi-objective test -- \b IN. + */ + static void set_flag_check_bimads ( bool fcb ) { _flag_check_bimads = fcb; } + + /// Set the flag \c _flag_reset_mesh. + /** + \param frm The flag -- \b IN. + */ + static void set_flag_reset_mesh ( bool frm ) { _flag_reset_mesh = frm; } + + /// Set the flag \c _flag_reset_barriers. + /** + \param frb The flag -- \b IN. + */ + static void set_flag_reset_barriers ( bool frb ) { _flag_reset_barriers = frb; } + + /// Set the flag \c _flag_p1_active -- \b IN. + /** + \param fpa The flag. + */ + static void set_flag_p1_active ( bool fpa ) { _flag_p1_active = fpa; } + + /// Access to the flags. + /** + \param flag_check_bimads Multi-objective flag -- \b OUT. + \param flag_reset_mesh Mesh reset flag -- \b OUT. + \param flag_reset_barriers Reset barriers flag -- \b OUT. + \param flag_p1_active Phase one flag -- \b OUT. + */ + static void get_flags ( bool & flag_check_bimads , + bool & flag_reset_mesh , + bool & flag_reset_barriers , + bool & flag_p1_active ); + + /// Access to the stats. + /** + \return The stats. + */ + NOMAD::Stats & get_stats ( void ) { return _stats; } + + /// Access to the evaluator control. + /** + \return The evaluator control. + */ + NOMAD::Evaluator_Control & get_evaluator_control ( void ) { return _ev_control; } + + /// Access to the barrier for true function evaluations. + /** + \return The barrier for the true function evaluations. + */ + NOMAD::Barrier & get_true_barrier ( void ) { return _true_barrier; } + + /// Access to the barrier for surrogate evaluations. + /** + \return The barrier for the surrogates. + */ + NOMAD::Barrier & get_sgte_barrier ( void ) { return _sgte_barrier; } + + /// Access to the NOMAD::Extended_Poll object. + /** + \return A pointer to \c _extended_poll. + */ + NOMAD::Extended_Poll * get_extended_poll ( void ) const { return _extended_poll; } + + + + /// Access to the Pareto front. + /** + \return A pointer to the Pareto front. + */ + NOMAD::Pareto_Front * get_pareto_front ( void ) const { return _pareto_front; } + + /// Access to the active cache (truth or surrogate). + /** + \return The active cache. + */ + const NOMAD::Cache & get_cache ( void ) const + { + return ( _p.get_opt_only_sgte() ) ? + _ev_control.get_sgte_cache() : _ev_control.get_cache(); + } + + /// Access to the active barrier (truth or surrogate). + /** + \return The active barrier. + */ + const NOMAD::Barrier & get_active_barrier ( void ) const + { + return ( _p.get_opt_only_sgte() ) ? _sgte_barrier : _true_barrier; + } + + /// Access to the best feasible point. + /** + \return A pointer to the best feasible point; + \return \c NULL if there is no feasible point. + */ + const NOMAD::Eval_Point * get_best_feasible ( void ) const + { + return get_active_barrier().get_best_feasible(); + } + + /// Access to the best infeasible point. + /** + \return A pointer to the best infeasible point; + \return \c NULL if there is no infeasible point. + */ + const NOMAD::Eval_Point * get_best_infeasible( void ) const + { + return get_active_barrier().get_best_infeasible(); + } + + /// Access to the best infeasible point with minimun constraint violation. + /** + \return A pointer to the best infeasible point with min. viol.; + \return \c NULL if there is no infeasible point. + */ + const NOMAD::Eval_Point * get_best_infeasible_min_viol ( void ) const + { + return get_active_barrier().get_best_infeasible_min_viol(); + } + + /// Display model stats. + /** + \param out The NOMAD::Display object -- \b IN. + */ + void display_model_stats ( const NOMAD::Display & out ) const; + + /// Display the Pareto front. + /** + Displays the front at the standard output or in a stats file. + */ + void display_pareto_front ( void ) const; + + /// Display. + /** + \param out The NOMAD::Display object -- \b IN. + */ + void display ( const NOMAD::Display & out ) const; + + /// Display. + /** + Uses the NOMAD::Display object of the NOMAD::Parameters class. + */ + void display ( void ) const { display ( _p.out() ); } + }; + + /// Display a NOMAD::Mads object. + /** \param out The NOMAD::Display object -- \b IN. \param m The NOMAD::Mads object to be displayed -- \b IN. \return The NOMAD::Display object. - */ - inline const NOMAD::Display & operator << ( const NOMAD::Display & out , - const NOMAD::Mads & m ) - { - m.display ( out ); - return out; - } + */ + inline const NOMAD::Display & operator << ( const NOMAD::Display & out , + const NOMAD::Mads & m ) + { + m.display ( out ); + return out; + } } #endif diff --git a/src/Makefile.am b/src/Makefile.am index 1046822..2ffa641 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,33 +3,35 @@ libnomad_a_SOURCES = Barrier.cpp Cache.cpp Cache_File_Point.cpp Cache_Point.cpp\ Cache_Search.cpp Clock.cpp Direction.cpp Directions.cpp Display.cpp\ Double.cpp Eval_Point.cpp Evaluator_Control.cpp Evaluator.cpp\ Exception.cpp Extended_Poll.cpp L_Curve.cpp LH_Search.cpp Mads.cpp\ - Mesh.cpp Model_Sorted_Point.cpp Model_Stats.cpp Multi_Obj_Evaluator.cpp\ + SMesh.cpp XMesh.cpp Model_Sorted_Point.cpp Model_Stats.cpp Multi_Obj_Evaluator.cpp\ Parameter_Entries.cpp Parameter_Entry.cpp Parameters.cpp\ Pareto_Front.cpp Pareto_Point.cpp Phase_One_Evaluator.cpp\ Phase_One_Search.cpp Point.cpp Priority_Eval_Point.cpp Quad_Model.cpp\ Quad_Model_Evaluator.cpp Quad_Model_Search.cpp Random_Pickup.cpp\ RNG.cpp Signature.cpp Slave.cpp Speculative_Search.cpp Stats.cpp\ TGP_Model.cpp TGP_Model_Evaluator.cpp TGP_Model_Search.cpp\ - TGP_Output_Model.cpp utils.cpp Variable_Group.cpp VNS_Search.cpp + TGP_Output_Model.cpp utils.cpp Variable_Group.cpp VNS_Search.cpp\ + OrthogonalMesh.cpp libnomadmpi_a_SOURCES = Barrier.cpp Cache.cpp Cache_File_Point.cpp Cache_Point.cpp\ Cache_Search.cpp Clock.cpp Direction.cpp Directions.cpp Display.cpp\ Double.cpp Eval_Point.cpp Evaluator_Control.cpp Evaluator.cpp\ Exception.cpp Extended_Poll.cpp L_Curve.cpp LH_Search.cpp Mads.cpp\ - Mesh.cpp Model_Sorted_Point.cpp Model_Stats.cpp Multi_Obj_Evaluator.cpp\ + SMesh.cpp XMesh.cpp Model_Sorted_Point.cpp Model_Stats.cpp Multi_Obj_Evaluator.cpp\ Parameter_Entries.cpp Parameter_Entry.cpp Parameters.cpp\ Pareto_Front.cpp Pareto_Point.cpp Phase_One_Evaluator.cpp\ Phase_One_Search.cpp Point.cpp Priority_Eval_Point.cpp Quad_Model.cpp\ Quad_Model_Evaluator.cpp Quad_Model_Search.cpp Random_Pickup.cpp\ RNG.cpp Signature.cpp Slave.cpp Speculative_Search.cpp Stats.cpp\ TGP_Model.cpp TGP_Model_Evaluator.cpp TGP_Model_Search.cpp\ - TGP_Output_Model.cpp utils.cpp Variable_Group.cpp VNS_Search.cpp + TGP_Output_Model.cpp utils.cpp Variable_Group.cpp VNS_Search.cpp\ + OrthogonalMesh.cpp pkginclude_HEADERS = Cache_File_Point.hpp Cache.hpp Cache_Point.hpp\ Cache_Search.hpp Clock.hpp defines.hpp Direction.hpp Directions.hpp\ Display.hpp Double.hpp Eval_Point.hpp Evaluator_Control.hpp\ Evaluator.hpp Exception.hpp Extended_Poll.hpp Filter_Point.hpp\ - L_Curve.hpp LH_Search.hpp Mads.hpp Mesh.hpp Model_Sorted_Point.hpp\ + L_Curve.hpp LH_Search.hpp Mads.hpp SMesh.hpp XMesh.hpp Model_Sorted_Point.hpp\ Model_Stats.hpp Multi_Obj_Evaluator.hpp\ Multi_Obj_Quad_Model_Evaluator.hpp nomad.hpp Parameter_Entries.hpp\ Parameter_Entry.hpp Parameters.hpp Pareto_Front.hpp Pareto_Point.hpp\ @@ -40,7 +42,7 @@ pkginclude_HEADERS = Cache_File_Point.hpp Cache.hpp Cache_Point.hpp\ Single_Obj_Quad_Model_Evaluator.hpp Slave.hpp Speculative_Search.hpp\ Stats.hpp TGP_Model_Evaluator.hpp TGP_Model.hpp TGP_Model_Search.hpp\ TGP_Output_Model.hpp Uncopyable.hpp utils.hpp Variable_Group.hpp\ - VNS_Search.hpp Barrier.hpp + VNS_Search.hpp Barrier.hpp OrthogonalMesh.hpp bin_PROGRAMS = nomad nomad_SOURCES = nomad.cpp diff --git a/src/Mesh.cpp b/src/Mesh.cpp deleted file mode 100644 index cd3bc7c..0000000 --- a/src/Mesh.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ -/* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ -/* Charles Audet - Ecole Polytechnique, Montreal */ -/* Gilles Couture - Ecole Polytechnique, Montreal */ -/* John Dennis - Rice University, Houston */ -/* Sebastien Le Digabel - Ecole Polytechnique, Montreal */ -/* Christophe Tribes - Ecole Polytechnique, Montreal */ -/* */ -/* funded in part by AFOSR and Exxon Mobil */ -/* */ -/* Author: Sebastien Le Digabel */ -/* */ -/* Contact information: */ -/* Ecole Polytechnique de Montreal - GERAD */ -/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ -/* e-mail: nomad@gerad.ca */ -/* phone : 1-514-340-6053 #6928 */ -/* fax : 1-514-340-5665 */ -/* */ -/* This program is free software: you can redistribute it and/or modify it under the */ -/* terms of the GNU Lesser General Public License as published by the Free Software */ -/* Foundation, either version 3 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 Lesser General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU Lesser General Public License along */ -/* with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* */ -/* You can find information on the NOMAD software at www.gerad.ca/nomad */ -/*-------------------------------------------------------------------------------------*/ -/** - \file Mesh.cpp - \brief Class for the MADS mesh (implementation) - \author Sebastien Le Digabel - \date 2010-04-06 - \see Mesh.hpp -*/ -#include "Mesh.hpp" - -/*-----------------------------------*/ -/* static members initialization */ -/*-----------------------------------*/ -double NOMAD::Mesh::_mesh_update_basis = 4.0; -int NOMAD::Mesh::_mesh_coarsening_exponent = 1; -int NOMAD::Mesh::_mesh_refining_exponent = -1; -int NOMAD::Mesh::_initial_mesh_index = 0; -int NOMAD::Mesh::_mesh_index = 0; -int NOMAD::Mesh::_min_mesh_index = 0; -int NOMAD::Mesh::_max_mesh_index = 0; -int NOMAD::Mesh::_max_halton_index = -1; - -/*-----------------------------------------------------------*/ -/* constructor */ -/*-----------------------------------------------------------*/ -NOMAD::Mesh::Mesh ( const NOMAD::Point & delta_m_0 , - const NOMAD::Point & delta_m_min , - const NOMAD::Point & delta_p_min ) - : _initial_mesh_size ( delta_m_0 ) , - _min_mesh_size ( delta_m_min ) , - _min_poll_size ( delta_p_min ) -{ - bool chkp = delta_p_min.is_defined(); - bool chkm = delta_m_min.is_defined(); - int k , n = delta_m_0.size(); - - if ( !delta_m_0.is_complete() ) - throw NOMAD::Exception ( "Mesh.cpp" , __LINE__ , - "NOMAD::Mesh::Mesh(): delta_m_0 has undefined values" ); - - if ( chkp && delta_p_min.size() != n ) - throw NOMAD::Exception ( "Mesh.cpp" , __LINE__ , - "NOMAD::Mesh::Mesh(): delta_m_0 and delta_p_min have different sizes" ); - - if ( chkm && delta_m_min.size() != n ) - throw NOMAD::Exception ( "Mesh.cpp" , __LINE__ , - "NOMAD::Mesh::Mesh(): delta_m_0 and delta_m_min have different sizes" ); - - // we check that delta_p_min <= delta_p_0 and that delta_m_min <= delta_m_0: - if ( chkp || chkm ) { - - NOMAD::Point * dp0 = NULL , * dm0 = NULL; - - if ( chkp ) { - dp0 = new NOMAD::Point ( n ); - get_delta_p ( *dp0 , NOMAD::Mesh::_initial_mesh_index ); - } - - if ( chkm ) { - dm0 = new NOMAD::Point ( n ); - get_delta_m ( *dm0 , NOMAD::Mesh::_initial_mesh_index ); - } - - std::string error; - - for ( k = 0 ; k < n ; ++k ) { - - if ( dp0 && - _min_poll_size[k].is_defined() && - (*dp0)[k] < _min_poll_size[k] ) { - error = "NOMAD::Mesh::Mesh(): delta_p_0 < delta_p_min"; - break; - } - - if ( dm0 && - _min_mesh_size[k].is_defined() && - (*dm0)[k] < _min_mesh_size[k] ) { - error = "NOMAD::Mesh::Mesh(): delta_m_0 < delta_m_min"; - break; - } - - } - - delete dp0; - delete dm0; - - if ( !error.empty() ) - throw NOMAD::Exception ( "Mesh.cpp" , __LINE__ , error ); - } -} - -/*-----------------------------------------------------------*/ -/* Mesh static members initialization (static) */ -/*-----------------------------------------------------------*/ -void NOMAD::Mesh::init ( double mesh_update_basis , - int mesh_coarsening_exponent , - int mesh_refining_exponent , - int initial_mesh_index ) -{ - NOMAD::Mesh::_mesh_update_basis = mesh_update_basis; - NOMAD::Mesh::_mesh_coarsening_exponent = mesh_coarsening_exponent; - NOMAD::Mesh::_mesh_refining_exponent = mesh_refining_exponent; - NOMAD::Mesh::_mesh_index = - NOMAD::Mesh::_initial_mesh_index = - NOMAD::Mesh::_min_mesh_index = - NOMAD::Mesh::_max_mesh_index = initial_mesh_index; - NOMAD::Mesh::_max_halton_index = -1; -} - -/*-----------------------------------------------------------*/ -/* update the mesh (static) */ -/*-----------------------------------------------------------*/ -void NOMAD::Mesh::update ( NOMAD::success_type success , int & mesh_index ) -{ - // defaults: - // full success: lk = lk - 1 - // failure : lk = lk + 1 - - if ( success == NOMAD::FULL_SUCCESS ) { - mesh_index -= NOMAD::Mesh::_mesh_coarsening_exponent; - if ( mesh_index < -NOMAD::L_LIMITS ) - mesh_index = -NOMAD::L_LIMITS; - } - else if ( success == NOMAD::UNSUCCESSFUL ) - mesh_index -= NOMAD::Mesh::_mesh_refining_exponent; - - if ( mesh_index > _max_mesh_index ) - _max_mesh_index = mesh_index; - - - if ( mesh_index < _min_mesh_index ) - _min_mesh_index = mesh_index; -} - -/*-----------------------------------------------------------*/ -/* manually set the mesh index (static) */ -/*-----------------------------------------------------------*/ -void NOMAD::Mesh::set_mesh_index ( int mesh_index ) -{ - NOMAD::Mesh::_mesh_index = mesh_index; - if ( mesh_index > _max_mesh_index ) - _max_mesh_index = mesh_index; - if ( mesh_index < _min_mesh_index ) - _min_mesh_index = mesh_index; -} - -/*-----------------------------------------------------------*/ -/* display */ -/*-----------------------------------------------------------*/ -void NOMAD::Mesh::display ( const NOMAD::Display & out ) const -{ - out << "n : " << get_n() << std::endl - << "mesh update basis : " << _mesh_update_basis << std::endl - << "mesh coarsening exponent: " << _mesh_coarsening_exponent << std::endl - << "mesh refining exponent : " << _mesh_refining_exponent << std::endl - << "initial mesh index : " << _initial_mesh_index << std::endl - << "initial mesh size : " - << "(" << _initial_mesh_size << " )" << std::endl; - out << "minimal mesh size : "; - if ( _min_mesh_size.is_defined() ) - out << "(" << _min_mesh_size << " )" << std::endl; - else - out << "none"; - out << std::endl - << "minimal poll size : "; - if ( _min_poll_size.is_defined() ) - out << "(" << _min_poll_size << " )" << std::endl; - else - out << "none"; - out << std::endl; -} - -/*----------------------------------------------------------*/ -/* check the stopping conditions on the minimal poll size */ -/* and on the minimal mesh size */ -/*----------------------------------------------------------*/ -void NOMAD::Mesh::check_min_mesh_sizes ( int max_mesh_index , - int mesh_index , - bool & stop , - NOMAD::stop_type & stop_reason ) const -{ - if ( stop ) - return; - - // 1. mesh index tests: - if ( abs ( mesh_index ) > NOMAD::L_LIMITS ) { - stop = true; - stop_reason = NOMAD::L_LIMITS_REACHED; - } - if ( max_mesh_index != NOMAD::UNDEFINED_L && mesh_index > max_mesh_index ) { - stop = true; - stop_reason = NOMAD::L_MAX_REACHED; - } - - // 2. delta_k^p (poll size) tests: - if ( check_min_poll_size_criterion ( mesh_index ) ) { - stop = true; - stop_reason = NOMAD::DELTA_P_MIN_REACHED; - } - - // 3. delta_k^m (mesh size) tests: - if ( check_min_mesh_size_criterion ( mesh_index ) ) { - stop = true; - stop_reason = NOMAD::DELTA_M_MIN_REACHED; - } -} - -/*-----------------------------------------------------------*/ -/* check the minimal poll size (private) */ -/*-----------------------------------------------------------*/ -bool NOMAD::Mesh::check_min_poll_size_criterion ( int mesh_index ) const -{ - if ( !_min_poll_size.is_defined() ) - return false; - NOMAD::Point delta_p; - return get_delta_p ( delta_p , mesh_index ); -} - -/*-----------------------------------------------------------*/ -/* check the minimal mesh size (private) */ -/*-----------------------------------------------------------*/ -bool NOMAD::Mesh::check_min_mesh_size_criterion ( int mesh_index ) const -{ - if ( !_min_mesh_size.is_defined() ) - return false; - NOMAD::Point delta_m; - return get_delta_m ( delta_m , mesh_index ); -} - -/*----------------------------------------------------------------*/ -/* get delta_m (mesh size parameter) */ -/* Delta^m_k = Delta^m_0 \tau^{ell_0^+ - ell_k^+} */ -/*----------------------------------------------------------------*/ -/* the function also returns true if one value is < delta_m_min */ -/* (stopping criterion MIN_MESH_SIZE) */ -/*----------------------------------------------------------------*/ -bool NOMAD::Mesh::get_delta_m ( NOMAD::Point & delta_m , int mesh_index ) const -{ - int n = get_n(); - delta_m.reset ( n ); - - // power_of_tau = tau^{ max{0,l0} - max{0,lk} }: - NOMAD::Double power_of_tau - = pow ( _mesh_update_basis , - ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) - - ( (mesh_index > 0) ? mesh_index : 0) ); - - bool stop = false; - bool mms_def = _min_mesh_size.is_defined(); - - // Delta^m_k = power_of_tau * Delta^m_0: - for ( int i = 0 ; i < n ; ++i ) - { - delta_m[i] = _initial_mesh_size[i] * power_of_tau; - if ( mms_def && !stop && _min_mesh_size[i].is_defined() && delta_m[i] < _min_mesh_size[i] ) - stop = true; - } - - return stop; -} - -/*----------------------------------------------------------------*/ -/* get delta_m (mesh size parameter) */ -/* Delta^m_k = Delta^m_0 \tau^{ell_0^+ - ell_k^+} */ -/*----------------------------------------------------------------*/ -/* static version */ -/*----------------------------------------------------------------*/ -void NOMAD::Mesh::get_delta_m ( NOMAD::Point & delta_m , - const NOMAD::Point & initial_mesh_size , - double mesh_update_basis , - int initial_mesh_index , - int mesh_index ) -{ - - int n = initial_mesh_size.size(); - delta_m.reset ( n ); - - // power_of_tau = tau^{ max{0,l0} - max{0,lk} }: - NOMAD::Double power_of_tau - = pow ( mesh_update_basis , - ( (initial_mesh_index > 0) ? initial_mesh_index : 0) - - ( (mesh_index > 0) ? mesh_index : 0) ); - - // Delta^m_k = power_of_tau * Delta^m_0: - for ( int i = 0 ; i < n ; ++i ) - delta_m[i] = initial_mesh_size[i] * power_of_tau; -} - -/*-------------------------------------------------------------------*/ -/* get delta_p (poll size parameter) */ -/* Delta^p_k = Delta^m_k \tau^{ |ell_k|/2 } */ -/* = Delta^m_0 \tau^{ell_0^+ - ell_k^+ + |ell_k|/2} */ -/*-------------------------------------------------------------------*/ -/* the function also returns true if all values are < delta_p_ */ -/* (stopping criterion MIN_POLL_SIZE) */ -/*-------------------------------------------------------------------*/ -bool NOMAD::Mesh::get_delta_p ( NOMAD::Point & delta_p , int mesh_index ) const -{ - int n = get_n(); - delta_p.reset ( n ); - - // power_of_tau = tau^{ max{0,l0} - max{0,lk} + |lk|/2}: - NOMAD::Double power_of_tau - = pow ( _mesh_update_basis , abs(mesh_index) / 2.0 + - ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) - - ( (mesh_index > 0) ? mesh_index : 0) ); - - bool stop = true; - - bool mps_def = _min_poll_size.is_defined(); - - // Delta^p_k = power_of_tau * Delta^m_0: - for ( int i = 0 ; i < n ; ++i ) - { - delta_p[i] = _initial_mesh_size[i] * power_of_tau; - if ( !mps_def || !_min_poll_size[i].is_defined() || delta_p[i] >= _min_poll_size[i] ) - stop = false; - } - - return stop; -} - -/*-------------------------------------------------------------------*/ -/* get delta_p (poll size parameter) */ -/* Delta^p_k = Delta^m_k \tau^{ |ell_k|/2 } */ -/* = Delta^m_0 \tau^{ell_0^+ - ell_k^+ + |ell_k|/2} */ -/*-------------------------------------------------------------------*/ -/* static version */ -/*-------------------------------------------------------------------*/ -void NOMAD::Mesh::get_delta_p ( NOMAD::Point & delta_p , - const NOMAD::Point & initial_mesh_size , - double mesh_update_basis , - int initial_mesh_index , - int mesh_index ) { - - int n = initial_mesh_size.size(); - delta_p.reset ( n ); - - // power_of_tau = tau^{ max{0,l0} - max{0,lk} + |lk|/2}: - NOMAD::Double power_of_tau - = pow ( mesh_update_basis , abs(mesh_index) / 2.0 + - ( (initial_mesh_index > 0) ? initial_mesh_index : 0) - - ( (mesh_index > 0) ? mesh_index : 0) ); - - // Delta^p_k = power_of_tau * Delta^m_0: - for ( int i = 0 ; i < n ; ++i ) - delta_p[i] = initial_mesh_size[i] * power_of_tau; -} diff --git a/src/Mesh.hpp b/src/Mesh.hpp deleted file mode 100644 index bd00a52..0000000 --- a/src/Mesh.hpp +++ /dev/null @@ -1,361 +0,0 @@ -/*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ -/* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ -/* Charles Audet - Ecole Polytechnique, Montreal */ -/* Gilles Couture - Ecole Polytechnique, Montreal */ -/* John Dennis - Rice University, Houston */ -/* Sebastien Le Digabel - Ecole Polytechnique, Montreal */ -/* Christophe Tribes - Ecole Polytechnique, Montreal */ -/* */ -/* funded in part by AFOSR and Exxon Mobil */ -/* */ -/* Author: Sebastien Le Digabel */ -/* */ -/* Contact information: */ -/* Ecole Polytechnique de Montreal - GERAD */ -/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ -/* e-mail: nomad@gerad.ca */ -/* phone : 1-514-340-6053 #6928 */ -/* fax : 1-514-340-5665 */ -/* */ -/* This program is free software: you can redistribute it and/or modify it under the */ -/* terms of the GNU Lesser General Public License as published by the Free Software */ -/* Foundation, either version 3 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 Lesser General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU Lesser General Public License along */ -/* with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* */ -/* You can find information on the NOMAD software at www.gerad.ca/nomad */ -/*-------------------------------------------------------------------------------------*/ -/** - \file Mesh.hpp - \brief Class for the MADS mesh (headers) - \author Sebastien Le Digabel - \date 2010-04-06 - \see Mesh.cpp -*/ -#ifndef __MESH__ -#define __MESH__ - -#include "Point.hpp" - -namespace NOMAD { - - /// Class for the MADS mesh. - /** - - The mesh in NOMAD is defined with the basic directions and the - mesh size parameter Delta^m_k. - - The mesh size parameter is defined with the mesh index (the integer ell_k). - - Use the static function \c NOMAD::Mesh::get_mesh_index() to access the value - of the mesh index ell_k. - - The poll size parameter Delta^p_k is not used to define the mesh but - to define the poll trial points. - - At each MADS iteration the mesh is updated with - Delta^m_k+1 = tau^w+ Delta^m_k and w+ >= 0 (dominating iteration) - or with - Delta^m_k+1 = tau^w- Delta^m_k and w- < 0 (iteration failure). - The mesh is not changed after improving iterations. - - Mesh and poll size parameters are stored as NOMAD::Point objects - (one value for each variable) in order to ensure automatic scaling. - - See the MADS papers for more details on the mesh. - */ - class Mesh { - - private: - - static double _mesh_update_basis; ///< Mesh update basis (tau) - static int _mesh_coarsening_exponent; ///< Mesh coarsening exponent (w+) - static int _mesh_refining_exponent; ///< Mesh refining exponent (w-) - static int _initial_mesh_index; ///< Initial mesh index (ell_0) - static int _mesh_index; ///< Mesh index (ell_k) - - static int _min_mesh_index; ///< Minimal value reached by the mesh index - static int _max_mesh_index; ///< Maximal value reached by the mesh index - - static int _max_halton_index; ///< Maximal Halton index for Ortho-MADS - - NOMAD::Point _initial_mesh_size; ///< Delta^m_0 (abs values; one delta/var) - - /// Equivalent of \c _min_poll_size for the mesh size parameter Delta^m_k. - NOMAD::Point _min_mesh_size; - - /// Delta^p_min (abs. values, one delta/var.); Can be undefined or incomplete. - NOMAD::Point _min_poll_size; - - /*--------------------------------------------------------------*/ - - /// Private affectation operator. - /** - \param m The right-hand side object -- \b IN. - */ - const Mesh & operator = ( const Mesh & m ); - - /// Check the minimal poll size criterion. - bool check_min_poll_size_criterion ( int mesh_index = Mesh::_mesh_index ) const; - - /// Check the minimal mesh size criterion. - bool check_min_mesh_size_criterion ( int mesh_index = Mesh::_mesh_index ) const; - - /*--------------------------------------------------------------*/ - - public: - - /// Constructor. - /** - \param delta_m_0 Initial mesh size Delta^m_0 -- \b IN. - \param delta_p_min Minimal poll size Delta^p_min (may be undefined) -- \b IN. - \param delta_m_min Minimal mesh size Delta^m_min (may be undefined) -- \b IN. - */ - Mesh ( const NOMAD::Point & delta_m_0 , - const NOMAD::Point & delta_p_min , - const NOMAD::Point & delta_m_min ); - - /// Copy constructor. - /** - \param m The copied object -- \b IN. - */ - Mesh ( const Mesh & m ) - : _initial_mesh_size ( m._initial_mesh_size ) , - _min_mesh_size ( m._min_mesh_size ) , - _min_poll_size ( m._min_poll_size ) {} - - /// Destructor. - virtual ~Mesh ( void ) {} - - /// Static members initialization. - /** - \param mesh_update_basis Mesh update basis (tau) -- \b IN. - \param mesh_coarsening_exponent Mesh coarsening exponent (w+) -- \b IN. - \param mesh_refining_exponent Mesh refining exponent (w-) -- \b IN. - \param initial_mesh_index Initial mesh index ell_0 -- \b IN. - */ - static void init ( double mesh_update_basis , - int mesh_coarsening_exponent , - int mesh_refining_exponent , - int initial_mesh_index ); - - /// Access to the initial mesh size. - /** - \return A NOMAD::Point for the initial mesh size. - */ - const NOMAD::Point & get_initial_mesh_size ( void ) const - { - return _initial_mesh_size; - } - - /// Access to the minimal mesh size. - /** - \return A NOMAD::Point for the minimal mesh size. - */ - const NOMAD::Point & get_min_mesh_size ( void ) const { return _min_mesh_size; } - - /// Access to the minimal poll size. - /** - \return A NOMAD::Point for the minimal poll size. - */ - const NOMAD::Point & get_min_poll_size ( void ) const { return _min_poll_size; } - - /// Access to the mesh index. - /** - \return An integer with the mesh index. - */ - static int get_mesh_index ( void ) { return Mesh::_mesh_index; } - - /// Manually set the mesh index. - /** - \param mesh_index The mesh index ell_k -- \b IN. - */ - static void set_mesh_index ( int mesh_index ); - - /// Access to the maximal mesh index. - /** - This corresponds to the maximal value of ell_k reached so far. - \return An integer with the maximal mesh index. - */ - static int get_max_mesh_index ( void ) { return Mesh::_max_mesh_index; } - - - /// Manually set the maximum mesh index. - /** - This corresponds to the maximum value of ell_k reached so far. - \param h The maximum mesh index -- \b IN. - */ - static void set_max_mesh_index ( int h ) { _max_mesh_index = h; } - - /// Access to the minimal mesh index. - /** - This corresponds to the minimal value of ell_k reached so far. - \return An integer with the minimal mesh index. - */ - static int get_min_mesh_index ( void ) { return Mesh::_min_mesh_index; } - - /// Manually set the minimum mesh index. - /** - This corresponds to the minimum value of ell_k reached so far. - \param h The minimum mesh index -- \b IN. - */ - static void set_min_mesh_index ( int h ) { _min_mesh_index = h; } - - /// Test if mesh index<max_mesh_index so far. - /** - \return True if mesh index lower than maximal mesh index False otherwise. - */ - // Use 1- Apply dynamic reduction of poll dir only if true - // use 2- Ortho n+1. Apply selection n directions out of 2n based on target dir only if true. Otherwise the selection alternates +/-. - static bool mesh_index_is_not_max(void){return Mesh::_mesh_index<Mesh::_max_mesh_index; /*true*/ } - - /// Access to the mesh update basis tau. - /** - \return A double with the mesh update basis tau. - */ - static double get_mesh_update_basis ( void ) { return Mesh::_mesh_update_basis; } - - /// Access to the maximal Halton index. - /** - This corresponds to the maximal value of the Halton index reached so far. - \return An integer with the maximal Halton index. - */ - static int get_max_halton_index ( void ) { return _max_halton_index; } - - /// Manually set the maximal Halton index. - /** - This corresponds to the maximal value of the Halton index reached so far. - \param h The maximal Halton index -- \b IN. - */ - static void set_max_halton_index ( int h ) { _max_halton_index = h; } - - /// Update the mesh (#1). - /** - \param success Type of success of the iteration -- \b IN. - \param mesh_index The mesh index before and after the update -- \b IN/OUT. - */ - static void update ( NOMAD::success_type success , int & mesh_index ); - - /// Update the mesh (#2). - /** - \param success Type of success of the iteration -- \b IN. - */ - static void update ( NOMAD::success_type success ) - { - Mesh::update ( success , Mesh::_mesh_index ); - } - - /// Access to the number of variables. - /** - This number of variables corresponds to the one used for the construction - of the current NOMAD::Mesh object. - \return An integer with the number of variables. - */ - int get_n ( void ) const { return _initial_mesh_size.size(); } - - /// Access to the mesh size parameter Delta^m_k. - /** - - The mesh size parameter is computed with - Delta^m_k = Delta^m_0 tau^{ell_0^+ - ell_k^+}. - - It is a NOMAD::Point of size \c nc the number of free variables. - \param delta_m The mesh size parameter Delta^m_k -- \b OUT. - \param mesh_index A mesh index ell_k -- \b IN - -- \b optional (default = the current mesh index ell_k.) - \return A boolean equal to \c true if all values are - strictly inferior than the associated minimal - mesh size Delta^m_min - (stopping criterion MIN_MESH_SIZE). - */ - bool get_delta_m ( NOMAD::Point & delta_m , - int mesh_index = Mesh::_mesh_index ) const; - - /// Access to the mesh size parameter Delta^m_k. - /** - - The mesh size parameter is computed with - Delta^m_k = Delta^m_0 tau^{ell_0^+ - ell_k^+}. - - It is a NOMAD::Point of size \c nc the number of free variables. - - This method is static and allows to compute mesh sizes - without a NOMAD::Mesh object. - \param delta_m Mesh size parameter Delta^m_k (size \c nc) -- \b OUT. - \param initial_mesh_size Initial mesh size Delta^m_0 (size \c nc) -- \b IN. - \param mesh_update_basis Mesh update basis tau -- \b IN. - \param initial_mesh_index Initial mesh index ell_0 -- \b IN. - \param mesh_index Mesh index ell_k -- \b IN. - */ - static void get_delta_m ( NOMAD::Point & delta_m , - const NOMAD::Point & initial_mesh_size , - double mesh_update_basis , - int initial_mesh_index , - int mesh_index ); - - /// Access to the poll size parameter Delta^p_k. - /** - - The poll size parameter is computed with - Delta^p_k = Delta^m_k tau^{ |ell_k|/2 } - = Delta^m_0 tau^{ell_0^+ - ell_k^+ + |ell_k|/2} - - It is a NOMAD::Point of size \c nc the number of free variables. - \param delta_p The poll size parameter Delta^p_k -- \b OUT. - \param mesh_index A mesh index -- \b IN - -- \b optional (default = the current mesh index ell_k.) - \return A boolean equal to \c true if all values are - strictly inferior than the associated minimal - poll size Delta^p_min - (stopping criterion MIN_POLL_SIZE). - */ - bool get_delta_p ( NOMAD::Point & delta_p , - int mesh_index = Mesh::_mesh_index ) const; - - /// Access to the poll size parameter Delta^p_k. - /** - - The poll size parameter is computed with - Delta^p_k = Delta^m_k tau^{ |ell_k|/2 } - = Delta^m_0 tau^{ell_0^+ - ell_k^+ + |ell_k|/2} - - It is a NOMAD::Point of size \c nc the number of free variables. - - This method is static and allows to compute poll sizes - without a NOMAD::Mesh object. - \param delta_p Poll size parameter Delta^p_k (size \c nc) -- \b OUT. - \param initial_mesh_size Initial mesh size Delta^m_0 (size \c nc) -- \b IN. - \param mesh_update_basis Mesh update basis tau -- \b IN. - \param initial_mesh_index Initial mesh index ell_0 -- \b IN. - \param mesh_index Mesh index ell_k -- \b IN. - */ - static void get_delta_p ( NOMAD::Point & delta_p , - const NOMAD::Point & initial_mesh_size , - double mesh_update_basis , - int initial_mesh_index , - int mesh_index ); - - /// Check the stopping conditions on the minimal poll and mesh sizes. - /** - \param max_mesh_index Maximal mesh index ell_max -- \b IN. - \param mesh_index Current mesh index ell_k -- \b IN. - \param stop Stop flag -- \b IN/OUT. - \param stop_reason Stop reason -- \b OUT. - */ - void check_min_mesh_sizes ( int max_mesh_index , - int mesh_index , - bool & stop , - NOMAD::stop_type & stop_reason ) const; - /// Display. - /** - \param out The NOMAD::Display object -- \b IN. - */ - void display ( const NOMAD::Display & out ) const; - }; - - /// Display a NOMAD::Mesh object. - /** - \param out The NOMAD::Display object -- \b IN. - \param m The NOMAD::Mesh object to be displayed -- \b IN. - \return The NOMAD::Display object. - */ - inline const NOMAD::Display & operator << ( const NOMAD::Display & out , - const NOMAD::Mesh & m ) - { - m.display ( out ); - return out; - } -} - -#endif diff --git a/src/Model_Sorted_Point.cpp b/src/Model_Sorted_Point.cpp index 0eaabf6..1afbbdb 100644 --- a/src/Model_Sorted_Point.cpp +++ b/src/Model_Sorted_Point.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Model_Sorted_Point.hpp b/src/Model_Sorted_Point.hpp index 195a47d..c1e1a7c 100644 --- a/src/Model_Sorted_Point.hpp +++ b/src/Model_Sorted_Point.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Model_Stats.cpp b/src/Model_Stats.cpp index 60b4201..bc18f4d 100644 --- a/src/Model_Stats.cpp +++ b/src/Model_Stats.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Model_Stats.hpp b/src/Model_Stats.hpp index 345fedd..1351a30 100644 --- a/src/Model_Stats.hpp +++ b/src/Model_Stats.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Multi_Obj_Evaluator.cpp b/src/Multi_Obj_Evaluator.cpp index 4cf8b81..89c5bfe 100644 --- a/src/Multi_Obj_Evaluator.cpp +++ b/src/Multi_Obj_Evaluator.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Multi_Obj_Evaluator.hpp b/src/Multi_Obj_Evaluator.hpp index e525c04..522cb4f 100644 --- a/src/Multi_Obj_Evaluator.hpp +++ b/src/Multi_Obj_Evaluator.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Multi_Obj_Quad_Model_Evaluator.hpp b/src/Multi_Obj_Quad_Model_Evaluator.hpp index 36cb9db..932fa5a 100644 --- a/src/Multi_Obj_Quad_Model_Evaluator.hpp +++ b/src/Multi_Obj_Quad_Model_Evaluator.hpp @@ -1,8 +1,7 @@ - /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version (3.5.1).7.2 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -38,7 +37,7 @@ \file Multi_Obj_Quad_Model_Evaluator.hpp \brief NOMAD::Mulit_Obj_Evaluator subclass for quadratic model optimization (headers) \author Christophe Tribes - \date 2012-06-19 + \date 2014-06-19 \see Multi_Obj_Quad_Model_Evaluator.cpp */ #ifndef __MULTI_OBJ_QUAD_MODEL_EVALUATOR__ @@ -59,11 +58,12 @@ namespace NOMAD { \param model Model -- \b IN. */ Multi_Obj_Quad_Model_Evaluator ( const NOMAD::Parameters & p , - const NOMAD::Quad_Model & model ) : NOMAD::Quad_Model_Evaluator(p,model),NOMAD::Multi_Obj_Evaluator(p) {;} + const NOMAD::Quad_Model & model ) : NOMAD::Quad_Model_Evaluator(p,model),NOMAD::Multi_Obj_Evaluator(p) {_is_model_evaluator=true;} /// Destructor. virtual ~Multi_Obj_Quad_Model_Evaluator ( void ){;} + /// Evaluate the blackboxes quad model at a given trial point /** \param x point to evaluate -- \b IN/OUT. diff --git a/src/OrthogonalMesh.cpp b/src/OrthogonalMesh.cpp new file mode 100644 index 0000000..1c7331a --- /dev/null +++ b/src/OrthogonalMesh.cpp @@ -0,0 +1,205 @@ +/*-------------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ +/* */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ +/* Charles Audet - Ecole Polytechnique, Montreal */ +/* Gilles Couture - Ecole Polytechnique, Montreal */ +/* John Dennis - Rice University, Houston */ +/* Sebastien Le Digabel - Ecole Polytechnique, Montreal */ +/* Christophe Tribes - Ecole Polytechnique, Montreal */ +/* */ +/* funded in part by AFOSR and Exxon Mobil */ +/* */ +/* Author: Sebastien Le Digabel */ +/* */ +/* Contact information: */ +/* Ecole Polytechnique de Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* phone : 1-514-340-6053 #6928 */ +/* fax : 1-514-340-5665 */ +/* */ +/* This program is free software: you can redistribute it and/or modify it under the */ +/* terms of the GNU Lesser General Public License as published by the Free Software */ +/* Foundation, either version 3 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 Lesser General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public License along */ +/* with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*-------------------------------------------------------------------------------------*/ +/** + \file OrthogonalMesh.hpp + \brief implementation + \author Christophe Tribes + \date 2014-06-19 + \see SMesh.cpp XMesh.cpp + */ + +#include "OrthogonalMesh.hpp" + +/// Constructor (called only by derived objects). +NOMAD::OrthogonalMesh::OrthogonalMesh (const NOMAD::Point & Delta_0 , + const NOMAD::Point & Delta_min , + const NOMAD::Point & delta_min , + const NOMAD::Point & fixed_variables , + NOMAD::Double update_basis, + int coarsening_step, + int refining_step, + int limit_mesh_index ) : +_delta_0 ( Delta_0 ), +_Delta_0 ( Delta_0 ), +_Delta_min ( Delta_min ), +_delta_min ( delta_min ), +_update_basis ( update_basis ), +_coarsening_step ( coarsening_step ), +_refining_step ( refining_step ), +_limit_mesh_index ( limit_mesh_index ) +{ + + _Delta_min_is_defined=_Delta_min.is_defined(); + _Delta_min_is_complete=_Delta_min.is_complete(); + + bool chkMesh = delta_min.is_defined(); + bool chkPoll = _Delta_min_is_defined; + _n = Delta_0.size(); + + + _n_free_variables = _n - fixed_variables.nb_defined(); + + // The delta_0 are decreased + _delta_0*=pow(_n_free_variables,-0.5); + + if ( !_Delta_0.is_complete() ) + throw NOMAD::Exception ( "OrthogonalMesh.hpp" , __LINE__ , + "NOMAD::OrthogonalMesh::OrthogonalMesh(): delta_0 has undefined values" ); + + if ( chkMesh && delta_min.size() != _n ) + throw NOMAD::Exception ( "OrthogonalMesh.hpp" , __LINE__ , + "NOMAD::OrthogonalMesh::OrthogonalMesh(): delta_0 and delta_min have different sizes" ); + + if ( chkPoll && Delta_min.size() != _n ) + throw NOMAD::Exception ( "OrthogonalMesh.hpp" , __LINE__ , + "NOMAD::OrthogonalMesh::OrthogonalMesh(): Delta_0 and Delta_min have different sizes" ); + + + std::string error; + for ( int k = 0 ; k < _n ; ++k ) + { + // we check that Delta_min <= Delta_0 and that delta_min <= delta_0: + if ( chkMesh && + _delta_min[k].is_defined() && + _delta_0[k] < _delta_min[k] ) + { + error = "NOMAD::OrthogonalMesh::OrthogonalMesh(): delta_0 < delta_min"; + break; + } + if ( chkPoll && + _Delta_min[k].is_defined() && + _Delta_0[k] < _Delta_min[k] ) + { + error = "NOMAD::OrthogonalMesh::OrthogonalMesh(): Delta_0 < Delta_min"; + break; + } + + } + + if ( !error.empty() ) + throw NOMAD::Exception ( "OrthogonalMesh.hpp" , __LINE__ , error ); +} + + + +bool NOMAD::OrthogonalMesh::is_finer_than_initial (void) const +{ + NOMAD::Point delta; + get_delta(delta); + + for (int i =0; i < _n ; ++i ) + if ( delta[i] >= _delta_0[i] ) + return false; + + return true; +} + + + +/// Manually set the min mesh size per coordinate. +void NOMAD::OrthogonalMesh::set_min_mesh_sizes ( const NOMAD::Point & delta_min ) +{ + + // If delta_min undefined than _delta_min->undefined + if ( ! delta_min.is_defined() ) + { + _delta_min.clear(); + return; + } + + // If delta_min defined test that everything is consistent + if ( delta_min.size() != _n ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::OrthogonalMesh::set_min_mesh_sizes() delta_min has dimension different than mesh dimension" ); + + if ( !delta_min.is_complete() ) + throw NOMAD::Exception ( "OrthogonalMesh.hpp" , __LINE__ , + "NOMAD::OrthogonalMesh::set_min_mesh_sizes(): delta_min has some defined and undefined values" ); + + std::string error; + for ( int k = 0 ; k < _n ; ++k ) + { + + // we check that Delta_min <= Delta_0 and that delta_min <= delta_0: + if ( delta_min[k].is_defined() && + _delta_0[k] < delta_min[k] ) + { + error = "NOMAD::OrthogonalMesh::set_delta_min(): delta_0 < delta_min"; + break; + } + if ( delta_min[k].is_defined() && + _Delta_0[k] < delta_min[k] ) + { + error = "NOMAD::OrthogonalMesh::set_delta_min(): Delta_0 < delta_min"; + break; + } + + } + + if ( !error.empty() ) + throw NOMAD::Exception ( "OrthogonalMesh.hpp" , __LINE__ , error ); + + _delta_min=delta_min; + +} + + + +/*-----------------------------------------------------------*/ +/* set delta_0 */ +/*-----------------------------------------------------------*/ +void NOMAD::OrthogonalMesh::set_delta_0 ( const NOMAD::Point & d ) +{ + + if ( d.size() != _delta_0.size() ) + throw NOMAD::Exception ( "OrthogonalMesh.hpp" , __LINE__ , + "NOMAD::OrthogonalMesh::set_delta_0(): dimension of provided delta_0 must be consistent with their previous dimension" ); + + _delta_0=d; +} + +/*-----------------------------------------------------------*/ +/* set Delta_0 */ +/*-----------------------------------------------------------*/ +void NOMAD::OrthogonalMesh::set_Delta_0 ( const NOMAD::Point & d ) +{ + + if ( d.size() != _Delta_0.size() ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::XMesh::set_Delta_0(): dimension of provided Delta_0 must be consistent with their previous dimension" ); + + _Delta_0=d; +} diff --git a/src/OrthogonalMesh.hpp b/src/OrthogonalMesh.hpp new file mode 100644 index 0000000..5971ae5 --- /dev/null +++ b/src/OrthogonalMesh.hpp @@ -0,0 +1,384 @@ +/*-------------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ +/* */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ +/* Charles Audet - Ecole Polytechnique, Montreal */ +/* Gilles Couture - Ecole Polytechnique, Montreal */ +/* John Dennis - Rice University, Houston */ +/* Sebastien Le Digabel - Ecole Polytechnique, Montreal */ +/* Christophe Tribes - Ecole Polytechnique, Montreal */ +/* */ +/* funded in part by AFOSR and Exxon Mobil */ +/* */ +/* Author: Sebastien Le Digabel */ +/* */ +/* Contact information: */ +/* Ecole Polytechnique de Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* phone : 1-514-340-6053 #6928 */ +/* fax : 1-514-340-5665 */ +/* */ +/* This program is free software: you can redistribute it and/or modify it under the */ +/* terms of the GNU Lesser General Public License as published by the Free Software */ +/* Foundation, either version 3 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 Lesser General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public License along */ +/* with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*-------------------------------------------------------------------------------------*/ +/** + \file OrthogonalMesh.hpp + \brief Virtual class for the MADS orthogonal meshes (headers) + \author Christophe Tribes + \date 2010-04-06 + \see Mesh.cpp XMesh.cpp +*/ +#ifndef __ORTHOGONALMESH__ +#define __ORTHOGONALMESH__ + +#include "Point.hpp" +#include "Direction.hpp" + +namespace NOMAD { + + /// Virtual class for the MADS orthogonal meshes. + /** + - An orthogonal mesh in NOMAD is defined with the basic orthogonal directions the + mesh size parameter delta^k. + - The poll size parameter Delta^k is not used to define the mesh but + to define the poll trial points. + - At each MADS iteration the mesh is updated. + - Mesh and poll size parameters are stored as NOMAD::Point objects. + */ + class OrthogonalMesh { + + /*--------------------------------------------------------------*/ + private: + + + /*--------------------------------------------------------------*/ + + /// Private affectation operator. + /** + \param m The right-hand side object -- \b IN. + */ + const OrthogonalMesh & operator = ( const OrthogonalMesh & m ); + + + /*--------------------------------------------------------------*/ + protected: + + + NOMAD::Point _delta_0; + NOMAD::Point _Delta_0; + NOMAD::Point _Delta_min; + NOMAD::Point _delta_min; + + + NOMAD::Double _update_basis; + int _coarsening_step; + int _refining_step ; + + int _n; + + bool _Delta_min_is_defined; + bool _Delta_min_is_complete; + + int _n_free_variables; + + int _limit_mesh_index; // Limit max or min of the mesh index for fine mesh (SMesh->max, XMesh->min) + + /// Constructor (called only by derived objects). + /** + \param Delta_0 Initial poll size Delta_0 -- \b IN. + \param Delta_min Minimal poll size Delta_min (may be undefined) -- \b IN. + \param delta_min Minimal mesh size delta_min (may be undefined) -- \b IN. + \param fixed_variables Fixed variables -- \b IN. + \param update_basis Mesh/poll update basis (tau) -- \b IN. + \param coarsening_step Mesh/poll coarsening exponent (w+) -- \b IN. + \param refining_step Mesh/poll refining exponent (w-) -- \b IN. + \param limit_mesh_index Limit mesh index to trigger stopping criterion -- \b IN. + */ + OrthogonalMesh (const NOMAD::Point & Delta_0 , + const NOMAD::Point & Delta_min , + const NOMAD::Point & delta_min , + const NOMAD::Point & fixed_variables , + NOMAD::Double update_basis, + int coarsening_step, + int refining_step, + int limit_mesh_index ) ; + + + /// Copy constructor (called only by derived objects). + /** + \param m The copied object -- \b IN. + */ + OrthogonalMesh ( const OrthogonalMesh & m ) + : _delta_0 ( m._delta_0 ), + _Delta_0 ( m._Delta_0 ), + _Delta_min ( m._Delta_min ), + _delta_min ( m._delta_min ), + _update_basis ( m._update_basis ), + _coarsening_step ( m._coarsening_step ), + _refining_step ( m._refining_step ), + _n ( m._n ), + _Delta_min_is_defined ( m._Delta_min_is_defined ), + _Delta_min_is_complete ( m._Delta_min_is_complete ), + _n_free_variables ( m._n_free_variables ), + _limit_mesh_index ( m._limit_mesh_index){} + + + /*--------------------------------------------------------------*/ + public: + + + /// Destructor. + virtual ~OrthogonalMesh ( void ){;} + + + /// Update the Mesh (poll and mesh sizes). + /** + \param success Type of success of the iteration -- \b IN. + \param dir Direction of the iteration (optional) -- \b IN. + */ + virtual void update ( NOMAD::success_type success, const NOMAD::Direction * dir=NULL) = 0; + + + /// Update the provided mesh indices (the Mesh is unchanged). + /** + \param success Type of success of the iteration -- \b IN. + \param mesh_indices Provided mesh indices for update -- \b IN/OUT. + \param dir Direction of the iteration (optional) -- \b IN. + */ + virtual void update ( NOMAD::success_type success, NOMAD::Point & mesh_indices, const NOMAD::Direction * dir=NULL ) const = 0; + + + + /// Reset the Mesh to its original sizes (poll and mesh sizes). + virtual void reset ( void ) = 0; + + + /// Access to the initial mesh size. + /** + \return A NOMAD::Point for the initial mesh size. + */ + const NOMAD::Point & get_initial_mesh_size ( void ) const { return _delta_0; } + + /// Access to the initial poll size. + /** + \return A NOMAD::Point for the initial poll size. + */ + const NOMAD::Point & get_initial_poll_size ( void ) const { return _Delta_0; } + + + /// Access to the minimal mesh size. + /** + \return A NOMAD::Point for the minimal mesh size. + */ + const NOMAD::Point & get_min_mesh_size ( void ) const { return _delta_min; } + + + /// Access to the minimal poll size. + /** + \return A NOMAD::Point for the minimal poll size. + */ + const NOMAD::Point & get_min_poll_size ( void ) const { return _Delta_min; } + + + /// Test if mesh is finest so far. + /** + \return True if mesh is the finest so far, False otherwise. + */ + virtual bool is_finest(void) const = 0; + + + /// Test if current mesh is finer than initial mesh (used by VNS search). + /** + \return True if mesh size is smaller than initial mesh size for all components. + */ + bool is_finer_than_initial (void) const; + + + /// Access to the mesh/poll update basis tau. + /** + \return A double with the update basis tau. + */ + double get_update_basis ( void ) const { return _update_basis.value(); } + + + /// Access to the mesh ratio after a success + /** + \return A point with the ratio for each coordinate + */ + virtual NOMAD::Point get_mesh_ratio_if_success( void ) const = 0; + + + /// Access to the number of variables. + /** + \return An integer with the number of variables. + */ + int get_n ( void ) const { return _n; } + + + /// Access to the number of free variables. + /** + \return An integer with the number of free variables. + */ + int get_n_free_variables ( void ) const { return _n_free_variables; } + + + /// Access to the mesh size parameter delta^k. + /** + \return delta The mesh size parameter delta^k -- \b OUT. + */ + NOMAD::Point get_delta ( void ) const + { + NOMAD::Point delta; + get_delta(delta); + return delta; + } + + /// Access to the mesh size parameter delta^k. + /** + \param delta The mesh size parameter delta^k -- \b OUT. + \return A boolean equal to \c true if all values are + strictly inferior than the associated minimal + mesh size delta_min + (stopping criterion MIN_MESH_SIZE). + */ + virtual bool get_delta ( NOMAD::Point & delta ) const = 0; + + /// Access to the largest mesh size. + /** + \return The largest mesh size -- \b OUT. + */ + virtual NOMAD::Point get_delta_max ( void ) const = 0; + + + /// Access to the poll size parameter Delta^k. + /** + \return Delta The poll size parameter Delta^k -- \b OUT. + */ + NOMAD::Point get_Delta ( void ) + { + NOMAD::Point Delta; + get_Delta(Delta); + return Delta; + } + + /// Access to the poll size parameter Delta^k. + /** + \param Delta The poll size parameter Delta^k -- \b OUT. + \return A boolean equal to \c true if all values are + strictly inferior than the associated minimal + mesh size delta_min + (stopping criterion MIN_POLL_SIZE). + */ + virtual bool get_Delta ( NOMAD::Point & Delta ) const = 0 ; + + + /// Display. + /** + \param out The NOMAD::Display object -- \b IN. + */ + virtual void display ( const NOMAD::Display & out ) const = 0; + + /// Check the stopping conditions on the minimal poll and mesh sizes. + /** + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + */ + virtual void check_min_mesh_sizes ( bool & stop , + NOMAD::stop_type & stop_reason ) const = 0; + + /// Access to the mesh indices per coordinate. + /** + \return A point with the mesh index for each coordinate. + */ + virtual const NOMAD::Point get_mesh_indices ( void ) const = 0; + + /// Manually set the mesh indices per coordinate (virtual). + /** + \param r The mesh index per coordinate -- \b IN. + */ + virtual void set_mesh_indices ( const NOMAD::Point & r ) =0 ; + + /// Manually set the min mesh size per coordinate. + /** + \param delta_min The min mesh sizes per coordinate (can be undefined) -- \b IN. + */ + void set_min_mesh_sizes ( const NOMAD::Point & delta_min ); + + /// Manually set intial mesh size per coordinate. + /** + \param d The initial mesh sizes per coordinate -- \b IN. + */ + void set_delta_0 ( const NOMAD::Point & d ); + + /// Manually set intial poll size per coordinate. + /** + \param d The initial poll sizes per coordinate -- \b IN. + */ + void set_Delta_0 ( const NOMAD::Point & d ); + + + /// Access to the min mesh indices reached so far. + /** + \return A point with the mesh index for each coordinate. + */ + virtual const NOMAD::Point get_min_mesh_indices ( void ) const = 0; + + /// Access to the max mesh indices reached so far. + /** + \return A point with the mesh index for each coordinate. + */ + virtual const NOMAD::Point get_max_mesh_indices ( void ) const = 0; + + + /// Access to the limit mesh index. + /** + \return An integer with the limit mesh index. + */ + int get_limit_mesh_index ( void ) const { return _limit_mesh_index;} + + + /// Manually set the limit mesh index. + /** + \param limit_mesh_index The limit mesh index. + */ + virtual void set_limit_mesh_index ( int limit_mesh_index ) = 0; + + + /// Scale and project the ith component of a vector on the mesh + /** + \param i The vector component number -- \b IN. + \param l The vector component value -- \b IN. + \return The ith component of a vector after mesh scaling and projection + */ + virtual NOMAD::Double scale_and_project(int i, const NOMAD::Double & l) const = 0 ; + + + }; + + /// Display a NOMAD::OrthogonalMesh object. + /** + \param out The NOMAD::Display object -- \b IN. + \param m The NOMAD::OrthogonalMesh object to be displayed -- \b IN. + \return The NOMAD::Display object. + */ + inline const NOMAD::Display & operator << ( const NOMAD::Display & out , + const NOMAD::OrthogonalMesh & m ) + { + m.display ( out ); + return out; + } +} + +#endif diff --git a/src/Parameter_Entries.cpp b/src/Parameter_Entries.cpp index 5b30143..6a7392c 100644 --- a/src/Parameter_Entries.cpp +++ b/src/Parameter_Entries.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Parameter_Entries.hpp b/src/Parameter_Entries.hpp index 7c1d9e1..aff4d01 100644 --- a/src/Parameter_Entries.hpp +++ b/src/Parameter_Entries.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Parameter_Entry.cpp b/src/Parameter_Entry.cpp index 069e559..de60272 100644 --- a/src/Parameter_Entry.cpp +++ b/src/Parameter_Entry.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -57,6 +57,10 @@ NOMAD::Parameter_Entry::Parameter_Entry ( const std::string & entry , std::string s; std::istringstream in ( entry ); in >> _name; + + if (_name.size()==0) + return; + if ( remove_comments && _name[0] == '#' ) _name.clear(); else { diff --git a/src/Parameter_Entry.hpp b/src/Parameter_Entry.hpp index 5333af5..7c1e0b9 100644 --- a/src/Parameter_Entry.hpp +++ b/src/Parameter_Entry.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Parameters.cpp b/src/Parameters.cpp index 3d22e53..cf218fe 100644 --- a/src/Parameters.cpp +++ b/src/Parameters.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -42,6 +42,8 @@ */ #include "Parameters.hpp" #include "Slave.hpp" +#include "XMesh.hpp" +#include "SMesh.hpp" bool NOMAD::Parameters::_warning_has_been_displayed=false; @@ -50,9 +52,9 @@ bool NOMAD::Parameters::_warning_has_been_displayed=false; /*----------------------------------------*/ NOMAD::Parameters::~Parameters ( void ) { - delete _std_signature; - delete_x0s(); - reset_variable_groups(); + delete _std_signature; + delete_x0s(); + reset_variable_groups(); } /*----------------------------------------*/ @@ -60,174 +62,183 @@ NOMAD::Parameters::~Parameters ( void ) /*----------------------------------------*/ void NOMAD::Parameters::init ( void ) { - // miscellaneous and algorithm parameters: - _to_be_checked = true; - _seed = NOMAD::get_pid(); - _max_eval = -1; - _max_sim_bb_eval = -1; - _max_bb_eval = -1; - _max_bbe_decided = false; - _max_time = -1; - _max_iterations = -1; - _max_cons_failed_it = -1; - _max_cache_memory = 2000; - _cache_save_period = 25; - _snap_to_bounds = true; - _stop_if_feasible = false; - _user_calls_enabled = true; - _asynchronous = true; - _stat_sum_target.clear(); - _L_curve_target.clear(); - _cache_file.clear(); - _problem_dir.clear(); - _tmp_dir.clear(); - - // F_TARGET: - reset_f_target(); - - // output files: - _add_seed_to_file_names = true; - _solution_file.clear(); - _history_file.clear(); - - // NOMAD::Double static members: - set_EPSILON ( NOMAD::DEFAULT_EPSILON ); - set_UNDEF_STR ( NOMAD::DEFAULT_UNDEF_STR ); - set_INF_STR ( NOMAD::DEFAULT_INF_STR ); - - // Mesh: - _mesh_update_basis.clear(); - _mesh_coarsening_exponent = 1; - _mesh_refining_exponent =-1; - _initial_mesh_index = 0; - _max_mesh_index = NOMAD::UNDEFINED_L; - _min_poll_size_defined = false; - _initial_mesh_size.clear(); - _min_mesh_size.clear(); - _min_poll_size.clear(); - - // Directions: - reset_directions ( -1 ); - - // X0: - reset_X0(); - - // signature: - delete _std_signature; - _std_signature = NULL; - - // variables: - _dimension = -1; - _nb_free_variables = -1; - _extended_poll_trigger = 0.1; - _relative_ept = true; - _extended_poll_enabled = true; - _bb_input_include_tag = false; - _bb_input_include_seed = false; - _bb_redirection = true; - _bb_input_type.clear(); - _neighbors_exe.clear(); - reset_bounds(); - reset_scaling(); - reset_fixed_variables(); - reset_periodic_variables(); - reset_variable_groups(); - - // Barrier: - _rho = 0.1; - _h_min = 0.0; - _h_max_0 = NOMAD::INF; - _h_norm = NOMAD::L2; - _has_constraints = false; - _has_EB_constraints = false; - _has_filter_constraints = false; - _barrier_type = NOMAD::EB; - - // outputs: - _index_obj.clear(); - _bb_exe.clear(); - _bb_output_type.clear(); - _index_cnt_eval = -1; - _index_stat_sum = -1; - _index_stat_avg = -1; - - // surrogate: - _sgte_exe.clear(); - _sgte_cache_file.clear(); - _sgte_eval_sort = true; - _has_sgte = false; - _opt_only_sgte = false; - _sgte_cost = -1; - _sgte_max_eval = -1; - - // MULTI-MADS: - _multi_nb_mads_runs = -1; - _multi_overall_bb_eval = -1; - _multi_use_delta_crit = false; - _multi_formulation = NOMAD::UNDEFINED_FORMULATION; - _multi_f_bounds.reset(); - - // model disabled - _disable_models=false; - - - // model search parameters: - _model_params.search1 = NOMAD::QUADRATIC_MODEL; - _model_params.search2 = NOMAD::NO_MODEL; - - _model_params.search_proj_to_mesh = true; - _model_params.search_optimistic = true; - _model_params.search_max_trial_pts = 10; - - // model ordering parameters: - _model_params.eval_sort = NOMAD::QUADRATIC_MODEL; - _model_params.eval_sort_cautious = true; - - // quadratic model parameters: - _model_params.quad_radius_factor = 2.0; - _model_params.quad_use_WP = false; - _model_params.quad_min_Y_size = -1; - _model_params.quad_max_Y_size = 500; - _model_params.model_np1_quad_epsilon =0.01; - - // TGP model parameters: - _model_params.tgp_mode = NOMAD::TGP_FAST; - _model_params.tgp_reuse_model = true; - - // other searches: - _VNS_trigger.clear(); - _speculative_search = true; - _VNS_search = false; - _LH_search_p0 = -1; - _LH_search_pi = -1; - _opportunistic_LH = true; - _opp_LH_is_defined = false; - _cache_search = false; - _opportunistic_cache_search = false; - _opp_CS_is_defined = false; - - // opportunistic strategy: - _opportunistic_eval = true; - _opportunistic_min_nb_success = -1; - _opportunistic_min_eval = -1; - _opportunistic_lucky_eval = false; - _opportunistic_min_f_imprvmt.clear(); - - // display: - _out.set_degrees ( NOMAD::NORMAL_DISPLAY ); + // miscellaneous and algorithm parameters: + _to_be_checked = true; + _seed = 0; + // _seed = NOMAD::get_pid(); + _max_eval = -1; + _max_sim_bb_eval = -1; + _max_bb_eval = -1; + _max_bbe_decided = false; + _max_time = -1; + _max_iterations = -1; + _max_cons_failed_it = -1; + _max_cache_memory = 2000; + _cache_save_period = 25; + _snap_to_bounds = true; + _stop_if_feasible = false; + _user_calls_enabled = true; + _asynchronous = true; + _stat_sum_target.clear(); + _L_curve_target.clear(); + _cache_file.clear(); + _problem_dir.clear(); + _tmp_dir.clear(); + + // F_TARGET: + reset_f_target(); + + // output files: + _add_seed_to_file_names = true; + _solution_file.clear(); + _history_file.clear(); + + // NOMAD::Double static members: + set_EPSILON ( NOMAD::DEFAULT_EPSILON ); + set_UNDEF_STR ( NOMAD::DEFAULT_UNDEF_STR ); + set_INF_STR ( NOMAD::DEFAULT_INF_STR ); + + // Mesh: + _anisotropic_mesh = true; + _use_smesh = false; + _mesh_update_basis = 4; + _poll_update_basis = 2; + _mesh_coarsening_exponent = 1; + _mesh_refining_exponent =-1; + _initial_mesh_index = 0; + _min_poll_size_defined = false; + _initial_mesh_size.clear(); + _initial_poll_size.clear(); + _min_mesh_size.clear(); + _min_poll_size.clear(); + + // Directions: + reset_directions ( ); + + // X0: + reset_X0(); + + // signature: + delete _std_signature; + _std_signature = NULL; + + // variables: + _dimension = -1; + _nb_free_variables = -1; + _extended_poll_trigger = 0.1; + _relative_ept = true; + _extended_poll_enabled = true; + _bb_input_include_tag = false; + _bb_input_include_seed = false; + _bb_redirection = true; + _bb_input_type.clear(); + _neighbors_exe.clear(); + reset_bounds(); + reset_scaling(); + reset_fixed_variables(); + reset_periodic_variables(); + reset_variable_groups(); + + // Barrier: + _rho = 0.1; + _h_min = 0.0; + _h_max_0 = NOMAD::INF; + _h_norm = NOMAD::L2; + _has_constraints = false; + _has_EB_constraints = false; + _has_filter_constraints = false; + _barrier_type = NOMAD::EB; + + // outputs: + _index_obj.clear(); + _bb_exe.clear(); + _bb_output_type.clear(); + _index_cnt_eval = -1; + _index_stat_sum = -1; + _index_stat_avg = -1; + + // surrogate: + _sgte_exe.clear(); + _sgte_cache_file.clear(); + _sgte_eval_sort = true; + _has_sgte = false; + _opt_only_sgte = false; + _sgte_cost = -1; + _sgte_max_eval = -1; + + // MULTI-MADS: + _multi_nb_mads_runs = -1; + _multi_overall_bb_eval = -1; + _multi_use_delta_crit = false; + _multi_formulation = NOMAD::UNDEFINED_FORMULATION; + _multi_f_bounds.reset(); + + // model is not disabled + _disable_models=false; + + // sort is not disabled + _disable_eval_sort=false; + + + // model search parameters: + _model_params.search1 = NOMAD::QUADRATIC_MODEL; + _model_params.search2 = NOMAD::NO_MODEL; + + _model_params.search_proj_to_mesh = true; + _model_params.search_optimistic = true; + _model_params.search_max_trial_pts = 10; + + // model ordering parameters: + _model_params.eval_sort = NOMAD::QUADRATIC_MODEL; + _model_params.eval_sort_cautious = false; + + // quadratic model parameters: + _model_params.quad_radius_factor = 2.0; + _model_params.quad_use_WP = false; + _model_params.quad_min_Y_size = -1; + _model_params.quad_max_Y_size = 500; + _model_params.model_np1_quad_epsilon =0.01; + + // TGP model parameters: + _model_params.tgp_mode = NOMAD::TGP_FAST; + _model_params.tgp_reuse_model = true; + + // other searches: + _VNS_trigger.clear(); + _speculative_search = true; + _VNS_search = false; + _LH_search_p0 = -1; + _LH_search_pi = -1; + _opportunistic_LH = true; + _opp_LH_is_defined = false; + _cache_search = false; + _opportunistic_cache_search = false; + _opp_CS_is_defined = false; + + // opportunistic strategy: + _bb_max_block_size = 1; + _eval_points_as_block = false; + _opportunistic_eval = true; + _opportunistic_min_nb_success = -1; + _opportunistic_min_eval = -1; + _opportunistic_lucky_eval = false; + _opportunistic_min_f_imprvmt.clear(); + + // display: + _out.set_degrees ( NOMAD::NORMAL_DISPLAY ); #ifdef DEBUG - set_POINT_DISPLAY_LIMIT ( -1 ); + set_POINT_DISPLAY_LIMIT ( -1 ); #else - set_POINT_DISPLAY_LIMIT ( NOMAD::DEFAULT_POINT_DISPLAY_LIMIT ); + set_POINT_DISPLAY_LIMIT ( NOMAD::DEFAULT_POINT_DISPLAY_LIMIT ); #endif - - _out.set_open_brace ( "{" ); - _out.set_closed_brace ( "}" ); - - _display_stats.clear(); - reset_stats_file(); - - _display_all_eval = false; + + _out.set_open_brace ( "{" ); + _out.set_closed_brace ( "}" ); + + _display_stats.clear(); + reset_stats_file(); + + _display_all_eval = false; } /*------------------------------------------------------------------*/ @@ -236,10 +247,10 @@ void NOMAD::Parameters::init ( void ) /*------------------------------------------------------------------*/ void NOMAD::Parameters::delete_x0s ( void ) { - size_t x0n = _x0s.size(); - for ( size_t i = 0 ; i < x0n ; ++i ) - delete _x0s[i]; - _x0s.clear(); + size_t x0n = _x0s.size(); + for ( size_t i = 0 ; i < x0n ; ++i ) + delete _x0s[i]; + _x0s.clear(); } /*----------------------------------------*/ @@ -247,20 +258,19 @@ void NOMAD::Parameters::delete_x0s ( void ) /*----------------------------------------*/ void NOMAD::Parameters::reset_X0 ( void ) { - _to_be_checked = true; - delete_x0s(); - _x0_cache_file.clear(); + _to_be_checked = true; + delete_x0s(); + _x0_cache_file.clear(); } /*----------------------------------------*/ /* reset the directions */ /*----------------------------------------*/ -void NOMAD::Parameters::reset_directions ( int halton_seed ) +void NOMAD::Parameters::reset_directions ( void ) { - _to_be_checked = true; - _direction_types.clear(); - _sec_poll_dir_types.clear(); - _halton_seed = halton_seed; + _to_be_checked = true; + _direction_types.clear(); + _sec_poll_dir_types.clear(); } /*--------------------------------------------*/ @@ -269,20 +279,20 @@ void NOMAD::Parameters::reset_directions ( int halton_seed ) bool NOMAD::Parameters::check_display_stats ( const std::list<std::string> & stats ) const { - int var_index; - std::list<std::string>::const_iterator it , end = stats.end(); - for ( it = stats.begin() ; it != end ; ++it ) { - if ( !it->empty() && - NOMAD::Display::get_display_stats_type(*it) == NOMAD::DS_VAR ) { - ++it; - if ( !NOMAD::atoi ( *it , var_index ) || - var_index < 0 || - var_index >= _dimension ) { - return false; - } - } - } - return true; + int var_index; + std::list<std::string>::const_iterator it , end = stats.end(); + for ( it = stats.begin() ; it != end ; ++it ) { + if ( !it->empty() && + NOMAD::Display::get_display_stats_type(*it) == NOMAD::DS_VAR ) { + ++it; + if ( !NOMAD::atoi ( *it , var_index ) || + var_index < 0 || + var_index >= _dimension ) { + return false; + } + } + } + return true; } /*--------------------------------------------*/ @@ -290,38 +300,38 @@ bool NOMAD::Parameters::check_display_stats /*--------------------------------------------*/ bool NOMAD::Parameters::check_directory ( std::string & s ) { - // step 1: remove spaces at the begining: - size_t i = 0 , ns = s.size(); - while ( i < ns && s[i] == ' ' ) - ++i; - std::string ss; - while ( i < ns ) - ss.push_back(s[i++]); - if ( ss.empty() ) - return false; - s = ss; - - // step 2: replace '/' or '\' with DIR_SEP: - i = 0; - ns = s.size(); - while ( i < ns ) { - if ( s[i] == '/' || s[i] == '\\' ) - s[i] = NOMAD::DIR_SEP; - ++i; - } - - // step 3: add DIR_SEP at the end: - if ( i >= 1 ) { - if (s[i-1] != NOMAD::DIR_SEP) { - s += NOMAD::DIR_SEP; - } - } - else { - s = "."; - s.push_back ( NOMAD::DIR_SEP ); - } - - return true; + // step 1: remove spaces at the begining: + size_t i = 0 , ns = s.size(); + while ( i < ns && s[i] == ' ' ) + ++i; + std::string ss; + while ( i < ns ) + ss.push_back(s[i++]); + if ( ss.empty() ) + return false; + s = ss; + + // step 2: replace '/' or '\' with DIR_SEP: + i = 0; + ns = s.size(); + while ( i < ns ) { + if ( s[i] == '/' || s[i] == '\\' ) + s[i] = NOMAD::DIR_SEP; + ++i; + } + + // step 3: add DIR_SEP at the end: + if ( i >= 1 ) { + if (s[i-1] != NOMAD::DIR_SEP) { + s += NOMAD::DIR_SEP; + } + } + else { + s = "."; + s.push_back ( NOMAD::DIR_SEP ); + } + + return true; } /*---------------------------------------------------------------*/ @@ -331,38 +341,38 @@ bool NOMAD::Parameters::check_directory ( std::string & s ) void NOMAD::Parameters::interpret_periodic_var ( const NOMAD::Parameter_Entries & entries ) { - int i , j , k; - std::list<std::string>::const_iterator it , end; - NOMAD::Parameter_Entry * pe = entries.find ( "PERIODIC_VARIABLE" ); - - while ( pe ) { - - // just one variable index (can be '*' or a range of indexes 'i-j'): - if ( pe->get_nb_values() == 1 ) { - - it = pe->get_values().begin(); - if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: PERIODIC_VARIABLE" ); - - for ( k = i ; k <= j ; ++k ) - set_PERIODIC_VARIABLE (k); - } - - // list of variable indexes: - else { - end = pe->get_values().end(); - for ( it = pe->get_values().begin() ; it != end ; ++it ) { - if ( !NOMAD::atoi ( *it , i ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: PERIODIC_VARIABLE" ); - set_PERIODIC_VARIABLE (i); - } - } - - pe->set_has_been_interpreted(); - pe = pe->get_next(); - } + int i , j , k; + std::list<std::string>::const_iterator it , end; + NOMAD::Parameter_Entry * pe = entries.find ( "PERIODIC_VARIABLE" ); + + while ( pe ) { + + // just one variable index (can be '*' or a range of indexes 'i-j'): + if ( pe->get_nb_values() == 1 ) { + + it = pe->get_values().begin(); + if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: PERIODIC_VARIABLE" ); + + for ( k = i ; k <= j ; ++k ) + set_PERIODIC_VARIABLE (k); + } + + // list of variable indexes: + else { + end = pe->get_values().end(); + for ( it = pe->get_values().begin() ; it != end ; ++it ) { + if ( !NOMAD::atoi ( *it , i ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: PERIODIC_VARIABLE" ); + set_PERIODIC_VARIABLE (i); + } + } + + pe->set_has_been_interpreted(); + pe = pe->get_next(); + } } /*------------------------------------------------------------*/ @@ -371,46 +381,45 @@ void NOMAD::Parameters::interpret_periodic_var /*------------------------------------------------------------*/ void NOMAD::Parameters::interpret_var_groups ( const NOMAD::Parameter_Entries & entries ) { - int i , j , k; - std::set<int> var_indexes; - std::list<std::string>::const_iterator it , end; - NOMAD::Parameter_Entry * pe = entries.find ( "VARIABLE_GROUP" ); - - while ( pe ) { - - // just one variable index (can be '*' or a range of indexes 'i-j'): - if ( pe->get_nb_values() == 1 ) { - - it = pe->get_values().begin(); - if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VARIABLE_GROUP" ); - - for ( k = j ; k >= i ; --k ) - var_indexes.insert(k); - } - - // list of variable indexes: - else { - end = pe->get_values().end(); - for ( it = pe->get_values().begin() ; it != end ; ++it ) { - if ( !NOMAD::atoi ( *it , i ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VARIABLE_GROUP" ); - var_indexes.insert(i); - } - } - - set_VARIABLE_GROUP ( var_indexes , - _direction_types , - _sec_poll_dir_types , - -1 ); - - var_indexes.clear(); - - pe->set_has_been_interpreted(); - pe = pe->get_next(); - } + int i , j , k; + std::set<int> var_indexes; + std::list<std::string>::const_iterator it , end; + NOMAD::Parameter_Entry * pe = entries.find ( "VARIABLE_GROUP" ); + + while ( pe ) { + + // just one variable index (can be '*' or a range of indexes 'i-j'): + if ( pe->get_nb_values() == 1 ) { + + it = pe->get_values().begin(); + if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VARIABLE_GROUP" ); + + for ( k = j ; k >= i ; --k ) + var_indexes.insert(k); + } + + // list of variable indexes: + else { + end = pe->get_values().end(); + for ( it = pe->get_values().begin() ; it != end ; ++it ) { + if ( !NOMAD::atoi ( *it , i ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VARIABLE_GROUP" ); + var_indexes.insert(i); + } + } + + set_VARIABLE_GROUP ( var_indexes , + _direction_types , + _sec_poll_dir_types ); + + var_indexes.clear(); + + pe->set_has_been_interpreted(); + pe = pe->get_next(); + } } /*------------------------------------------------------*/ @@ -421,180 +430,180 @@ void NOMAD::Parameters::interpret_var_groups ( const NOMAD::Parameter_Entries & /* (private) */ /*------------------------------------------------------*/ void NOMAD::Parameters::interpret_BFVS ( const NOMAD::Parameter_Entries & entries , - const std::string & param_name ) -{ - // param_name == LOWER_BOUND or UPPER_BOUND or FIXED_VARIABLE: - if ( param_name != "LOWER_BOUND" && - param_name != "UPPER_BOUND" && - param_name != "FIXED_VARIABLE" && - param_name != "SCALING" ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "wrong use of Parameters::interpret_BFVS()" ); - - NOMAD::Parameter_Entry * pe = entries.find ( param_name ); - std::list<std::string>::const_iterator it; - int i, j, k; - NOMAD::Double v; - std::string err; - std::string file_name; - std::ifstream fin; - - while ( pe ) - { - - // file name or just one index: - if ( pe->get_nb_values() == 1 ) - { - - // special case for FIXED_VARIABLE without value - // (the value will be taken from x0, if unique): - if ( isdigit ( (*pe->get_values().begin())[0] ) || - *pe->get_values().begin() == "*" ) - { - - if ( param_name[0] != 'F' ) - { - err = "invalid parameter: " + param_name - + " - only one argument, which is not a file name"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - if ( _x0s.size() != 1 || !_x0_cache_file.empty() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "FIXED_VARIABLE with only a variable index and no unique x0" ); - - if ( !NOMAD::string_to_index_range ( *pe->get_values().begin() , - i , - j , - &_dimension ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: FIXED_VARIABLE" ); - - for ( k = i ; k <= j ; ++k ) - set_FIXED_VARIABLE ( k , (*_x0s[0])[k] ); - } - - - // file name: - else { - - file_name = _problem_dir + *pe->get_values().begin(); - - fin.open ( file_name.c_str() ); - - if ( fin.fail() ) - { - err = "invalid parameter: " + param_name + - " - could not open file \'" + file_name + "\'"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - try { - switch ( param_name[0] ) { - case 'L': - _lb.reset ( _dimension ); - fin >> _lb; - break; - case 'U': - _ub.reset ( _dimension ); - fin >> _ub; - break; - case 'F': - _fixed_variables.reset ( _dimension ); - fin >> _fixed_variables; - break; - case 'S': - _scaling.reset ( _dimension ); - fin >> _scaling; - } - } - catch ( NOMAD::Point::Bad_Input & ) { - err = "invalid parameter: " + param_name + - " - could not read file \'" + file_name + "\'"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - fin.close(); - } - } - - // vector form: all values on one row: - else if ( pe->get_nb_values() == _dimension + 2 ) { - - if ( !pe->is_unique() ) { - err = "invalid parameter: " + param_name + - " - has been given in vector form with [] or () and is not unique"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - it = pe->get_values().begin(); - - if ( *it != "[" && *it != "(" ) { - err = "invalid parameter: " + param_name + - " - error in vector form with () or []"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - ++it; - for ( k = 0 ; k < _dimension ; ++k ) { - if ( !v.atof(*it) ) { - err = "invalid parameter: " + param_name; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - ++it; - switch ( param_name[0] ) { - case 'L': set_LOWER_BOUND ( k , v ); - break; - case 'U': set_UPPER_BOUND ( k , v ); - break; - case 'F': set_FIXED_VARIABLE ( k , v ); - break; - case 'S': set_SCALING ( k , v ); - } - } - - if ( *it != "]" && *it != ")" ) { - err = "invalid parameter: " + param_name + - " - error in vector form with () or []"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - } - - // indexed values: - else { - - if ( pe->get_nb_values() != 2 ) { - err = "invalid parameter: " + param_name; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - it = pe->get_values().begin(); - if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) { - err = "invalid parameter: " + param_name; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - ++it; - if ( !v.atof(*it) ) { - err = "invalid parameter: " + param_name; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - for ( k = j ; k >= i ; --k ) - switch (param_name[0]) { - case 'L': set_LOWER_BOUND ( k, v ); - break; - case 'U': set_UPPER_BOUND ( k, v ); - break; - case 'F': set_FIXED_VARIABLE ( k, v ); - break; - case 'S': set_SCALING ( k, v ); - } - } - pe->set_has_been_interpreted(); - pe = pe->get_next(); - } + const std::string & param_name ) +{ + // param_name == LOWER_BOUND or UPPER_BOUND or FIXED_VARIABLE: + if ( param_name != "LOWER_BOUND" && + param_name != "UPPER_BOUND" && + param_name != "FIXED_VARIABLE" && + param_name != "SCALING" ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "wrong use of Parameters::interpret_BFVS()" ); + + NOMAD::Parameter_Entry * pe = entries.find ( param_name ); + std::list<std::string>::const_iterator it; + int i, j, k; + NOMAD::Double v; + std::string err; + std::string file_name; + std::ifstream fin; + + while ( pe ) + { + + // file name or just one index: + if ( pe->get_nb_values() == 1 ) + { + + // special case for FIXED_VARIABLE without value + // (the value will be taken from x0, if unique): + if ( isdigit ( (*pe->get_values().begin())[0] ) || + *pe->get_values().begin() == "*" ) + { + + if ( param_name[0] != 'F' ) + { + err = "invalid parameter: " + param_name + + " - only one argument, which is not a file name"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + if ( _x0s.size() != 1 || !_x0_cache_file.empty() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "FIXED_VARIABLE with only a variable index and no unique x0" ); + + if ( !NOMAD::string_to_index_range ( *pe->get_values().begin() , + i , + j , + &_dimension ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: FIXED_VARIABLE" ); + + for ( k = i ; k <= j ; ++k ) + set_FIXED_VARIABLE ( k , (*_x0s[0])[k] ); + } + + + // file name: + else { + + file_name = _problem_dir + *pe->get_values().begin(); + + fin.open ( file_name.c_str() ); + + if ( fin.fail() ) + { + err = "invalid parameter: " + param_name + + " - could not open file \'" + file_name + "\'"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + try { + switch ( param_name[0] ) { + case 'L': + _lb.reset ( _dimension ); + fin >> _lb; + break; + case 'U': + _ub.reset ( _dimension ); + fin >> _ub; + break; + case 'F': + _fixed_variables.reset ( _dimension ); + fin >> _fixed_variables; + break; + case 'S': + _scaling.reset ( _dimension ); + fin >> _scaling; + } + } + catch ( NOMAD::Point::Bad_Input & ) { + err = "invalid parameter: " + param_name + + " - could not read file \'" + file_name + "\'"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + fin.close(); + } + } + + // vector form: all values on one row: + else if ( pe->get_nb_values() == _dimension + 2 ) { + + if ( !pe->is_unique() ) { + err = "invalid parameter: " + param_name + + " - has been given in vector form with [] or () and is not unique"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + it = pe->get_values().begin(); + + if ( *it != "[" && *it != "(" ) { + err = "invalid parameter: " + param_name + + " - error in vector form with () or []"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + ++it; + for ( k = 0 ; k < _dimension ; ++k ) { + if ( !v.atof(*it) ) { + err = "invalid parameter: " + param_name; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + ++it; + switch ( param_name[0] ) { + case 'L': set_LOWER_BOUND ( k , v ); + break; + case 'U': set_UPPER_BOUND ( k , v ); + break; + case 'F': set_FIXED_VARIABLE ( k , v ); + break; + case 'S': set_SCALING ( k , v ); + } + } + + if ( *it != "]" && *it != ")" ) { + err = "invalid parameter: " + param_name + + " - error in vector form with () or []"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + } + + // indexed values: + else { + + if ( pe->get_nb_values() != 2 ) { + err = "invalid parameter: " + param_name; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + it = pe->get_values().begin(); + if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) { + err = "invalid parameter: " + param_name; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + ++it; + if ( !v.atof(*it) ) { + err = "invalid parameter: " + param_name; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + for ( k = j ; k >= i ; --k ) + switch (param_name[0]) { + case 'L': set_LOWER_BOUND ( k, v ); + break; + case 'U': set_UPPER_BOUND ( k, v ); + break; + case 'F': set_FIXED_VARIABLE ( k, v ); + break; + case 'S': set_SCALING ( k, v ); + } + } + pe->set_has_been_interpreted(); + pe = pe->get_next(); + } } /*----------------------------------------------------------------*/ @@ -602,64 +611,64 @@ void NOMAD::Parameters::interpret_BFVS ( const NOMAD::Parameter_Entries & entrie /*----------------------------------------------------------------*/ void NOMAD::Parameters::interpret_f_target ( const NOMAD::Parameter_Entries & entries ) { - NOMAD::Double d; - std::list<std::string>::const_iterator it; - NOMAD::Parameter_Entry * pe = entries.find ( "F_TARGET" ); - - if ( pe ) - { - - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: F_TARGET not unique" ); - - it = pe->get_values().begin(); - - int nb_values = pe->get_nb_values(); - - // just one value: single-objective optimization: - if ( nb_values == 1 ) - { - - if ( !d.atof ( *it ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: F_TARGET" ); - set_F_TARGET (d); - } - - // vector form: multi-objective optimization: - else - { - - nb_values -= 2; - - NOMAD::Point f_target ( nb_values ); - - if ( *it != "[" && *it != "(" ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: F_TARGET - error in vector form with () or []" ); - - ++it; - - for ( int k = 0 ; k < nb_values ; ++k ) - { - - if ( !d.atof ( *it ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: F_TARGET" ); - ++it; - - f_target[k] = d; - } - - if ( *it != "]" && *it != ")" ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: F_TARGET - error in vector form with () or []" ); - - set_F_TARGET ( f_target ); - } - pe->set_has_been_interpreted(); - } + NOMAD::Double d; + std::list<std::string>::const_iterator it; + NOMAD::Parameter_Entry * pe = entries.find ( "F_TARGET" ); + + if ( pe ) + { + + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: F_TARGET not unique" ); + + it = pe->get_values().begin(); + + int nb_values = pe->get_nb_values(); + + // just one value: single-objective optimization: + if ( nb_values == 1 ) + { + + if ( !d.atof ( *it ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: F_TARGET" ); + set_F_TARGET (d); + } + + // vector form: multi-objective optimization: + else + { + + nb_values -= 2; + + NOMAD::Point f_target ( nb_values ); + + if ( *it != "[" && *it != "(" ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: F_TARGET - error in vector form with () or []" ); + + ++it; + + for ( int k = 0 ; k < nb_values ; ++k ) + { + + if ( !d.atof ( *it ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: F_TARGET" ); + ++it; + + f_target[k] = d; + } + + if ( *it != "]" && *it != ")" ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: F_TARGET - error in vector form with () or []" ); + + set_F_TARGET ( f_target ); + } + pe->set_has_been_interpreted(); + } } /*-------------------------------------------------------------*/ @@ -670,116 +679,137 @@ void NOMAD::Parameters::interpret_mesh_sizes ( const NOMAD::Parameter_Entries & entries , const std::string & param_name ) { - // param_name == "INITIAL_MESH_SIZE" or "MIN_MESH_SIZE" or "MIN_POLL_SIZE": - if ( param_name != "INITIAL_MESH_SIZE" && - param_name != "MIN_MESH_SIZE" && - param_name != "MIN_POLL_SIZE" ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "wrong use of Parameters::interpret_mesh_sizes()" ); - - int i , j , k; - NOMAD::Double v; - bool relative; - std::string err; - std::list<std::string>::const_iterator it; - NOMAD::Parameter_Entry * pe = entries.find ( param_name ); - - while ( pe ) { - - // just one value: - if ( pe->get_nb_values() == 1 ) { - - if ( !pe->is_unique() ) { - err = "invalid parameter: " + param_name - + " - has been given with just one value and is not unique"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - if ( !v.relative_atof ( *pe->get_values().begin() , relative ) ) { - err = "invalid parameter: " + param_name; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - if ( param_name[0] == 'I' ) - set_INITIAL_MESH_SIZE ( v , relative ); - else if ( param_name[4] == 'M' ) - set_MIN_MESH_SIZE ( v , relative ); - else - set_MIN_POLL_SIZE ( v , relative ); - } - - // indexed form: - else if ( pe->get_nb_values() == 2 ) { - - it = pe->get_values().begin(); - if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) { - err = "invalid parameter: " + param_name; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - ++it; - - if ( !v.relative_atof( *it , relative ) ) { - err = "invalid parameter: " + param_name; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - for ( k = i ; k <= j ; ++k ) { - if ( param_name[0] == 'I' ) - set_INITIAL_MESH_SIZE ( k , v , relative ); - else if ( param_name[4] == 'M' ) - set_MIN_MESH_SIZE ( k , v , relative ); - else - set_MIN_POLL_SIZE ( k , v , relative ); - } - } - - // vector form: all values on one row: - else if ( pe->get_nb_values() == _dimension + 2 ) { - - if ( !pe->is_unique() ) { - err = "invalid parameter: " + param_name - + " - has been given in vector form with [] or () and is not unique"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - it = pe->get_values().begin(); - - if ( *it != "[" && *it != "(" ) { - err = "invalid parameter: " + param_name + - " - error in vector form with () or []"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - ++it; - for ( k = 0 ; k < _dimension ; ++k ) { - if ( !v.relative_atof ( *it , relative ) ) { - err = "invalid parameter: " + param_name; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - ++it; - if ( param_name[0] == 'I' ) - set_INITIAL_MESH_SIZE ( k , v , relative ); - else if ( param_name[4] == 'M' ) - set_MIN_MESH_SIZE ( k , v , relative ); - else - set_MIN_POLL_SIZE ( k , v , relative ); - } - - if ( *it != "]" && *it != ")" ) { - err = "invalid parameter: " + param_name + - " - error in vector form with () or []"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - } - - else { - err = "invalid parameter: " + param_name; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - pe->set_has_been_interpreted(); - pe = pe->get_next(); - } + // param_name == "INITIAL_MESH_SIZE" or "INITIAL_MESH_SIZE" or "MIN_MESH_SIZE" or "MIN_POLL_SIZE": + if ( param_name != "INITIAL_POLL_SIZE" && + param_name != "INITIAL_MESH_SIZE" && + param_name != "MIN_MESH_SIZE" && + param_name != "MIN_POLL_SIZE" ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "wrong use of Parameters::interpret_mesh_sizes()" ); + + int i , j , k; + NOMAD::Double v; + bool relative; + std::string err; + std::list<std::string>::const_iterator it; + NOMAD::Parameter_Entry * pe = entries.find ( param_name ); + + while ( pe ) + { + + // just one value: + if ( pe->get_nb_values() == 1 ) + { + + if ( !pe->is_unique() ) + { + err = "invalid parameter: " + param_name + + " - has been given with just one value and is not unique"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + if ( !v.relative_atof ( *pe->get_values().begin() , relative ) ) + { + err = "invalid parameter: " + param_name; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + if ( param_name[0] == 'I' && param_name[8] =='M') + set_INITIAL_MESH_SIZE ( v , relative ); + else if ( param_name[0] == 'I' && param_name[8] =='P') + set_INITIAL_POLL_SIZE ( v , relative ); + else if ( param_name[4] == 'M' ) + set_MIN_MESH_SIZE ( v , relative ); + else + set_MIN_POLL_SIZE ( v , relative ); + } + + // indexed form: + else if ( pe->get_nb_values() == 2 ) + { + + it = pe->get_values().begin(); + if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) + { + err = "invalid parameter: " + param_name; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + ++it; + + if ( !v.relative_atof( *it , relative ) ) + { + err = "invalid parameter: " + param_name; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + for ( k = i ; k <= j ; ++k ) + { + if ( param_name[0] == 'I' && param_name[8] =='M') + set_INITIAL_MESH_SIZE ( k , v , relative ); + else if ( param_name[0] == 'I' && param_name[8] =='P') + set_INITIAL_POLL_SIZE ( k , v , relative ); + else if ( param_name[4] == 'M' ) + set_MIN_MESH_SIZE ( k , v , relative ); + else + set_MIN_POLL_SIZE ( k , v , relative ); + } + } + + // vector form: all values on one row: + else if ( pe->get_nb_values() == _dimension + 2 ) + { + + if ( !pe->is_unique() ) { + err = "invalid parameter: " + param_name + + " - has been given in vector form with [] or () and is not unique"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + it = pe->get_values().begin(); + + if ( *it != "[" && *it != "(" ) + { + err = "invalid parameter: " + param_name + + " - error in vector form with () or []"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + ++it; + for ( k = 0 ; k < _dimension ; ++k ) + { + if ( !v.relative_atof ( *it , relative ) ) + { + err = "invalid parameter: " + param_name; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + ++it; + if ( param_name[0] == 'I' && param_name[8] =='M' ) + set_INITIAL_MESH_SIZE ( k , v , relative ); + if ( param_name[0] == 'I' && param_name[8] =='P' ) + set_INITIAL_POLL_SIZE ( k , v , relative ); + else if ( param_name[4] == 'M' ) + set_MIN_MESH_SIZE ( k , v , relative ); + else + set_MIN_POLL_SIZE ( k , v , relative ); + } + + if ( *it != "]" && *it != ")" ) + { + err = "invalid parameter: " + param_name + + " - error in vector form with () or []"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + } + + else + { + err = "invalid parameter: " + param_name; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + pe->set_has_been_interpreted(); + pe = pe->get_next(); + } } /*---------------------------------------------------------------------------------*/ @@ -793,64 +823,64 @@ void NOMAD::Parameters::interpret_mesh_sizes void NOMAD::Parameters::interpret_bb_input_type ( const NOMAD::Parameter_Entries & entries ) { - int i , j , k; - NOMAD::bb_input_type bbit; - std::list<std::string>::const_iterator it; - NOMAD::Parameter_Entry * pe = entries.find ( "BB_INPUT_TYPE" ); - - while ( pe ) { - - // indexed form: - if ( pe->get_nb_values() == 2 ) { - - it = pe->get_values().begin(); - if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_TYPE" ); - ++it; - if ( !NOMAD::string_to_bb_input_type ( *it , bbit ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_TYPE" ); - - for ( k = i ; k <= j ; ++k ) - set_BB_INPUT_TYPE ( k , bbit ); - } - - // vector form: all values on one row: - else if ( pe->get_nb_values() == _dimension + 2 ) { - - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - std::string ( "invalid parameter: BB_INPUT_TYPE " ) - + " - has been given in vector form with [] or () and is not unique" ); - - it = pe->get_values().begin(); - - if ( *it != "[" && *it != "(" ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_TYPE - error in vector form with () or []" ); - - ++it; - for ( k = 0 ; k < _dimension ; ++k ) { - if ( !NOMAD::string_to_bb_input_type ( *it , bbit ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_TYPE" ); - ++it; - set_BB_INPUT_TYPE ( k , bbit ); - } - - if ( *it != "]" && *it != ")" ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_TYPE - error in vector form with () ot []" ); - } - - else - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_TYPE" ); - - pe->set_has_been_interpreted(); - pe = pe->get_next(); - } + int i , j , k; + NOMAD::bb_input_type bbit; + std::list<std::string>::const_iterator it; + NOMAD::Parameter_Entry * pe = entries.find ( "BB_INPUT_TYPE" ); + + while ( pe ) { + + // indexed form: + if ( pe->get_nb_values() == 2 ) { + + it = pe->get_values().begin(); + if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_TYPE" ); + ++it; + if ( !NOMAD::string_to_bb_input_type ( *it , bbit ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_TYPE" ); + + for ( k = i ; k <= j ; ++k ) + set_BB_INPUT_TYPE ( k , bbit ); + } + + // vector form: all values on one row: + else if ( pe->get_nb_values() == _dimension + 2 ) { + + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + std::string ( "invalid parameter: BB_INPUT_TYPE " ) + + " - has been given in vector form with [] or () and is not unique" ); + + it = pe->get_values().begin(); + + if ( *it != "[" && *it != "(" ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_TYPE - error in vector form with () or []" ); + + ++it; + for ( k = 0 ; k < _dimension ; ++k ) { + if ( !NOMAD::string_to_bb_input_type ( *it , bbit ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_TYPE" ); + ++it; + set_BB_INPUT_TYPE ( k , bbit ); + } + + if ( *it != "]" && *it != ")" ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_TYPE - error in vector form with () ot []" ); + } + + else + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_TYPE" ); + + pe->set_has_been_interpreted(); + pe = pe->get_next(); + } } /*------------------------------------------------*/ @@ -859,153 +889,153 @@ void NOMAD::Parameters::interpret_bb_input_type /*------------------------------------------------*/ void NOMAD::Parameters::interpret_x0 ( const NOMAD::Parameter_Entries & entries ) { - NOMAD::Parameter_Entry * pe = entries.find ( "X0" ); - std::list<std::string>::const_iterator it; - int i , j , k , l; - NOMAD::Double v; - NOMAD::Point tmp_x0; - std::vector<int> indexes; - - while ( pe ) { - - tmp_x0.reset ( _dimension ); - - // File name: - if ( pe->get_nb_values() == 1 ) - set_X0 ( *pe->get_values().begin() ); - - // Vector form: all values on one row: - else if ( pe->get_nb_values() == _dimension + 2 ) { - - it = pe->get_values().begin(); - - if ( *it != "[" && *it != "(" ) { - - // particular case with n=1 and 3 entry values: - // example: X0 1 0 4.0 (first coordinate of the 2nd x0 point put to 4.0) - if ( _dimension == 1 ) { - - it = pe->get_values().begin(); - - if ( !NOMAD::atoi ( *it , l ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: X0" ); - - i = static_cast<int> ( indexes.size() ); - if ( l > i ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: X0" ); - else if ( l == i ) { - l = static_cast<int> ( _x0s.size() ); - indexes.push_back ( l ); - set_X0 ( tmp_x0 ); - } - else - l = indexes[l]; - - ++it; - if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: X0" ); - - if ( i != 0 && j != 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: X0" ); - - ++it; - if ( !v.atof(*it) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: X0" ); - - (*_x0s[l])[0] = v; - } - - else - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: X0 - error in vector form with () or []" ); - } - - else { - - ++it; - for ( k = 0 ; k < _dimension ; ++k ) { - if ( !v.atof(*it) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: X0" ); - ++it; - tmp_x0[k] = v; - } - - if ( *it != "]" && *it != ")" ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: X0 - error in vector form with () or []" ); - - set_X0 ( tmp_x0 ); - } - } - - // indexed values without x0 index (must be unique) - // (example: X0 0-5 1.0): - else if ( pe->get_nb_values() == 2 ) { - - it = pe->get_values().begin(); - if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); - ++it; - if ( !v.atof(*it) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); - - if ( indexes.empty() ) { - l = static_cast<int> ( _x0s.size() ); - indexes.push_back ( l ); - set_X0 ( tmp_x0 ); - } - else - l = indexes[0]; - - for ( k = j ; k >= i ; --k ) - (*_x0s[l])[k] = v; - } - - // indexed values with x0 index - // example: X0 0 0-5 1.0 --> first x0 point - // X0 1 0-5 2.0 --> 2nd x0 point - else { - - if ( pe->get_nb_values() != 3 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); - - it = pe->get_values().begin(); - - if ( !NOMAD::atoi ( *it , l ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); - - i = static_cast<int> ( indexes.size() ); - if ( l > i ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); - else if ( l == i ) { - l = static_cast<int> ( _x0s.size() ); - indexes.push_back ( l ); - set_X0 ( tmp_x0 ); - } - else - l = indexes[l]; - - ++it; - if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); - - ++it; - if ( !v.atof(*it) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); - - for ( k = j ; k >= i ; --k ) - (*_x0s[l])[k] = v; - - } - pe->set_has_been_interpreted(); - pe = pe->get_next(); - } + NOMAD::Parameter_Entry * pe = entries.find ( "X0" ); + std::list<std::string>::const_iterator it; + int i , j , k , l; + NOMAD::Double v; + NOMAD::Point tmp_x0; + std::vector<int> indexes; + + while ( pe ) { + + tmp_x0.reset ( _dimension ); + + // File name: + if ( pe->get_nb_values() == 1 ) + set_X0 ( *pe->get_values().begin() ); + + // Vector form: all values on one row: + else if ( pe->get_nb_values() == _dimension + 2 ) { + + it = pe->get_values().begin(); + + if ( *it != "[" && *it != "(" ) { + + // particular case with n=1 and 3 entry values: + // example: X0 1 0 4.0 (first coordinate of the 2nd x0 point put to 4.0) + if ( _dimension == 1 ) { + + it = pe->get_values().begin(); + + if ( !NOMAD::atoi ( *it , l ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: X0" ); + + i = static_cast<int> ( indexes.size() ); + if ( l > i ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: X0" ); + else if ( l == i ) { + l = static_cast<int> ( _x0s.size() ); + indexes.push_back ( l ); + set_X0 ( tmp_x0 ); + } + else + l = indexes[l]; + + ++it; + if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: X0" ); + + if ( i != 0 && j != 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: X0" ); + + ++it; + if ( !v.atof(*it) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: X0" ); + + (*_x0s[l])[0] = v; + } + + else + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: X0 - error in vector form with () or []" ); + } + + else { + + ++it; + for ( k = 0 ; k < _dimension ; ++k ) { + if ( !v.atof(*it) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: X0" ); + ++it; + tmp_x0[k] = v; + } + + if ( *it != "]" && *it != ")" ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: X0 - error in vector form with () or []" ); + + set_X0 ( tmp_x0 ); + } + } + + // indexed values without x0 index (must be unique) + // (example: X0 0-5 1.0): + else if ( pe->get_nb_values() == 2 ) { + + it = pe->get_values().begin(); + if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); + ++it; + if ( !v.atof(*it) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); + + if ( indexes.empty() ) { + l = static_cast<int> ( _x0s.size() ); + indexes.push_back ( l ); + set_X0 ( tmp_x0 ); + } + else + l = indexes[0]; + + for ( k = j ; k >= i ; --k ) + (*_x0s[l])[k] = v; + } + + // indexed values with x0 index + // example: X0 0 0-5 1.0 --> first x0 point + // X0 1 0-5 2.0 --> 2nd x0 point + else { + + if ( pe->get_nb_values() != 3 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); + + it = pe->get_values().begin(); + + if ( !NOMAD::atoi ( *it , l ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); + + i = static_cast<int> ( indexes.size() ); + if ( l > i ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); + else if ( l == i ) { + l = static_cast<int> ( _x0s.size() ); + indexes.push_back ( l ); + set_X0 ( tmp_x0 ); + } + else + l = indexes[l]; + + ++it; + if ( !NOMAD::string_to_index_range ( *it , i , j , &_dimension ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); + + ++it; + if ( !v.atof(*it) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: X0" ); + + for ( k = j ; k >= i ; --k ) + (*_x0s[l])[k] = v; + + } + pe->set_has_been_interpreted(); + pe = pe->get_next(); + } } /*----------------------------------------*/ @@ -1013,77 +1043,77 @@ void NOMAD::Parameters::interpret_x0 ( const NOMAD::Parameter_Entries & entries /*----------------------------------------*/ void NOMAD::Parameters::read ( const std::string & param_file ) { - // parameters will have to be checked: - _to_be_checked = true; - - // PROBLEM_DIR: - // ------------ - _problem_dir.clear(); - size_t k = param_file.find_last_of ( NOMAD::DIR_SEP ); - if ( k >= 0 && k < param_file.size() ) - _problem_dir = param_file.substr (0,k) + NOMAD::DIR_SEP; - else - _problem_dir = std::string(".") + NOMAD::DIR_SEP; - - // open the parameters file: - std::string err = "could not open parameters file \'" + param_file + "\'"; - std::ifstream fin; - if ( NOMAD::check_read_file ( param_file ) ) { - fin.open ( param_file.c_str() ); - if ( !fin.fail() ) - err.clear(); - } - if ( !err.empty() ) { - fin.close(); - throw NOMAD::Exception ( "Parameters.cpp" , __LINE__ , err ); - } - - // the set of entries: - NOMAD::Parameter_Entries entries; - - // the file is read: fill the set 'entries' of Parameter_Entry: - NOMAD::Parameter_Entry * pe; - std::string s; - - while ( fin.good() && !fin.eof() ) - { - - s.clear(); - - getline ( fin , s ); - - if ( !fin.fail() && !s.empty() ) - { - pe = new NOMAD::Parameter_Entry ( s ); - if ( pe->is_ok() ) - entries.insert ( pe ); // pe will be deleted by ~Parameter_Entries() - else - { - if ( ( pe->get_name() != "" && pe->get_nb_values() == 0 ) || - pe->get_name() == "STATS_FILE" ) - { - err = "invalid parameter: " + pe->get_name(); - delete pe; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - delete pe; - } - } - } - - // the file is closed: - fin.close(); - - // entries display: + // parameters will have to be checked: + _to_be_checked = true; + + // PROBLEM_DIR: + // ------------ + _problem_dir.clear(); + size_t k = param_file.find_last_of ( NOMAD::DIR_SEP ); + if ( k < param_file.size() ) + _problem_dir = param_file.substr (0,k) + NOMAD::DIR_SEP; + else + _problem_dir = std::string(".") + NOMAD::DIR_SEP; + + // open the parameters file: + std::string err = "could not open parameters file \'" + param_file + "\'"; + std::ifstream fin; + if ( NOMAD::check_read_file ( param_file ) ) { + fin.open ( param_file.c_str() ); + if ( !fin.fail() ) + err.clear(); + } + if ( !err.empty() ) { + fin.close(); + throw NOMAD::Exception ( "Parameters.cpp" , __LINE__ , err ); + } + + // the set of entries: + NOMAD::Parameter_Entries entries; + + // the file is read: fill the set 'entries' of Parameter_Entry: + NOMAD::Parameter_Entry * pe; + std::string s; + + while ( fin.good() && !fin.eof() ) + { + + s.clear(); + + getline ( fin , s ); + + if ( !fin.fail() && !s.empty() ) + { + pe = new NOMAD::Parameter_Entry ( s ); + if ( pe->is_ok() ) + entries.insert ( pe ); // pe will be deleted by ~Parameter_Entries() + else + { + if ( ( pe->get_name() != "" && pe->get_nb_values() == 0 ) || + pe->get_name() == "STATS_FILE" ) + { + err = "invalid parameter: " + pe->get_name(); + delete pe; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + delete pe; + } + } + } + + // the file is closed: + fin.close(); + + // entries display: #ifdef DEBUG - if ( NOMAD::Slave::is_master() ) - _out << std::endl - << NOMAD::open_block ( "parsing of \'" + param_file + "\'" ) - << entries - << NOMAD::close_block(); + if ( NOMAD::Slave::is_master() ) + _out << std::endl + << NOMAD::open_block ( "parsing of \'" + param_file + "\'" ) + << entries + << NOMAD::close_block(); #endif - - read(entries); + + read(entries); } /*----------------------------------------*/ @@ -1091,1705 +1121,1760 @@ void NOMAD::Parameters::read ( const std::string & param_file ) /*----------------------------------------*/ void NOMAD::Parameters::read ( const NOMAD::Parameter_Entries & entries ) { - - // interpret and set the entries using SET methods: - std::list<std::string>::const_iterator it , end; - int i , j , m; - NOMAD::Double d; - NOMAD::Parameter_Entry * pe; - std::string s; - std::string err ; - - /*----------------------------------------------*/ - - // EPSILON: - // -------- - { - pe = entries.find ( "EPSILON" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: EPSILON not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: EPSILON" ); - set_EPSILON (d); - pe->set_has_been_interpreted(); - } - } - - // UNDEF_STR: - // ---------- - pe = entries.find ( "UNDEF_STR" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: UNDEF_STR not unique" ); - set_UNDEF_STR ( *(pe->get_values().begin()) ); - pe->set_has_been_interpreted(); - } - - // INF_STR: - // -------- - pe = entries.find ( "INF_STR" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: INF_STR not unique" ); - set_INF_STR ( *(pe->get_values().begin()) ); - pe->set_has_been_interpreted(); - } - - // MESH_UPDATE_BASIS: - // ------------------ - { - pe = entries.find ( "MESH_UPDATE_BASIS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MESH_UPDATE_BASIS not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MESH_UPDATE_BASIS" ); - set_MESH_UPDATE_BASIS (d); - pe->set_has_been_interpreted(); - } - } - - // INITIAL_MESH_INDEX: - // ------------------- - { - pe = entries.find ( "INITIAL_MESH_INDEX" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: INITIAL_MESH_INDEX not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: INITIAL_MESH_INDEX" ); - pe->set_has_been_interpreted(); - set_INITIAL_MESH_INDEX (i); - } - } - - // MESH_REFINING_EXPONENT: - // ----------------------- - { - pe = entries.find ( "MESH_REFINING_EXPONENT" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MESH_REFINING_EXPONENT not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MESH_REFINING_EXPONENT" ); - pe->set_has_been_interpreted(); - set_MESH_REFINING_EXPONENT (i); - } - } - - // MESH_COARSENING_EXPONENT: - // ------------------------- - { - pe = entries.find ( "MESH_COARSENING_EXPONENT" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MESH_COARSENING_EXPONENT not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MESH_COARSENING_EXPONENT" ); - pe->set_has_been_interpreted(); - set_MESH_COARSENING_EXPONENT (i); - } - } - - // MAX_MESH_INDEX: - // --------------- - { - pe = entries.find ( "MAX_MESH_INDEX" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_MESH_INDEX not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_MESH_INDEX" ); - pe->set_has_been_interpreted(); - set_MAX_MESH_INDEX (i); - } - } - - // HALTON_SEED: - // ------------ - { - pe = entries.find ( "HALTON_SEED" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: HALTON_SEED not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: HALTON_SEED" ); - pe->set_has_been_interpreted(); - set_HALTON_SEED (i); - } - } - - // POINT_DISPLAY_LIMIT: - // -------------------- - { - pe = entries.find ( "POINT_DISPLAY_LIMIT" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: POINT_DISPLAY_LIMIT not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: POINT_DISPLAY_LIMIT" ); - set_POINT_DISPLAY_LIMIT (i); - pe->set_has_been_interpreted(); - } - } - - // DIMENSION: - // ---------- - { - pe = entries.find ( "DIMENSION" ); - - if ( !pe ) { - if ( !pe && _dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DIMENSION not defined" ); - } - else { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DIMENSION not unique" ); - - int dim; - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), dim) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DIMENSION" ); - - pe->set_has_been_interpreted(); - - set_DIMENSION ( dim ); - } - } - - // SNAP_TO_BOUNDS: - // --------------- - { - pe = entries.find ( "SNAP_TO_BOUNDS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SNAP_TO_BOUNDS not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SNAP_TO_BOUNDS" ); - set_SNAP_TO_BOUNDS ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // MULTI-MADS: - // ----------- - { - // MULTI_OVERALL_BB_EVAL: - pe = entries.find ( "MULTI_OVERALL_BB_EVAL" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_OVERALL_BB_EVAL not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_OVERALL_BB_EVAL" ); - pe->set_has_been_interpreted(); - set_MULTI_OVERALL_BB_EVAL (i); - } - - // MULTI_NB_MADS_RUNS: - pe = entries.find ( "MULTI_NB_MADS_RUNS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_NB_MADS_RUNS not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_NB_MADS_RUNS" ); - pe->set_has_been_interpreted(); - set_MULTI_NB_MADS_RUNS (i); - } - - // MULTI_USE_DELTA_CRIT: - pe = entries.find ( "MULTI_USE_DELTA_CRIT" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_USE_DELTA_CRIT not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_USE_DELTA_CRIT" ); - pe->set_has_been_interpreted(); - set_MULTI_USE_DELTA_CRIT ( i == 1 ); - } - - // MULTI_F_BOUNDS (f1_min, f2_min, f2_min, f2_max): - pe = entries.find ( "MULTI_F_BOUNDS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_F_BOUNDS not unique" ); - if ( pe->get_nb_values() != 4 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_F_BOUNDS" ); - NOMAD::Point mfb ( 4 ); - it = pe->get_values().begin(); - for ( i = 0 ; i < 4 ; ++i ) { - if ( !d.atof ( *it ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_F_BOUNDS" ); - mfb[i] = d; - ++it; - } - pe->set_has_been_interpreted(); - set_MULTI_F_BOUNDS ( mfb ); - } - - // MULTI_FORMULATION: - // ------------------ - { - pe = entries.find ( "MULTI_FORMULATION" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_FORMULATION not unique" ); - NOMAD::multi_formulation_type mft; - if ( pe->get_nb_values() != 1 || - !NOMAD::string_to_multi_formulation_type - ( *(pe->get_values().begin()) , mft ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "Invalid parameter: MULTI_FORMULATION_TYPE" ); - pe->set_has_been_interpreted(); - set_MULTI_FORMULATION ( mft ); - } - } - } - - // Models - // -------------- - { - - - // Disable models when explicitely requested - pe = entries.find ( "DISABLE" ); - while ( pe ) - { - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DISABLE" ); - - std::string smt = *(pe->get_values().begin()); - NOMAD::toupper(smt); - if ( smt == "MODELS" ) - { - set_DISABLE_MODELS(); - } - else { - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "Invalid parameter: DISABLE MODELS. Only MODELS argument is accepted!" ); - - } - - - pe->set_has_been_interpreted(); - pe = pe->get_next(); - } - - - - // MODEL_SEARCH (can be entered one time or twice): - int i_model_search = 1; - bool b_model_search = false; - pe = entries.find ( "MODEL_SEARCH" ); - - while ( pe ) { - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH" ); - if ( i_model_search == 3 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH (cannot be entered more than twice" ); - - NOMAD::model_type mt; - std::string smt = *(pe->get_values().begin()); - int imt = NOMAD::string_to_bool ( smt ); - - // entered as a boolean: - if ( imt == 0 || imt == 1 ) { - if ( b_model_search || i_model_search == 2 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH (boolean argument can only be used once)" ); - b_model_search = true; - set_MODEL_SEARCH ( imt == 1 ); - } - - // entered as a model type: - else { - - if ( !NOMAD::string_to_model_type ( smt , mt ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_EVAL_SORT" ); - - set_MODEL_SEARCH ( i_model_search , mt ); - } - - pe->set_has_been_interpreted(); - pe = pe->get_next(); - ++i_model_search; - } - - // MODEL_SEARCH_OPTIMISTIC: - { - pe = entries.find ( "MODEL_SEARCH_OPTIMISTIC" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH_OPTIMISTIC not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH_OPTIMISTIC" ); - set_MODEL_SEARCH_OPTIMISTIC ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // MODEL_SEARCH_PROJ_TO_MESH: - { - pe = entries.find ( "MODEL_SEARCH_PROJ_TO_MESH" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH_PROJ_TO_MESH not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH_PROJ_TO_MESH" ); - set_MODEL_SEARCH_PROJ_TO_MESH ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // MODEL_QUAD_RADIUS_FACTOR: - { - pe = entries.find ( "MODEL_QUAD_RADIUS_FACTOR" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_RADIUS_FACTOR not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_RADIUS_FACTOR" ); - pe->set_has_been_interpreted(); - set_MODEL_QUAD_RADIUS_FACTOR ( d ); - } - } - - // MODEL_QUAD_USE_WP: - { - pe = entries.find ( "MODEL_QUAD_USE_WP" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_USE_WP not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_USE_WP" ); - set_MODEL_QUAD_USE_WP ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // MODEL_QUAD_MAX_Y_SIZE: - { - pe = entries.find ( "MODEL_QUAD_MAX_Y_SIZE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_MAX_Y_SIZE not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_MAX_Y_SIZE" ); - pe->set_has_been_interpreted(); - set_MODEL_QUAD_MAX_Y_SIZE (i); - } - } - - // MODEL_QUAD_MIN_Y_SIZE: - { - pe = entries.find ( "MODEL_QUAD_MIN_Y_SIZE" ); - if ( pe ) { - - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_MIN_Y_SIZE not unique" ); - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_MIN_Y_SIZE" ); - - s = *(pe->get_values().begin()); - NOMAD::toupper(s); - - if ( s == "N+1" ) - i = -1; - else if ( !NOMAD::atoi ( s , i ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_MIN_Y_SIZE" ); - - pe->set_has_been_interpreted(); - set_MODEL_QUAD_MIN_Y_SIZE (i); - } - } - - - // MODEL_QUAD_HYPERCUBE_LOWER_LIM: - { - pe = entries.find ( "MODEL_NP1_QUAD_EPSILON" ); - if ( pe ) { - - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_NP1_QUAD_EPSILON not unique" ); - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_NP1_QUAD_EPSILON" ); - - s = *(pe->get_values().begin()); - NOMAD::toupper(s); - NOMAD::Double d; - if ( !d.atof ( s) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_NP1_QUAD_EPSILON" ); - - pe->set_has_been_interpreted(); - set_MODEL_NP1_QUAD_EPSILON (d); - } - } - - // MODEL_TGP_MODE: - { - pe = entries.find ( "MODEL_TGP_MODE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_TGP_MODE not unique" ); - - NOMAD::TGP_mode_type m; - if ( pe->get_nb_values() != 1 || - !NOMAD::string_to_TGP_mode_type ( *(pe->get_values().begin()) , m ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "Invalid parameter: MODEL_TGP_MODE" ); - pe->set_has_been_interpreted(); - set_MODEL_TGP_MODE ( m ); - } - } - - // MODEL_TGP_REUSE_MODEL: - { - pe = entries.find ( "MODEL_TGP_REUSE_MODEL" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_TGP_REUSE_MODEL not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_TGP_REUSE_MODEL" ); - set_MODEL_TGP_REUSE_MODEL ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // MODEL_SEARCH_MAX_TRIAL_PTS: - { - pe = entries.find ( "MODEL_SEARCH_MAX_TRIAL_PTS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH_MAX_TRIAL_PTS not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH_MAX_TRIAL_PTS" ); - pe->set_has_been_interpreted(); - set_MODEL_SEARCH_MAX_TRIAL_PTS (i); - } - } - - // MODEL_EVAL_SORT: - { - pe = entries.find ( "MODEL_EVAL_SORT" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_EVAL_SORT not unique" ); - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_EVAL_SORT" ); - - NOMAD::model_type mt; - std::string smt = *(pe->get_values().begin()); - int imt = NOMAD::string_to_bool ( smt ); - - // entered as a boolean: - if ( imt == 0 || imt == 1 ) - set_MODEL_EVAL_SORT ( imt == 1 ); - - // entered as a model type: - else { - - if ( !NOMAD::string_to_model_type ( smt , mt ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_EVAL_SORT" ); - set_MODEL_EVAL_SORT ( mt ); - } - - pe->set_has_been_interpreted(); - } - } - - // MODEL_EVAL_SORT_CAUTIOUS: - { - pe = entries.find ( "MODEL_EVAL_SORT_CAUTIOUS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_EVAL_SORT_CAUTIOUS not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_EVAL_SORT_CAUTIOUS" ); - set_MODEL_EVAL_SORT_CAUTIOUS ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - } - - // SPECULATIVE_SEARCH: - // ------------------- - { - pe = entries.find ( "SPECULATIVE_SEARCH" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SPECULATIVE_SEARCH not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SPECULATIVE_SEARCH" ); - set_SPECULATIVE_SEARCH ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // VNS_SEARCH: - // ----------- - { - pe = entries.find ( "VNS_SEARCH" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VNS_SEARCH not unique" ); - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VNS_SEARCH" ); - - s = *(pe->get_values().begin()); - i = NOMAD::string_to_bool ( s ); - - // entered as a real: - if ( i == -1 || s == "1" ) { - if ( !d.atof ( s ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VNS_SEARCH" ); - set_VNS_SEARCH ( d ); - } - // entered as a boolean: - else - set_VNS_SEARCH ( i == 1 ); - - pe->set_has_been_interpreted(); - } - } - - // CACHE_SEARCH: - // ------------- - { - pe = entries.find ( "CACHE_SEARCH" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: CACHE_SEARCH not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: CACHE_SEARCH" ); - set_CACHE_SEARCH ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // LH_SEARCH: - // ---------- - { - pe = entries.find ( "LH_SEARCH" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: LH_SEARCH not unique" ); - if ( pe->get_nb_values() != 2 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: LH_SEARCH" ); - it = pe->get_values().begin(); - - if ( !NOMAD::atoi (*it++ , i) || i < 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: LH_SEARCH" ); - - if ( !NOMAD::atoi (*it , j) || j < 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: LH_SEARCH" ); - - set_LH_SEARCH ( i , j ); - pe->set_has_been_interpreted(); - } - - // OPPORTUNISTIC_LH: - // ----------------- - { - pe = entries.find ( "OPPORTUNISTIC_LH" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_LH not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_LH" ); - set_OPPORTUNISTIC_LH ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - } - - // OPPORTUNISTIC_CACHE_SEARCH: - // --------------------------- - { - pe = entries.find ( "OPPORTUNISTIC_CACHE_SEARCH" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_CACHE_SEARCH not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_CACHE_SEARCH" ); - set_OPPORTUNISTIC_CACHE_SEARCH ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // opportunistic strategy: - // ----------------------- - { - // OPPORTUNISTIC_EVAL: - pe = entries.find ( "OPPORTUNISTIC_EVAL" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_EVAL not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_EVAL" ); - set_OPPORTUNISTIC_EVAL ( i == 1 ); - pe->set_has_been_interpreted(); - } - - // OPPORTUNISTIC_MIN_NB_SUCCESS: - pe = entries.find ( "OPPORTUNISTIC_MIN_NB_SUCCESS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_MIN_NB_SUCCESS not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_MIN_NB_SUCCESS" ); - pe->set_has_been_interpreted(); - set_OPPORTUNISTIC_MIN_NB_SUCCESS (i); - } - - // OPPORTUNISTIC_MIN_EVAL: - pe = entries.find ( "OPPORTUNISTIC_MIN_EVAL" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_MIN_EVAL not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_MIN_EVAL" ); - pe->set_has_been_interpreted(); - set_OPPORTUNISTIC_MIN_EVAL (i); - } - - // OPPORTUNISTIC_MIN_F_IMPRVMT: - pe = entries.find ( "OPPORTUNISTIC_MIN_F_IMPRVMT" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_MIN_F_IMPRVMT not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_MIN_F_IMPRVMT" ); - pe->set_has_been_interpreted(); - set_OPPORTUNISTIC_MIN_F_IMPRVMT ( d ); - } - - // OPPORTUNISTIC_LUCKY_EVAL: - pe = entries.find ( "OPPORTUNISTIC_LUCKY_EVAL" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_LUCKY_EVAL not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPPORTUNISTIC_LUCKY_EVAL" ); - set_OPPORTUNISTIC_LUCKY_EVAL ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // Directions (DIRECTION_TYPE and SEC_POLL_DIR_TYPE): - // -------------------------------------------------- - { - NOMAD::direction_type dt; - - - pe = entries.find ( "DIRECTION_TYPE" ); - while ( pe ) { - - if ( !NOMAD::strings_to_direction_type ( pe->get_values() , dt ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DIRECTION_TYPE" ); - set_DIRECTION_TYPE ( dt ); - - - pe->set_has_been_interpreted(); - pe = pe->get_next(); - } - - pe = entries.find ( "SEC_POLL_DIR_TYPE" ); - while ( pe ) { - if ( !NOMAD::strings_to_direction_type ( pe->get_values() , dt ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SEC_POLL_DIR_TYPE" ); - set_SEC_POLL_DIR_TYPE ( dt ); - - pe->set_has_been_interpreted(); - pe = pe->get_next(); - } - } - - - // MAX_ITERATIONS: - // --------------- - { - pe = entries.find ( "MAX_ITERATIONS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_ITERATIONS not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_ITERATIONS" ); - pe->set_has_been_interpreted(); - set_MAX_ITERATIONS (i); - } - } - - // MAX_CONSECUTIVE_FAILED_ITERATIONS: - // ---------------------------------- - { - pe = entries.find ( "MAX_CONSECUTIVE_FAILED_ITERATIONS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_CONSECUTIVE_FAILED_ITERATIONS not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_CONSECUTIVE_FAILED_ITERATIONS" ); - pe->set_has_been_interpreted(); - set_MAX_CONSECUTIVE_FAILED_ITERATIONS (static_cast<int>(d.value())); - } - } - - // MAX_CACHE_MEMORY: - // ----------------- - { - pe = entries.find ( "MAX_CACHE_MEMORY" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_CACHE_MEMORY not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_CACHE_MEMORY" ); - pe->set_has_been_interpreted(); - set_MAX_CACHE_MEMORY (static_cast<float>(d.value())); - } - } - - // MAX_EVAL: - // --------- - { - pe = entries.find ( "MAX_EVAL" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_EVAL not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_EVAL" ); - pe->set_has_been_interpreted(); - set_MAX_EVAL (i); - } - } - - // MAX_BB_EVAL: - // ------------ - { - pe = entries.find ( "MAX_BB_EVAL" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_BB_EVAL not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_BB_EVAL" ); - pe->set_has_been_interpreted(); - set_MAX_BB_EVAL (i); - } - } - - // MAX_SIM_BB_EVAL: - // ---------------- - { - pe = entries.find ( "MAX_SIM_BB_EVAL" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_SIM_BB_EVAL not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_SIM_BB_EVAL" ); - pe->set_has_been_interpreted(); - set_MAX_SIM_BB_EVAL (i); - } - } - - // MAX_SGTE_EVAL: - // -------------- - { - pe = entries.find ( "MAX_SGTE_EVAL" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_SGTE_EVAL not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_SGTE_EVAL" ); - pe->set_has_been_interpreted(); - set_MAX_SGTE_EVAL (i); - } - } - - // MAX_TIME: - // --------- - { - pe = entries.find ( "MAX_TIME" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_TIME not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MAX_TIME" ); - - pe->set_has_been_interpreted(); - set_MAX_TIME (i); - } - } - - // STAT_SUM_TARGET: - // ---------------- - { - pe = entries.find ( "STAT_SUM_TARGET" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: STAT_SUM_TARGET not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: STAT_SUM_TARGET" ); - pe->set_has_been_interpreted(); - set_STAT_SUM_TARGET ( d ); - } - } - - // L_CURVE_TARGET: - // --------------- - { - pe = entries.find ( "L_CURVE_TARGET" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: L_CURVE_TARGET not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: L_CURVE_TARGET" ); - pe->set_has_been_interpreted(); - set_L_CURVE_TARGET ( d ); - } - } - - // EXTENDED_POLL_TRIGGER: - // ---------------------- - { - pe = entries.find ( "EXTENDED_POLL_TRIGGER" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: EXTENDED_POLL_TRIGGER not unique" ); - - bool rel; - - if ( pe->get_nb_values() != 1 || - !d.relative_atof ( *(pe->get_values().begin()) , rel ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: EXTENDED_POLL_TRIGGER" ); - - pe->set_has_been_interpreted(); - set_EXTENDED_POLL_TRIGGER ( d , rel ); - } - } - - // EXTENDED_POLL_ENABLED: - // ---------------------- - { - pe = entries.find ( "EXTENDED_POLL_ENABLED" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: EXTENDED_POLL_ENABLED not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: EXTENDED_POLL_ENABLED" ); - set_EXTENDED_POLL_ENABLED ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // USER_CALLS_ENABLED: - // ------------------- - { - pe = entries.find ( "USER_CALLS_ENABLED" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: USER_CALLS_ENABLED not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: USER_CALLS_ENABLED" ); - set_USER_CALLS_ENABLED ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // ASYNCHRONOUS: - // ------------- - { - pe = entries.find ( "ASYNCHRONOUS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: ASYNCHRONOUS not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: ASYNCHRONOUS" ); - set_ASYNCHRONOUS ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // RHO: - // ---- - { - pe = entries.find ( "RHO" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: RHO not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: RHO" ); - pe->set_has_been_interpreted(); - set_RHO(d); - } - } - - // H_MIN: - // ------ - { - pe = entries.find ( "H_MIN" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: H_MIN not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: H_MIN" ); - pe->set_has_been_interpreted(); - set_H_MIN(d); - } - } - - // H_MAX_0: - // -------- - { - pe = entries.find ( "H_MAX_0" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: H_MAX_0 not unique" ); - if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "Invalid parameter: H_MAX_0" ); - pe->set_has_been_interpreted(); - set_H_MAX_0(d); - } - } - - // H_NORM: - // ------- - { - pe = entries.find ( "H_NORM" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: H_NORM not unique" ); - NOMAD::hnorm_type hn = NOMAD::L2; - if ( pe->get_nb_values() != 1 || - !NOMAD::string_to_hnorm_type ( *(pe->get_values().begin()) , hn ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "Invalid parameter: H_NORM" ); - pe->set_has_been_interpreted(); - set_H_NORM ( hn ); - } - } - - // TMP_DIR: - // -------- - { - _tmp_dir.clear(); - pe = entries.find ( "TMP_DIR" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: TMP_DIR not unique" ); - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: TMP_DIR" ); - - set_TMP_DIR ( *(pe->get_values().begin()) ); - - pe->set_has_been_interpreted(); - } - } - - // ADD_SEED_TO_FILE_NAMES: - // ----------------------- - { - pe = entries.find ( "ADD_SEED_TO_FILE_NAMES" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: ADD_SEED_TO_FILE_NAMES not unique" ); - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: ADD_SEED_TO_FILE_NAMES" ); - - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: ADD_SEED_TO_FILE_NAMES" ); - set_ADD_SEED_TO_FILE_NAMES ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // SOLUTION_FILE: - // -------------- - { - _solution_file.clear(); - pe = entries.find ( "SOLUTION_FILE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SOLUTION_FILE not unique" ); - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SOLUTION_FILE" ); - set_SOLUTION_FILE ( *(pe->get_values().begin()) ); - pe->set_has_been_interpreted(); - } - } - - // HISTORY_FILE: - // ------------- - { - _history_file.clear(); - pe = entries.find ( "HISTORY_FILE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: HISTORY_FILE not unique" ); - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: HISTORY_FILE" ); - set_HISTORY_FILE ( *(pe->get_values().begin()) ); - pe->set_has_been_interpreted(); - } - } - - // STATS_FILE: - // ----------- - { - pe = entries.find ( "STATS_FILE" ); - if ( pe ) { - - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: STATS_FILE not unique" ); - - end = pe->get_values().end(); - it = pe->get_values().begin(); - std::string file_name = *it; - ++it; - - std::list<std::string> ls; - if (it!=end) - { - while ( it != end ) { - ls.push_back(*it); - ++it; - } - ls.resize(ls.size()-1); - } - - set_STATS_FILE ( file_name , ls ); - pe->set_has_been_interpreted(); - } - } - - // CACHE FILE: - // ----------- - { - _cache_file.clear(); - pe = entries.find ( "CACHE_FILE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: CACHE_FILE not unique" ); - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: CACHE_FILE" ); - set_CACHE_FILE ( *(pe->get_values().begin()) ); - pe->set_has_been_interpreted(); - } - } - - // SGTE_CACHE FILE: - // ---------------- - { - _sgte_cache_file.clear(); - pe = entries.find ( "SGTE_CACHE_FILE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_CACHE_FILE not unique" ); - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_CACHE_FILE" ); - set_SGTE_CACHE_FILE ( *(pe->get_values().begin()) ); - pe->set_has_been_interpreted(); - } - } - - - // CACHE_SAVE_PERIOD: - // ------------------ - { - pe = entries.find ( "CACHE_SAVE_PERIOD" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: CACHE_SAVE_PERIOD not unique" ); - if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: CACHE_SAVE_PERIOD" ); - set_CACHE_SAVE_PERIOD (i); - pe->set_has_been_interpreted(); - } - } - - // SGTE_COST: - // ---------- - { - pe = entries.find ( "SGTE_COST" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_COST not unique" ); - if ( pe->get_nb_values() != 1 || - !NOMAD::atoi (*(pe->get_values().begin()) , i) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_COST" ); - set_SGTE_COST (i); - pe->set_has_been_interpreted(); - } - } - - // X0: - // --- - interpret_x0 ( entries ); - - // FIXED_VARIABLE: - // --------------- - interpret_BFVS ( entries , "FIXED_VARIABLE"); - - // LOWER_BOUND: - // ------------ - interpret_BFVS ( entries , "LOWER_BOUND"); - - // UPPER_BOUND: - // ------------ - interpret_BFVS ( entries , "UPPER_BOUND"); - - // SCALING: - // -------- - interpret_BFVS ( entries , "SCALING" ); - - // BB_INPUT_TYPE: - // -------------- - interpret_bb_input_type ( entries ); - - // F_TARGET: - // --------- - interpret_f_target ( entries ); - - // STOP_IF_FEASIBLE: - // ----------------- - pe = entries.find ( "STOP_IF_FEASIBLE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: STOP_IF_FEASIBLE not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: STOP_IF_FEASIBLE" ); - pe->set_has_been_interpreted(); - set_STOP_IF_FEASIBLE ( i == 1 ); - } - - // BB_INPUT_INCLUDE_TAG: - // --------------------- - { - pe = entries.find ( "BB_INPUT_INCLUDE_TAG" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_INCLUDE_TAG not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_INCLUDE_TAG" ); - set_BB_INPUT_INCLUDE_TAG ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // BB_INPUT_INCLUDE_SEED: - // ---------------------- - { - pe = entries.find ( "BB_INPUT_INCLUDE_SEED" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_INCLUDE_SEED not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_INCLUDE_SEED" ); - set_BB_INPUT_INCLUDE_SEED ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - // BB_REDIRECTION: - // --------------- - { - pe = entries.find ( "BB_REDIRECTION" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_REDIRECTION not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_REDIRECTION" ); - set_BB_REDIRECTION ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // INITIAL_MESH_SIZE, MIN_MESH_SIZE, and MIN_POLL_SIZE: - // ---------------------------------------------------- - interpret_mesh_sizes ( entries , "INITIAL_MESH_SIZE" ); - interpret_mesh_sizes ( entries , "MIN_MESH_SIZE" ); - interpret_mesh_sizes ( entries , "MIN_POLL_SIZE" ); - - // BB_OUTPUT_TYPE: - // --------------- - { - pe = entries.find ( "BB_OUTPUT_TYPE" ); - - if ( !pe ) { - if ( _bb_output_type.empty() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_OUTPUT_TYPE not defined" ); - } - else { - - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_OUTPUT_TYPE not unique" ); - - m = pe->get_nb_values(); - - if ( m <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_OUTPUT_TYPE" ); - - NOMAD::bb_output_type cur; - std::list<NOMAD::bb_output_type> bbot; - i = 0; - end = pe->get_values().end(); - for ( it = pe->get_values().begin() ; it != end ; ++it ) { - if ( !NOMAD::string_to_bb_output_type ( *it , cur ) ) { - err = "invalid parameter: BB_OUTPUT_TYPE (" + pe->get_name(); - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - bbot.push_back (cur); - } - - set_BB_OUTPUT_TYPE ( bbot ); - - pe->set_has_been_interpreted(); - } - } - - // NEIGHBORS_EXE: - // -------------- - { - _neighbors_exe.clear(); - pe = entries.find ( "NEIGHBORS_EXE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: NEIGHBORS_EXE not unique" ); - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: NEIGHBORS_EXE" ); - set_NEIGHBORS_EXE ( *(pe->get_values().begin()) ); - pe->set_has_been_interpreted(); - } - } - - // BB_EXE: - // ------- - { - pe = entries.find ( "BB_EXE" ); - if ( pe ) { - - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_EXE not unique" ); - - m = pe->get_nb_values(); - - if ( m == 1 ) - set_BB_EXE ( *pe->get_values().begin() ); - - else { - - if ( m != static_cast<int>(_bb_output_type.size()) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: number of BB_EXE (>1) and corresponding BB_OUTPUT_TYPE must be the same." ); - - std::list<std::string> bbexe; - end = pe->get_values().end(); - for ( it = pe->get_values().begin() ; it != end ; ++it ) - bbexe.push_back (*it); - - set_BB_EXE ( bbexe ); - } - - pe->set_has_been_interpreted(); - } - } - - // SGTE_EXE: - // --------- - { - pe = entries.find ( "SGTE_EXE" ); - if ( pe ) { - - std::string bb_exe_name , sgte_name; - - if ( pe->get_nb_values() == 1 ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_EXE (with one arguement) not unique" ); - sgte_name = *pe->get_values().begin(); - } - - else if ( pe->get_nb_values() == 2 ) { - bb_exe_name = *pe->get_values().begin(); - sgte_name = *(++pe->get_values().begin()); - } - - else - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_EXE" ); - - set_SGTE_EXE ( bb_exe_name , sgte_name ); - pe->set_has_been_interpreted(); - } - } - - // SGTE_EVAL_SORT: - // --------------- - { - pe = entries.find ( "SGTE_EVAL_SORT" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_EVAL_SORT not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_EVAL_SORT" ); - set_SGTE_EVAL_SORT ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // HAS_SGTE: - // --------- - { - pe = entries.find ( "HAS_SGTE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: HAS_SGTE not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: HAS_SGTE" ); - set_HAS_SGTE ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // OPT_ONLY_SGTE: - // -------------- - { - pe = entries.find ( "OPT_ONLY_SGTE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPT_ONLY_SGTE not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPT_ONLY_SGTE" ); - set_OPT_ONLY_SGTE ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // DISPLAY_DEGREE: - // --------------- - { - pe = entries.find ( "DISPLAY_DEGREE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DISPLAY_DEGREE not unique" ); - if ( pe->get_nb_values() != 1 || - !set_DISPLAY_DEGREE ( *(pe->get_values().begin()) ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DISPLAY_DEGREE" ); - pe->set_has_been_interpreted(); - } - } - - // OPEN_BRACE: - // ----------- - { - pe = entries.find ( "OPEN_BRACE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPEN_BRACE not unique" ); - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPEN_BRACE" ); - - set_OPEN_BRACE ( *(pe->get_values().begin()) ); - - pe->set_has_been_interpreted(); - } - } - - // CLOSED_BRACE: - // ------------- - { - pe = entries.find ( "CLOSED_BRACE" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: CLOSED_BRACE not unique" ); - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: CLOSED_BRACE" ); - - set_CLOSED_BRACE ( *(pe->get_values().begin()) ); - - pe->set_has_been_interpreted(); - } - } - - // DISPLAY_STATS: - { - pe = entries.find ( "DISPLAY_STATS" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DISPLAY_STATS not unique" ); - std::list<std::string> ls; - end = pe->get_values().end(); - for ( it = pe->get_values().begin() ; it != end ; ++it ) - ls.push_back ( *it ); - ls.resize ( ls.size()-1 ); - set_DISPLAY_STATS ( ls ); - pe->set_has_been_interpreted(); - } - } - - // DISPLAY_ALL_EVAL: - // ----------------- - { - pe = entries.find ( "DISPLAY_ALL_EVAL" ); - if ( pe ) { - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DISPLAY_ALL_EVAL not unique" ); - i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); - if ( pe->get_nb_values() != 1 || i == -1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DISPLAY_ALL_EVAL" ); - set_DISPLAY_ALL_EVAL ( i == 1 ); - pe->set_has_been_interpreted(); - } - } - - // SEED: - // ----- - { - pe = entries.find ( "SEED" ); - - if ( pe ) { - - if ( !pe->is_unique() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SEED not unique" ); - - if ( pe->get_nb_values() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SEED" ); - - s = *(pe->get_values().begin()); - NOMAD::toupper(s); - - if ( s == "NONE" || s == "DIFF" ) - i = -1; - else if ( !NOMAD::atoi ( s , i ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SEED" ); - set_SEED(i); - pe->set_has_been_interpreted(); - } - } - - // VARIABLE_GROUP: - // --------------- - interpret_var_groups ( entries ); - - // PERIODIC_VARIABLE: - // ------------------ - interpret_periodic_var ( entries ); - - /*----------------------------------------------*/ - - // check the non-interpreted parameters: - pe = entries.find_non_interpreted(); - if ( pe ) { - err = "invalid parameter: " + pe->get_name() + " - unknown"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - // user must check the parameters with Parameters::check() + + // interpret and set the entries using SET methods: + std::list<std::string>::const_iterator it , end; + int i , j , m; + NOMAD::Double d; + NOMAD::Parameter_Entry * pe; + std::string s; + std::string err ; + + /*----------------------------------------------*/ + + // EPSILON: + // -------- + { + pe = entries.find ( "EPSILON" ); + if ( pe ) + { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: EPSILON not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: EPSILON" ); + set_EPSILON (d); + pe->set_has_been_interpreted(); + } + } + + // UNDEF_STR: + // ---------- + pe = entries.find ( "UNDEF_STR" ); + if ( pe ) + { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: UNDEF_STR not unique" ); + set_UNDEF_STR ( *(pe->get_values().begin()) ); + pe->set_has_been_interpreted(); + } + + // INF_STR: + // -------- + pe = entries.find ( "INF_STR" ); + if ( pe ) + { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INF_STR not unique" ); + set_INF_STR ( *(pe->get_values().begin()) ); + pe->set_has_been_interpreted(); + } + + // ANISOTROPIC_MESH + //------------------- + { + pe = entries.find ( "ANISOTROPIC_MESH" ); + if ( pe ) + { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: ANISOTROPIC_MESH not unique" ); + + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: ANISOTROPIC_MESH" ); + set_ANISOTROPIC_MESH ( i == 1 ); + pe->set_has_been_interpreted(); + + } + } + + // POLL_UPDATE_BASIS: + // ------------------ + { + pe = entries.find ( "POLL_UPDATE_BASIS" ); + if ( pe ) + { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: POLL_UPDATE_BASIS not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: POLL_UPDATE_BASIS" ); + set_POLL_UPDATE_BASIS (d); + pe->set_has_been_interpreted(); + } + } + + + + // MESH_UPDATE_BASIS: + // ------------------ + { + pe = entries.find ( "MESH_UPDATE_BASIS" ); + if ( pe ) + { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MESH_UPDATE_BASIS not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MESH_UPDATE_BASIS" ); + set_MESH_UPDATE_BASIS (d); + pe->set_has_been_interpreted(); + } + } + + // INITIAL_MESH_INDEX: + // ------------------- + { + pe = entries.find ( "INITIAL_MESH_INDEX" ); + if ( pe ) + { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_MESH_INDEX not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_MESH_INDEX" ); + pe->set_has_been_interpreted(); + set_INITIAL_MESH_INDEX (i); + } + } + + // MESH_REFINING_EXPONENT: + // ----------------------- + { + pe = entries.find ( "MESH_REFINING_EXPONENT" ); + if ( pe ) + { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MESH_REFINING_EXPONENT not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MESH_REFINING_EXPONENT" ); + pe->set_has_been_interpreted(); + set_MESH_REFINING_EXPONENT (i); + } + } + + // MESH_COARSENING_EXPONENT: + // ------------------------- + { + pe = entries.find ( "MESH_COARSENING_EXPONENT" ); + if ( pe ) + { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MESH_COARSENING_EXPONENT not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MESH_COARSENING_EXPONENT" ); + pe->set_has_been_interpreted(); + set_MESH_COARSENING_EXPONENT (i); + } + } + + // USE_SMESH: + // --------------- + { + pe = entries.find ( "USE_SMESH" ); + if ( pe ) + { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: USE_SMESH not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: USE_SMESH" ); + set_USE_SMESH ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + + // POINT_DISPLAY_LIMIT: + // -------------------- + { + pe = entries.find ( "POINT_DISPLAY_LIMIT" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: POINT_DISPLAY_LIMIT not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: POINT_DISPLAY_LIMIT" ); + set_POINT_DISPLAY_LIMIT (i); + pe->set_has_been_interpreted(); + } + } + + // DIMENSION: + // ---------- + { + pe = entries.find ( "DIMENSION" ); + + if ( !pe ) { + if ( !pe && _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DIMENSION not defined" ); + } + else { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DIMENSION not unique" ); + + int dim; + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), dim) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DIMENSION" ); + + pe->set_has_been_interpreted(); + + set_DIMENSION ( dim ); + } + } + + // SNAP_TO_BOUNDS: + // --------------- + { + pe = entries.find ( "SNAP_TO_BOUNDS" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SNAP_TO_BOUNDS not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SNAP_TO_BOUNDS" ); + set_SNAP_TO_BOUNDS ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // MULTI-MADS: + // ----------- + { + // MULTI_OVERALL_BB_EVAL: + pe = entries.find ( "MULTI_OVERALL_BB_EVAL" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_OVERALL_BB_EVAL not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_OVERALL_BB_EVAL" ); + pe->set_has_been_interpreted(); + set_MULTI_OVERALL_BB_EVAL (i); + } + + // MULTI_NB_MADS_RUNS: + pe = entries.find ( "MULTI_NB_MADS_RUNS" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_NB_MADS_RUNS not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_NB_MADS_RUNS" ); + pe->set_has_been_interpreted(); + set_MULTI_NB_MADS_RUNS (i); + } + + // MULTI_USE_DELTA_CRIT: + pe = entries.find ( "MULTI_USE_DELTA_CRIT" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_USE_DELTA_CRIT not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_USE_DELTA_CRIT" ); + pe->set_has_been_interpreted(); + set_MULTI_USE_DELTA_CRIT ( i == 1 ); + } + + // MULTI_F_BOUNDS (f1_min, f2_min, f2_min, f2_max): + pe = entries.find ( "MULTI_F_BOUNDS" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_F_BOUNDS not unique" ); + if ( pe->get_nb_values() != 4 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_F_BOUNDS" ); + NOMAD::Point mfb ( 4 ); + it = pe->get_values().begin(); + for ( i = 0 ; i < 4 ; ++i ) { + if ( !d.atof ( *it ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_F_BOUNDS" ); + mfb[i] = d; + ++it; + } + pe->set_has_been_interpreted(); + set_MULTI_F_BOUNDS ( mfb ); + } + + // MULTI_FORMULATION: + // ------------------ + { + pe = entries.find ( "MULTI_FORMULATION" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_FORMULATION not unique" ); + NOMAD::multi_formulation_type mft; + if ( pe->get_nb_values() != 1 || + !NOMAD::string_to_multi_formulation_type + ( *(pe->get_values().begin()) , mft ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Invalid parameter: MULTI_FORMULATION_TYPE" ); + pe->set_has_been_interpreted(); + set_MULTI_FORMULATION ( mft ); + } + } + } + + // Models + // -------------- + { + + + // Disable models when explicitely requested + pe = entries.find ( "DISABLE" ); + while ( pe ) + { + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DISABLE" ); + + std::string smt = *(pe->get_values().begin()); + NOMAD::toupper(smt); + if ( smt == "MODELS" ) + set_DISABLE_MODELS(); + else if ( smt == "EVAL_SORT" ) + set_DISABLE_EVAL_SORT(); + else + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Invalid parameter: DISABLE MODELS. Only MODELS argument is accepted!" ); + + + pe->set_has_been_interpreted(); + pe = pe->get_next(); + } + + + + // MODEL_SEARCH (can be entered one time or twice): + int i_model_search = 1; + bool b_model_search = false; + pe = entries.find ( "MODEL_SEARCH" ); + + while ( pe ) { + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH" ); + if ( i_model_search == 3 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH (cannot be entered more than twice" ); + + NOMAD::model_type mt; + std::string smt = *(pe->get_values().begin()); + int imt = NOMAD::string_to_bool ( smt ); + + // entered as a boolean: + if ( imt == 0 || imt == 1 ) { + if ( b_model_search || i_model_search == 2 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH (boolean argument can only be used once)" ); + b_model_search = true; + set_MODEL_SEARCH ( imt == 1 ); + } + + // entered as a model type: + else { + + if ( !NOMAD::string_to_model_type ( smt , mt ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH" ); + + set_MODEL_SEARCH ( i_model_search , mt ); + } + + pe->set_has_been_interpreted(); + pe = pe->get_next(); + ++i_model_search; + } + + // MODEL_SEARCH_OPTIMISTIC: + { + pe = entries.find ( "MODEL_SEARCH_OPTIMISTIC" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH_OPTIMISTIC not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH_OPTIMISTIC" ); + set_MODEL_SEARCH_OPTIMISTIC ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // MODEL_SEARCH_PROJ_TO_MESH: + { + pe = entries.find ( "MODEL_SEARCH_PROJ_TO_MESH" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH_PROJ_TO_MESH not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH_PROJ_TO_MESH" ); + set_MODEL_SEARCH_PROJ_TO_MESH ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // MODEL_QUAD_RADIUS_FACTOR: + { + pe = entries.find ( "MODEL_QUAD_RADIUS_FACTOR" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_RADIUS_FACTOR not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_RADIUS_FACTOR" ); + pe->set_has_been_interpreted(); + set_MODEL_QUAD_RADIUS_FACTOR ( d ); + } + } + + // MODEL_QUAD_USE_WP: + { + pe = entries.find ( "MODEL_QUAD_USE_WP" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_USE_WP not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_USE_WP" ); + set_MODEL_QUAD_USE_WP ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // MODEL_QUAD_MAX_Y_SIZE: + { + pe = entries.find ( "MODEL_QUAD_MAX_Y_SIZE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_MAX_Y_SIZE not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_MAX_Y_SIZE" ); + pe->set_has_been_interpreted(); + set_MODEL_QUAD_MAX_Y_SIZE (i); + } + } + + // MODEL_QUAD_MIN_Y_SIZE: + { + pe = entries.find ( "MODEL_QUAD_MIN_Y_SIZE" ); + if ( pe ) { + + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_MIN_Y_SIZE not unique" ); + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_MIN_Y_SIZE" ); + + s = *(pe->get_values().begin()); + NOMAD::toupper(s); + + if ( s == "N+1" ) + i = -1; + else if ( !NOMAD::atoi ( s , i ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_MIN_Y_SIZE" ); + + pe->set_has_been_interpreted(); + set_MODEL_QUAD_MIN_Y_SIZE (i); + } + } + + + // MODEL_QUAD_HYPERCUBE_LOWER_LIM: + { + pe = entries.find ( "MODEL_NP1_QUAD_EPSILON" ); + if ( pe ) { + + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_NP1_QUAD_EPSILON not unique" ); + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_NP1_QUAD_EPSILON" ); + + s = *(pe->get_values().begin()); + NOMAD::toupper(s); + NOMAD::Double d; + if ( !d.atof ( s) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_NP1_QUAD_EPSILON" ); + + pe->set_has_been_interpreted(); + set_MODEL_NP1_QUAD_EPSILON (d); + } + } + + // MODEL_TGP_MODE: + { + pe = entries.find ( "MODEL_TGP_MODE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_TGP_MODE not unique" ); + + NOMAD::TGP_mode_type m; + if ( pe->get_nb_values() != 1 || + !NOMAD::string_to_TGP_mode_type ( *(pe->get_values().begin()) , m ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Invalid parameter: MODEL_TGP_MODE" ); + pe->set_has_been_interpreted(); + set_MODEL_TGP_MODE ( m ); + } + } + + // MODEL_TGP_REUSE_MODEL: + { + pe = entries.find ( "MODEL_TGP_REUSE_MODEL" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_TGP_REUSE_MODEL not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_TGP_REUSE_MODEL" ); + set_MODEL_TGP_REUSE_MODEL ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // MODEL_SEARCH_MAX_TRIAL_PTS: + { + pe = entries.find ( "MODEL_SEARCH_MAX_TRIAL_PTS" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH_MAX_TRIAL_PTS not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH_MAX_TRIAL_PTS" ); + pe->set_has_been_interpreted(); + set_MODEL_SEARCH_MAX_TRIAL_PTS (i); + } + } + + // MODEL_EVAL_SORT: + { + pe = entries.find ( "MODEL_EVAL_SORT" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_EVAL_SORT not unique" ); + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_EVAL_SORT" ); + + NOMAD::model_type mt; + std::string smt = *(pe->get_values().begin()); + int imt = NOMAD::string_to_bool ( smt ); + + // entered as a boolean: + if ( imt == 0 || imt == 1 ) + set_MODEL_EVAL_SORT ( imt == 1 ); + + // entered as a model type: + else { + + if ( !NOMAD::string_to_model_type ( smt , mt ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_EVAL_SORT" ); + set_MODEL_EVAL_SORT ( mt ); + } + + pe->set_has_been_interpreted(); + } + } + + // MODEL_EVAL_SORT_CAUTIOUS: + { + pe = entries.find ( "MODEL_EVAL_SORT_CAUTIOUS" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_EVAL_SORT_CAUTIOUS not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_EVAL_SORT_CAUTIOUS" ); + set_MODEL_EVAL_SORT_CAUTIOUS ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + } + + // SPECULATIVE_SEARCH: + // ------------------- + { + pe = entries.find ( "SPECULATIVE_SEARCH" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SPECULATIVE_SEARCH not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SPECULATIVE_SEARCH" ); + set_SPECULATIVE_SEARCH ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // VNS_SEARCH: + // ----------- + { + pe = entries.find ( "VNS_SEARCH" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VNS_SEARCH not unique" ); + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VNS_SEARCH" ); + + s = *(pe->get_values().begin()); + i = NOMAD::string_to_bool ( s ); + + // entered as a real: + if ( i == -1 || s == "1" ) { + if ( !d.atof ( s ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VNS_SEARCH" ); + set_VNS_SEARCH ( d ); + } + // entered as a boolean: + else + set_VNS_SEARCH ( i == 1 ); + + pe->set_has_been_interpreted(); + } + } + + // CACHE_SEARCH: + // ------------- + { + pe = entries.find ( "CACHE_SEARCH" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: CACHE_SEARCH not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: CACHE_SEARCH" ); + set_CACHE_SEARCH ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // LH_SEARCH: + // ---------- + { + pe = entries.find ( "LH_SEARCH" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: LH_SEARCH not unique" ); + if ( pe->get_nb_values() != 2 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: LH_SEARCH" ); + it = pe->get_values().begin(); + + if ( !NOMAD::atoi (*it++ , i) || i < 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: LH_SEARCH" ); + + if ( !NOMAD::atoi (*it , j) || j < 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: LH_SEARCH" ); + + set_LH_SEARCH ( i , j ); + pe->set_has_been_interpreted(); + } + + // OPPORTUNISTIC_LH: + // ----------------- + { + pe = entries.find ( "OPPORTUNISTIC_LH" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_LH not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_LH" ); + set_OPPORTUNISTIC_LH ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + } + + // OPPORTUNISTIC_CACHE_SEARCH: + // --------------------------- + { + pe = entries.find ( "OPPORTUNISTIC_CACHE_SEARCH" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_CACHE_SEARCH not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_CACHE_SEARCH" ); + set_OPPORTUNISTIC_CACHE_SEARCH ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // opportunistic strategy: + // ----------------------- + { + + // BB_MAX_BLOCK_SIZE + pe = entries.find ( "BB_MAX_BLOCK_SIZE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_MAX_BLOCK_SIZE not unique" ); + + it = pe->get_values().begin(); + + if ( !NOMAD::atoi (*it++ , i) || i <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_MAX_BLOCK_SIZE" ); + set_BB_MAX_BLOCK_SIZE (i); + + pe->set_has_been_interpreted(); + } + + + // OPPORTUNISTIC_EVAL: + pe = entries.find ( "OPPORTUNISTIC_EVAL" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_EVAL not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_EVAL" ); + set_OPPORTUNISTIC_EVAL ( i == 1 ); + pe->set_has_been_interpreted(); + } + + // OPPORTUNISTIC_MIN_NB_SUCCESS: + pe = entries.find ( "OPPORTUNISTIC_MIN_NB_SUCCESS" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_MIN_NB_SUCCESS not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_MIN_NB_SUCCESS" ); + pe->set_has_been_interpreted(); + set_OPPORTUNISTIC_MIN_NB_SUCCESS (i); + } + + // OPPORTUNISTIC_MIN_EVAL: + pe = entries.find ( "OPPORTUNISTIC_MIN_EVAL" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_MIN_EVAL not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_MIN_EVAL" ); + pe->set_has_been_interpreted(); + set_OPPORTUNISTIC_MIN_EVAL (i); + } + + // OPPORTUNISTIC_MIN_F_IMPRVMT: + pe = entries.find ( "OPPORTUNISTIC_MIN_F_IMPRVMT" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_MIN_F_IMPRVMT not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_MIN_F_IMPRVMT" ); + pe->set_has_been_interpreted(); + set_OPPORTUNISTIC_MIN_F_IMPRVMT ( d ); + } + + // OPPORTUNISTIC_LUCKY_EVAL: + pe = entries.find ( "OPPORTUNISTIC_LUCKY_EVAL" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_LUCKY_EVAL not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPPORTUNISTIC_LUCKY_EVAL" ); + set_OPPORTUNISTIC_LUCKY_EVAL ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // Directions (DIRECTION_TYPE and SEC_POLL_DIR_TYPE): + // -------------------------------------------------- + { + NOMAD::direction_type dt; + + + pe = entries.find ( "DIRECTION_TYPE" ); + while ( pe ) { + + if ( !NOMAD::strings_to_direction_type ( pe->get_values() , dt ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DIRECTION_TYPE" ); + set_DIRECTION_TYPE ( dt ); + + + pe->set_has_been_interpreted(); + pe = pe->get_next(); + } + + pe = entries.find ( "SEC_POLL_DIR_TYPE" ); + while ( pe ) { + if ( !NOMAD::strings_to_direction_type ( pe->get_values() , dt ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SEC_POLL_DIR_TYPE" ); + set_SEC_POLL_DIR_TYPE ( dt ); + + pe->set_has_been_interpreted(); + pe = pe->get_next(); + } + } + + + // MAX_ITERATIONS: + // --------------- + { + pe = entries.find ( "MAX_ITERATIONS" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_ITERATIONS not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_ITERATIONS" ); + pe->set_has_been_interpreted(); + set_MAX_ITERATIONS (i); + } + } + + // MAX_CONSECUTIVE_FAILED_ITERATIONS: + // ---------------------------------- + { + pe = entries.find ( "MAX_CONSECUTIVE_FAILED_ITERATIONS" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_CONSECUTIVE_FAILED_ITERATIONS not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_CONSECUTIVE_FAILED_ITERATIONS" ); + pe->set_has_been_interpreted(); + set_MAX_CONSECUTIVE_FAILED_ITERATIONS (static_cast<int>(d.value())); + } + } + + // MAX_CACHE_MEMORY: + // ----------------- + { + pe = entries.find ( "MAX_CACHE_MEMORY" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_CACHE_MEMORY not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_CACHE_MEMORY" ); + pe->set_has_been_interpreted(); + set_MAX_CACHE_MEMORY (static_cast<float>(d.value())); + } + } + + // MAX_EVAL: + // --------- + { + pe = entries.find ( "MAX_EVAL" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_EVAL not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_EVAL" ); + pe->set_has_been_interpreted(); + set_MAX_EVAL (i); + } + } + + // MAX_BB_EVAL: + // ------------ + { + pe = entries.find ( "MAX_BB_EVAL" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_BB_EVAL not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_BB_EVAL" ); + pe->set_has_been_interpreted(); + set_MAX_BB_EVAL (i); + } + } + + // MAX_SIM_BB_EVAL: + // ---------------- + { + pe = entries.find ( "MAX_SIM_BB_EVAL" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_SIM_BB_EVAL not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_SIM_BB_EVAL" ); + pe->set_has_been_interpreted(); + set_MAX_SIM_BB_EVAL (i); + } + } + + // MAX_SGTE_EVAL: + // -------------- + { + pe = entries.find ( "MAX_SGTE_EVAL" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_SGTE_EVAL not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_SGTE_EVAL" ); + pe->set_has_been_interpreted(); + set_MAX_SGTE_EVAL (i); + } + } + + // MAX_TIME: + // --------- + { + pe = entries.find ( "MAX_TIME" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_TIME not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()), i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MAX_TIME" ); + + pe->set_has_been_interpreted(); + set_MAX_TIME (i); + } + } + + // STAT_SUM_TARGET: + // ---------------- + { + pe = entries.find ( "STAT_SUM_TARGET" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: STAT_SUM_TARGET not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: STAT_SUM_TARGET" ); + pe->set_has_been_interpreted(); + set_STAT_SUM_TARGET ( d ); + } + } + + // L_CURVE_TARGET: + // --------------- + { + pe = entries.find ( "L_CURVE_TARGET" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: L_CURVE_TARGET not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: L_CURVE_TARGET" ); + pe->set_has_been_interpreted(); + set_L_CURVE_TARGET ( d ); + } + } + + // EXTENDED_POLL_TRIGGER: + // ---------------------- + { + pe = entries.find ( "EXTENDED_POLL_TRIGGER" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: EXTENDED_POLL_TRIGGER not unique" ); + + bool rel; + + if ( pe->get_nb_values() != 1 || + !d.relative_atof ( *(pe->get_values().begin()) , rel ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: EXTENDED_POLL_TRIGGER" ); + + pe->set_has_been_interpreted(); + set_EXTENDED_POLL_TRIGGER ( d , rel ); + } + } + + // EXTENDED_POLL_ENABLED: + // ---------------------- + { + pe = entries.find ( "EXTENDED_POLL_ENABLED" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: EXTENDED_POLL_ENABLED not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: EXTENDED_POLL_ENABLED" ); + set_EXTENDED_POLL_ENABLED ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // USER_CALLS_ENABLED: + // ------------------- + { + pe = entries.find ( "USER_CALLS_ENABLED" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: USER_CALLS_ENABLED not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: USER_CALLS_ENABLED" ); + set_USER_CALLS_ENABLED ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // ASYNCHRONOUS: + // ------------- + { + pe = entries.find ( "ASYNCHRONOUS" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: ASYNCHRONOUS not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: ASYNCHRONOUS" ); + set_ASYNCHRONOUS ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // RHO: + // ---- + { + pe = entries.find ( "RHO" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: RHO not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: RHO" ); + pe->set_has_been_interpreted(); + set_RHO(d); + } + } + + // H_MIN: + // ------ + { + pe = entries.find ( "H_MIN" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: H_MIN not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: H_MIN" ); + pe->set_has_been_interpreted(); + set_H_MIN(d); + } + } + + // H_MAX_0: + // -------- + { + pe = entries.find ( "H_MAX_0" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: H_MAX_0 not unique" ); + if ( pe->get_nb_values() != 1 || !d.atof ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Invalid parameter: H_MAX_0" ); + pe->set_has_been_interpreted(); + set_H_MAX_0(d); + } + } + + // H_NORM: + // ------- + { + pe = entries.find ( "H_NORM" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: H_NORM not unique" ); + NOMAD::hnorm_type hn = NOMAD::L2; + if ( pe->get_nb_values() != 1 || + !NOMAD::string_to_hnorm_type ( *(pe->get_values().begin()) , hn ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Invalid parameter: H_NORM" ); + pe->set_has_been_interpreted(); + set_H_NORM ( hn ); + } + } + + // TMP_DIR: + // -------- + { + _tmp_dir.clear(); + pe = entries.find ( "TMP_DIR" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: TMP_DIR not unique" ); + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: TMP_DIR" ); + + set_TMP_DIR ( *(pe->get_values().begin()) ); + + pe->set_has_been_interpreted(); + } + } + + // ADD_SEED_TO_FILE_NAMES: + // ----------------------- + { + pe = entries.find ( "ADD_SEED_TO_FILE_NAMES" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: ADD_SEED_TO_FILE_NAMES not unique" ); + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: ADD_SEED_TO_FILE_NAMES" ); + + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: ADD_SEED_TO_FILE_NAMES" ); + set_ADD_SEED_TO_FILE_NAMES ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // SOLUTION_FILE: + // -------------- + { + _solution_file.clear(); + pe = entries.find ( "SOLUTION_FILE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SOLUTION_FILE not unique" ); + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SOLUTION_FILE" ); + set_SOLUTION_FILE ( *(pe->get_values().begin()) ); + pe->set_has_been_interpreted(); + } + } + + // HISTORY_FILE: + // ------------- + { + _history_file.clear(); + pe = entries.find ( "HISTORY_FILE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: HISTORY_FILE not unique" ); + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: HISTORY_FILE" ); + set_HISTORY_FILE ( *(pe->get_values().begin()) ); + pe->set_has_been_interpreted(); + } + } + + // STATS_FILE: + // ----------- + { + pe = entries.find ( "STATS_FILE" ); + if ( pe ) { + + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: STATS_FILE not unique" ); + + end = pe->get_values().end(); + it = pe->get_values().begin(); + std::string file_name = *it; + ++it; + + std::list<std::string> ls; + if (it!=end) + { + while ( it != end ) { + ls.push_back(*it); + ++it; + } + ls.resize(ls.size()-1); + } + + set_STATS_FILE ( file_name , ls ); + pe->set_has_been_interpreted(); + } + } + + // CACHE FILE: + // ----------- + { + _cache_file.clear(); + pe = entries.find ( "CACHE_FILE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: CACHE_FILE not unique" ); + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: CACHE_FILE" ); + set_CACHE_FILE ( *(pe->get_values().begin()) ); + pe->set_has_been_interpreted(); + } + } + + // SGTE_CACHE FILE: + // ---------------- + { + _sgte_cache_file.clear(); + pe = entries.find ( "SGTE_CACHE_FILE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_CACHE_FILE not unique" ); + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_CACHE_FILE" ); + set_SGTE_CACHE_FILE ( *(pe->get_values().begin()) ); + pe->set_has_been_interpreted(); + } + } + + + // CACHE_SAVE_PERIOD: + // ------------------ + { + pe = entries.find ( "CACHE_SAVE_PERIOD" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: CACHE_SAVE_PERIOD not unique" ); + if ( pe->get_nb_values() != 1 || !NOMAD::atoi (*(pe->get_values().begin()) , i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: CACHE_SAVE_PERIOD" ); + set_CACHE_SAVE_PERIOD (i); + pe->set_has_been_interpreted(); + } + } + + // SGTE_COST: + // ---------- + { + pe = entries.find ( "SGTE_COST" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_COST not unique" ); + if ( pe->get_nb_values() != 1 || + !NOMAD::atoi (*(pe->get_values().begin()) , i) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_COST" ); + set_SGTE_COST (i); + pe->set_has_been_interpreted(); + } + } + + // X0: + // --- + interpret_x0 ( entries ); + + // FIXED_VARIABLE: + // --------------- + interpret_BFVS ( entries , "FIXED_VARIABLE"); + + // LOWER_BOUND: + // ------------ + interpret_BFVS ( entries , "LOWER_BOUND"); + + // UPPER_BOUND: + // ------------ + interpret_BFVS ( entries , "UPPER_BOUND"); + + // SCALING: + // -------- + interpret_BFVS ( entries , "SCALING" ); + + // BB_INPUT_TYPE: + // -------------- + interpret_bb_input_type ( entries ); + + // F_TARGET: + // --------- + interpret_f_target ( entries ); + + // STOP_IF_FEASIBLE: + // ----------------- + pe = entries.find ( "STOP_IF_FEASIBLE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: STOP_IF_FEASIBLE not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: STOP_IF_FEASIBLE" ); + pe->set_has_been_interpreted(); + set_STOP_IF_FEASIBLE ( i == 1 ); + } + + // BB_INPUT_INCLUDE_TAG: + // --------------------- + { + pe = entries.find ( "BB_INPUT_INCLUDE_TAG" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_INCLUDE_TAG not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_INCLUDE_TAG" ); + set_BB_INPUT_INCLUDE_TAG ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // BB_INPUT_INCLUDE_SEED: + // ---------------------- + { + pe = entries.find ( "BB_INPUT_INCLUDE_SEED" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_INCLUDE_SEED not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_INCLUDE_SEED" ); + set_BB_INPUT_INCLUDE_SEED ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + // BB_REDIRECTION: + // --------------- + { + pe = entries.find ( "BB_REDIRECTION" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_REDIRECTION not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_REDIRECTION" ); + set_BB_REDIRECTION ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // INITIAL_POLL_SIZE, INITIAL_MESH_SIZE, MIN_MESH_SIZE, and MIN_POLL_SIZE: + // ---------------------------------------------------- + interpret_mesh_sizes ( entries , "INITIAL_MESH_SIZE" ); + interpret_mesh_sizes ( entries , "INITIAL_POLL_SIZE" ); + interpret_mesh_sizes ( entries , "MIN_MESH_SIZE" ); + interpret_mesh_sizes ( entries , "MIN_POLL_SIZE" ); + + // BB_OUTPUT_TYPE: + // --------------- + { + pe = entries.find ( "BB_OUTPUT_TYPE" ); + + if ( !pe ) { + if ( _bb_output_type.empty() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_OUTPUT_TYPE not defined" ); + } + else { + + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_OUTPUT_TYPE not unique" ); + + m = pe->get_nb_values(); + + if ( m <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_OUTPUT_TYPE" ); + + NOMAD::bb_output_type cur; + std::list<NOMAD::bb_output_type> bbot; + i = 0; + end = pe->get_values().end(); + for ( it = pe->get_values().begin() ; it != end ; ++it ) { + if ( !NOMAD::string_to_bb_output_type ( *it , cur ) ) { + err = "invalid parameter: BB_OUTPUT_TYPE (" + pe->get_name(); + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + bbot.push_back (cur); + } + + set_BB_OUTPUT_TYPE ( bbot ); + + pe->set_has_been_interpreted(); + } + } + + // NEIGHBORS_EXE: + // -------------- + { + _neighbors_exe.clear(); + pe = entries.find ( "NEIGHBORS_EXE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: NEIGHBORS_EXE not unique" ); + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: NEIGHBORS_EXE" ); + set_NEIGHBORS_EXE ( *(pe->get_values().begin()) ); + pe->set_has_been_interpreted(); + } + } + + // BB_EXE: + // ------- + { + pe = entries.find ( "BB_EXE" ); + if ( pe ) { + + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_EXE not unique" ); + + m = pe->get_nb_values(); + + if ( m == 1 ) + set_BB_EXE ( *pe->get_values().begin() ); + + else { + + if ( m != static_cast<int>(_bb_output_type.size()) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: number of BB_EXE (>1) and corresponding BB_OUTPUT_TYPE must be the same." ); + + std::list<std::string> bbexe; + end = pe->get_values().end(); + for ( it = pe->get_values().begin() ; it != end ; ++it ) + bbexe.push_back (*it); + + set_BB_EXE ( bbexe ); + } + + pe->set_has_been_interpreted(); + } + } + + // SGTE_EXE: + // --------- + { + pe = entries.find ( "SGTE_EXE" ); + if ( pe ) { + + std::string bb_exe_name , sgte_name; + + if ( pe->get_nb_values() == 1 ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_EXE (with one arguement) not unique" ); + sgte_name = *pe->get_values().begin(); + } + + else if ( pe->get_nb_values() == 2 ) { + bb_exe_name = *pe->get_values().begin(); + sgte_name = *(++pe->get_values().begin()); + } + + else + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_EXE" ); + + set_SGTE_EXE ( bb_exe_name , sgte_name ); + pe->set_has_been_interpreted(); + } + } + + // SGTE_EVAL_SORT: + // --------------- + { + pe = entries.find ( "SGTE_EVAL_SORT" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_EVAL_SORT not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_EVAL_SORT" ); + set_SGTE_EVAL_SORT ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // HAS_SGTE: + // --------- + { + pe = entries.find ( "HAS_SGTE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: HAS_SGTE not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: HAS_SGTE" ); + set_HAS_SGTE ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // OPT_ONLY_SGTE: + // -------------- + { + pe = entries.find ( "OPT_ONLY_SGTE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPT_ONLY_SGTE not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPT_ONLY_SGTE" ); + set_OPT_ONLY_SGTE ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // DISPLAY_DEGREE: + // --------------- + { + pe = entries.find ( "DISPLAY_DEGREE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DISPLAY_DEGREE not unique" ); + if ( pe->get_nb_values() != 1 || + !set_DISPLAY_DEGREE ( *(pe->get_values().begin()) ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DISPLAY_DEGREE" ); + pe->set_has_been_interpreted(); + } + } + + // OPEN_BRACE: + // ----------- + { + pe = entries.find ( "OPEN_BRACE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPEN_BRACE not unique" ); + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPEN_BRACE" ); + + set_OPEN_BRACE ( *(pe->get_values().begin()) ); + + pe->set_has_been_interpreted(); + } + } + + // CLOSED_BRACE: + // ------------- + { + pe = entries.find ( "CLOSED_BRACE" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: CLOSED_BRACE not unique" ); + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: CLOSED_BRACE" ); + + set_CLOSED_BRACE ( *(pe->get_values().begin()) ); + + pe->set_has_been_interpreted(); + } + } + + // DISPLAY_STATS: + { + pe = entries.find ( "DISPLAY_STATS" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DISPLAY_STATS not unique" ); + std::list<std::string> ls; + end = pe->get_values().end(); + for ( it = pe->get_values().begin() ; it != end ; ++it ) + ls.push_back ( *it ); + ls.resize ( ls.size()-1 ); + set_DISPLAY_STATS ( ls ); + pe->set_has_been_interpreted(); + } + } + + // DISPLAY_ALL_EVAL: + // ----------------- + { + pe = entries.find ( "DISPLAY_ALL_EVAL" ); + if ( pe ) { + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DISPLAY_ALL_EVAL not unique" ); + i = NOMAD::string_to_bool ( *(pe->get_values().begin() ) ); + if ( pe->get_nb_values() != 1 || i == -1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DISPLAY_ALL_EVAL" ); + set_DISPLAY_ALL_EVAL ( i == 1 ); + pe->set_has_been_interpreted(); + } + } + + // SEED: + // ----- + { + pe = entries.find ( "SEED" ); + + if ( pe ) + { + + if ( !pe->is_unique() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SEED not unique" ); + + if ( pe->get_nb_values() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SEED" ); + + s = *(pe->get_values().begin()); + NOMAD::toupper(s); + + + if ( s == "DIFF" ) + i = -1; + else if ( !NOMAD::atoi ( s , i ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SEED" ); + set_SEED(i); + pe->set_has_been_interpreted(); + + + } + } + + // VARIABLE_GROUP: + // --------------- + interpret_var_groups ( entries ); + + // PERIODIC_VARIABLE: + // ------------------ + interpret_periodic_var ( entries ); + + /*----------------------------------------------*/ + + // check the non-interpreted parameters: + pe = entries.find_non_interpreted(); + if ( pe ) { + err = "invalid parameter: " + pe->get_name() + " - unknown"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + // user must check the parameters with Parameters::check() } /*---------------------------------------*/ @@ -2797,644 +2882,654 @@ void NOMAD::Parameters::read ( const NOMAD::Parameter_Entries & entries ) /*---------------------------------------*/ void NOMAD::Parameters::display ( const NOMAD::Display & out ) const { - std::list<std::string>::const_iterator it; - - if ( _to_be_checked ) { - out << "parameters not checked" << std::endl; - return; - } - - // problem directory: - if ( !_problem_dir.empty() ) { - out << "problem directory : " << _problem_dir << std::endl; - if ( _tmp_dir != _problem_dir ) - out << "tmp directory : " << _tmp_dir << std::endl; - } - - // dimension: - out << "dimension : n=" << _dimension << std::endl; - - // bounds: - if ( _lb.is_defined() ) { - out << "lower bounds : ( "; - _lb.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - } - if ( _ub.is_defined() ) { - out << "upper bounds : ( "; - _ub.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - } - - // scaling: - if ( _scaling.is_defined() ) { - out << "scaling : ( "; - _scaling.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - } - - // fixed variables: - if ( _fixed_variables.is_defined() ) { - out << "fixed variables : ( "; - _fixed_variables.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - } - - // back-box input types: - if ( _bb_input_include_tag ) - out << "blackbox input files : include tag" << std::endl; - if ( _bb_input_include_seed ) - out << "blackbox input files : include seed" << std::endl; - - out << "blackbox input types : "; - if ( get_signature()->all_continuous() ) - out << "all variables are continuous (R)" << std::endl; - else - out << "( " << _bb_input_type << " )" << std::endl; - - // extended poll trigger: - if ( get_signature()->has_categorical() ) { - if ( _extended_poll_enabled ) { - out << "extended poll trigger: " << _extended_poll_trigger; - if ( _relative_ept ) - out << " (relative)"; - if ( !_neighbors_exe.empty() ) - out << std::endl << "neighbors executable : " << _neighbors_exe; - } - else - out << "extended poll is disabled"; - out << std::endl; - } - - // periodic variables: - if ( !_periodic_variables.empty() ) { - out << "periodic variables : { "; - for ( size_t k = 0 ; k < _periodic_variables.size() ; ++k ) - if ( _periodic_variables[k] ) - out << k << " "; - out << "}" << std::endl; - } - - // variable groups: - if ( _var_groups.size() > 1 ) { - int i = 0; - out.open_block ( "variable groups" ); - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::const_iterator - it2 , end2 = _var_groups.end(); - for ( it2 = _var_groups.begin() ; it2 != end2 ; ++it2 ) - out << NOMAD::open_block ( "group #" + NOMAD::itos ( i++ ) ) - << **it2 << NOMAD::close_block(); - out.close_block(); - } - - // blackbox outputs: - { - bool display_bb_exe = !_bb_exe.empty(); - bool display_sgte_exe = !_sgte_exe.empty(); - int m = static_cast<int>(_bb_output_type.size()); - int w = 1+int(log(static_cast<double>(m))/NOMAD::LOG10); - it = _bb_exe.begin(); - - out.open_block ( "blackbox outputs (m=" + NOMAD::itos ( m ) + ")" ); - for ( int i = 0 ; i < m ; ++i ) { - out << "#" << std::setw(w) << i << " " << std::setw(12) << _bb_output_type[i]; - if ( display_bb_exe ) { - out << "\t" << *it; - if ( display_sgte_exe ) - out << "\t" << get_sgte_exe(*it); - ++it; - } - out << std::endl; - } - out.close_block(); - } - - // signature (standard or extern): - out << "signature : " - << ( (_std_signature) ? "standard" : "extern" ) << std::endl; - - // BB_REDIRECTION: - if ( !_bb_redirection ) { - out << "blackbox output redirection : "; - out.display_yes_or_no ( _bb_redirection ); - out << std::endl; - } - - // surrogate: - { - out << "has surrogate : "; - out.display_yes_or_no ( _has_sgte ); - out << std::endl; - if ( _has_sgte ) { - - // OPT_ONLY_SGTE: - if ( _opt_only_sgte ) { - out << "minimize only with surrogate : "; - out.display_yes_or_no ( _opt_only_sgte ); - out << std::endl; - } - - // SGTE_EVAL_SORT: - out << "sort trial points with surrogate: "; - out.display_yes_or_no ( _sgte_eval_sort ); - out << std::endl; - - // SGTE_COST: - out << "surrogate cost : "; - if ( _sgte_cost > 0 ) - out << _sgte_cost - << " surrogate evaluations count as one bb evaluation" << std::endl; - else - out << "none" << std::endl; - } - } - - // MULTI-MADS: - if ( get_nb_obj() > 1 ) { - out << "multi-MADS : [overall bb eval="; - if ( _multi_overall_bb_eval >= 0 ) - out << _multi_overall_bb_eval; - else - out << "-"; - out << "] [nb MADS runs="; - if ( _multi_nb_mads_runs >= 0 ) - out << _multi_nb_mads_runs; - else - out << "-"; - out << "] [use delta crit="; - out.display_yes_or_no ( _multi_use_delta_crit ); - out << "]" << std::endl - << " [formulation=" - << _multi_formulation << "]"; - if ( _multi_f_bounds.is_defined() ) { - out << " [f_bounds="; - _multi_f_bounds.display ( out , "," , -1 , -1 ); - out << "]"; - } - out << std::endl; - } - - // barrier: - if ( _has_constraints ) { - - out << "barrier type : "; - switch ( _barrier_type ) { - case NOMAD::EB: - out << "extreme" << std::endl; - break; - case NOMAD::PEB_P: - case NOMAD::PB: - out << "progressive" << std::endl; - out << "prog. barrier trigger : " << _rho << std::endl; - break; - default: - out << "filter" << std::endl; - } - out << "barrier h_min : " << _h_min << std::endl - << "barrier initial h_max : " << _h_max_0 << std::endl; - } - if ( _has_filter_constraints ) - out << "barrier h_norm : " << _h_norm << std::endl; - - // ADD_SEED_TO_FILE_NAMES: - out << "add seed to output file names : "; - out.display_yes_or_no ( _add_seed_to_file_names ); - out << std::endl; - - // SOLUTION_FILE: - out << "solution file : "; - if ( !_solution_file.empty() ) - out << _solution_file << std::endl; - else - out << "none" << std::endl; - - // HISTORY_FILE: - out << "history file : "; - if ( !_history_file.empty() ) - out << _history_file << std::endl; - else - out << "none" << std::endl; - - // STATS_FILE: - out << "stats file : "; - if ( !_stats_file_name.empty() ) { - out << "(" << _stats_file_name << ") "; - std::list<std::string>::const_iterator end = _stats_file.end(); - for ( it = _stats_file.begin() ; it != end ; ++it ) { - if ( it->empty() ) - out << " "; - else - out << *it; - } - out << std::endl; - } - else - out << "none" << std::endl; - - // CACHE_FILE: - out << "cache file : "; - if ( !_cache_file.empty() ) { - out << _cache_file << std::endl; - out << "cache save period : "; - if ( _cache_save_period <= 0 ) - out << "never"; - else if ( _cache_save_period == 1 ) - out << "every iteration"; - else - out << "every " << _cache_save_period << " iterations"; - out << std::endl; - } - else - out << "none" << std::endl; - - // surrogate cache file: - if ( !_sgte_cache_file.empty() ) - out << "surrogate cache file : " - << _sgte_cache_file << std::endl; - - // X0: - if ( _x0s.empty() && _x0_cache_file.empty() ) - out << "x0 : points in \'" - << _cache_file << "\'" << std::endl; - else { - bool first = true; - if ( !_x0_cache_file.empty() ) { - if ( first ) { - out << "x0 : "; - first = false; - } - else - out << " : "; - out << _x0_cache_file; - if ( _x0_cache_file != _cache_file ) - out << " (read only)"; - out << std::endl; - } - if ( !_x0s.empty() ) { - size_t x0n = _x0s.size(); - for ( size_t k = 0 ; k < x0n ; ++k ) { - if ( first ) { - out << "x0 : "; - first = false; - } - else - out << " : "; - out << "( "; - _x0s[k]->display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - } - } - } - - // directions: - { - std::set<NOMAD::direction_type>::const_iterator it , end = _direction_types.end(); - if ( _direction_types.size() == 1 ) - out << "directions : " - << *_direction_types.begin() << std::endl; - else { - out << NOMAD::open_block ( "directions" ); - for ( it = _direction_types.begin() ; it != end ; ++it ) - out << *it << std::endl; - out.close_block(); - } - if ( _barrier_type == NOMAD::PB || _barrier_type == NOMAD::PEB_P ) { - if ( _sec_poll_dir_types.empty() ) - out << "sec. poll dir. type: no secondary poll" << std::endl; - else { - if ( _sec_poll_dir_types.size() == 1 ) - out << "sec. poll dir. type: " - << *_sec_poll_dir_types.begin() << std::endl; - else { - end = _sec_poll_dir_types.end(); - out << NOMAD::open_block ( "sec. poll dir. types" ); - for ( it = _sec_poll_dir_types.begin() ; it != end ; ++it ) - out << *it << std::endl; - out.close_block(); - } - } - } - if ( _halton_seed >= 0 ) - out << "user halton seed : " << _halton_seed << std::endl; - - } - - // mesh: - { - out << NOMAD::open_block ( "mesh" ) - << "update basis : " << std::setw(3) << _mesh_update_basis << std::endl - << "coarsening exponent: " << std::setw(3) << _mesh_coarsening_exponent - << std::endl - << "refining exponent : " << std::setw(3) << _mesh_refining_exponent - << std::endl - << "initial mesh index : " << std::setw(3) << _initial_mesh_index << std::endl; - if ( _max_mesh_index != NOMAD::UNDEFINED_L ) - out << "max mesh index : " << std::setw(3) << _max_mesh_index << std::endl; - out << "initial mesh size : ( "; - _initial_mesh_size.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - if ( _min_mesh_size.is_defined() ) { - out << "min mesh size : ( "; - _min_mesh_size.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - } - if ( _min_poll_size.is_defined() ) { - out << "min poll size : ( "; - _min_poll_size.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - } - out.close_block(); - } - - // ASYNCHRONOUS: + std::list<std::string>::const_iterator it; + + if ( _to_be_checked ) { + out << "parameters not checked" << std::endl; + return; + } + + // problem directory: + if ( !_problem_dir.empty() ) { + out << "problem directory : " << _problem_dir << std::endl; + if ( _tmp_dir != _problem_dir ) + out << "tmp directory : " << _tmp_dir << std::endl; + } + + // dimension: + out << "dimension : n=" << _dimension << std::endl; + + // bounds: + if ( _lb.is_defined() ) { + out << "lower bounds : ( "; + _lb.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + if ( _ub.is_defined() ) { + out << "upper bounds : ( "; + _ub.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + + // scaling: + if ( _scaling.is_defined() ) { + out << "scaling : ( "; + _scaling.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + + // fixed variables: + if ( _fixed_variables.is_defined() ) { + out << "fixed variables : ( "; + _fixed_variables.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + + // back-box input types: + if ( _bb_input_include_tag ) + out << "blackbox input files : include tag" << std::endl; + if ( _bb_input_include_seed ) + out << "blackbox input files : include seed" << std::endl; + + out << "blackbox input types : "; + if ( get_signature()->all_continuous() ) + out << "all variables are continuous (R)" << std::endl; + else + out << "( " << _bb_input_type << " )" << std::endl; + + // extended poll trigger: + if ( get_signature()->has_categorical() ) { + if ( _extended_poll_enabled ) { + out << "extended poll trigger: " << _extended_poll_trigger; + if ( _relative_ept ) + out << " (relative)"; + if ( !_neighbors_exe.empty() ) + out << std::endl << "neighbors executable : " << _neighbors_exe; + } + else + out << "extended poll is disabled"; + out << std::endl; + } + + // periodic variables: + if ( !_periodic_variables.empty() ) { + out << "periodic variables : { "; + for ( size_t k = 0 ; k < _periodic_variables.size() ; ++k ) + if ( _periodic_variables[k] ) + out << k << " "; + out << "}" << std::endl; + } + + // variable groups: + if ( _var_groups.size() > 1 ) { + int i = 0; + out.open_block ( "variable groups" ); + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::const_iterator + it2 , end2 = _var_groups.end(); + for ( it2 = _var_groups.begin() ; it2 != end2 ; ++it2 ) + out << NOMAD::open_block ( "group #" + NOMAD::itos ( i++ ) ) + << **it2 << NOMAD::close_block(); + out.close_block(); + } + + // blackbox outputs: + { + bool display_bb_exe = !_bb_exe.empty(); + bool display_sgte_exe = !_sgte_exe.empty(); + int m = static_cast<int>(_bb_output_type.size()); + int w = 1+int(log(static_cast<double>(m))/NOMAD::LOG10); + it = _bb_exe.begin(); + + out.open_block ( "blackbox outputs (m=" + NOMAD::itos ( m ) + ")" ); + for ( int i = 0 ; i < m ; ++i ) { + out << "#" << std::setw(w) << i << " " << std::setw(12) << _bb_output_type[i]; + if ( display_bb_exe ) { + out << "\t" << *it; + if ( display_sgte_exe ) + out << "\t" << get_sgte_exe(*it); + ++it; + } + out << std::endl; + } + out.close_block(); + } + + // signature (standard or extern): + out << "signature : " + << ( (_std_signature) ? "standard" : "extern" ) << std::endl; + + // BB_REDIRECTION: + if ( !_bb_redirection ) { + out << "blackbox output redirection : "; + out.display_yes_or_no ( _bb_redirection ); + out << std::endl; + } + + // surrogate: + { + out << "has surrogate : "; + out.display_yes_or_no ( _has_sgte ); + out << std::endl; + if ( _has_sgte ) { + + // OPT_ONLY_SGTE: + if ( _opt_only_sgte ) { + out << "minimize only with surrogate : "; + out.display_yes_or_no ( _opt_only_sgte ); + out << std::endl; + } + + // SGTE_EVAL_SORT: + out << "sort trial points with surrogate: "; + out.display_yes_or_no ( _sgte_eval_sort ); + out << std::endl; + + // SGTE_COST: + out << "surrogate cost : "; + if ( _sgte_cost > 0 ) + out << _sgte_cost + << " surrogate evaluations count as one bb evaluation" << std::endl; + else + out << "none" << std::endl; + } + } + + // MULTI-MADS: + if ( get_nb_obj() > 1 ) { + out << "multi-MADS : [overall bb eval="; + if ( _multi_overall_bb_eval >= 0 ) + out << _multi_overall_bb_eval; + else + out << "-"; + out << "] [nb MADS runs="; + if ( _multi_nb_mads_runs >= 0 ) + out << _multi_nb_mads_runs; + else + out << "-"; + out << "] [use delta crit="; + out.display_yes_or_no ( _multi_use_delta_crit ); + out << "]" << std::endl + << " [formulation=" + << _multi_formulation << "]"; + if ( _multi_f_bounds.is_defined() ) { + out << " [f_bounds="; + _multi_f_bounds.display ( out , "," , -1 , -1 ); + out << "]"; + } + out << std::endl; + } + + // barrier: + if ( _has_constraints ) { + + out << "barrier type : "; + switch ( _barrier_type ) { + case NOMAD::EB: + out << "extreme" << std::endl; + break; + case NOMAD::PEB_P: + case NOMAD::PB: + out << "progressive" << std::endl; + out << "prog. barrier trigger : " << _rho << std::endl; + break; + default: + out << "filter" << std::endl; + } + out << "barrier h_min : " << _h_min << std::endl + << "barrier initial h_max : " << _h_max_0 << std::endl; + } + if ( _has_filter_constraints ) + out << "barrier h_norm : " << _h_norm << std::endl; + + // ADD_SEED_TO_FILE_NAMES: + out << "add seed to output file names : "; + out.display_yes_or_no ( _add_seed_to_file_names ); + out << std::endl; + + // SOLUTION_FILE: + out << "solution file : "; + if ( !_solution_file.empty() ) + out << _solution_file << std::endl; + else + out << "none" << std::endl; + + // HISTORY_FILE: + out << "history file : "; + if ( !_history_file.empty() ) + out << _history_file << std::endl; + else + out << "none" << std::endl; + + // STATS_FILE: + out << "stats file : "; + if ( !_stats_file_name.empty() ) { + out << "(" << _stats_file_name << ") "; + std::list<std::string>::const_iterator end = _stats_file.end(); + for ( it = _stats_file.begin() ; it != end ; ++it ) { + if ( it->empty() ) + out << " "; + else + out << *it; + } + out << std::endl; + } + else + out << "none" << std::endl; + + // CACHE_FILE: + out << "cache file : "; + if ( !_cache_file.empty() ) { + out << _cache_file << std::endl; + out << "cache save period : "; + if ( _cache_save_period <= 0 ) + out << "never"; + else if ( _cache_save_period == 1 ) + out << "every iteration"; + else + out << "every " << _cache_save_period << " iterations"; + out << std::endl; + } + else + out << "none" << std::endl; + + // surrogate cache file: + if ( !_sgte_cache_file.empty() ) + out << "surrogate cache file : " + << _sgte_cache_file << std::endl; + + // X0: + if ( _x0s.empty() && _x0_cache_file.empty() ) + out << "x0 : points in \'" + << _cache_file << "\'" << std::endl; + else { + bool first = true; + if ( !_x0_cache_file.empty() ) { + if ( first ) { + out << "x0 : "; + first = false; + } + else + out << " : "; + out << _x0_cache_file; + if ( _x0_cache_file != _cache_file ) + out << " (read only)"; + out << std::endl; + } + if ( !_x0s.empty() ) { + size_t x0n = _x0s.size(); + for ( size_t k = 0 ; k < x0n ; ++k ) { + if ( first ) { + out << "x0 : "; + first = false; + } + else + out << " : "; + out << "( "; + _x0s[k]->display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + } + } + + // directions: + { + std::set<NOMAD::direction_type>::const_iterator it , end = _direction_types.end(); + if ( _direction_types.size() == 1 ) + out << "directions : " + << *_direction_types.begin() << std::endl; + else { + out << NOMAD::open_block ( "directions" ); + for ( it = _direction_types.begin() ; it != end ; ++it ) + out << *it << std::endl; + out.close_block(); + } + if ( _barrier_type == NOMAD::PB || _barrier_type == NOMAD::PEB_P ) { + if ( _sec_poll_dir_types.empty() ) + out << "sec. poll dir. type: no secondary poll" << std::endl; + else { + if ( _sec_poll_dir_types.size() == 1 ) + out << "sec. poll dir. type: " + << *_sec_poll_dir_types.begin() << std::endl; + else { + end = _sec_poll_dir_types.end(); + out << NOMAD::open_block ( "sec. poll dir. types" ); + for ( it = _sec_poll_dir_types.begin() ; it != end ; ++it ) + out << *it << std::endl; + out.close_block(); + } + } + } + + } + + // mesh: + { + if ( get_use_smesh() ) + { + out << NOMAD::open_block ( "smesh (isotropic)" ); + out << "mesh update basis : " << std::setw(3) << _mesh_update_basis << std::endl; + } + else + { + if ( get_anisotropic_mesh() ) + out << NOMAD::open_block ( "xmesh (anisotropic)" ); + else + out << NOMAD::open_block ( "xmesh (isotropic)" ); + out << "poll update basis : " << std::setw(3) << _poll_update_basis << std::endl; + } + out << "coarsening exponent : " << std::setw(3) << _mesh_coarsening_exponent + << std::endl + << "refining exponent : " << std::setw(3) << _mesh_refining_exponent + << std::endl + << "initial mesh index : " << std::setw(3) << _initial_mesh_index << std::endl; + out << "initial mesh size : ( "; + _initial_mesh_size.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + out << "initial poll size : ( "; + _initial_poll_size.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + if ( _min_mesh_size.is_defined() ) { + out << "min mesh size : ( "; + _min_mesh_size.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + if ( _min_poll_size.is_defined() ) { + out << "min poll size : ( "; + _min_poll_size.display ( out , " " , 4 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + out.close_block(); + } + + // ASYNCHRONOUS: #ifdef USE_MPI - out << "asynchronous : "; - out.display_yes_or_no ( _asynchronous ); - out << std::endl; + out << "asynchronous : "; + out.display_yes_or_no ( _asynchronous ); + out << std::endl; #endif - - // USER_CALLS_ENABLED: - if ( !_user_calls_enabled ) - out << "user calls : disabled" << std::endl; - - // SNAP_TO_BOUNDS: - out << "snap to bounds : "; - out.display_yes_or_no ( _snap_to_bounds ); - out << std::endl; - - // opportunistic strategy: - { - out << "opportunistic evaluations : "; - out.display_yes_or_no ( _opportunistic_eval ); - out << std::endl; - if ( _opportunistic_eval ) { - if ( _opportunistic_min_nb_success > 0 ) - out << "opportunistic min nb success : " - << _opportunistic_min_nb_success << std::endl; - if ( _opportunistic_min_eval > 0 ) - out << "opportunistic min nb eval : " - << _opportunistic_min_eval << std::endl; - if ( _opportunistic_min_f_imprvmt.is_defined() ) - out << "opportunistic min obj improvement: " - << _opportunistic_min_f_imprvmt << "%" - << std::endl; - if ( _opportunistic_lucky_eval ) - out << "opportunistic lucky eval : " - << _opportunistic_lucky_eval << std::endl; - } - } - - // models: - if (_disable_models) - { - out << NOMAD::open_block ( "models" ); - out << "models usage has been forcefully disabled: " - << std::endl << NOMAD::close_block(); - } - else - { - if ( _model_params.search1 != NOMAD::NO_MODEL || - _model_params.eval_sort != NOMAD::NO_MODEL ) - { - out << NOMAD::open_block ( "models" ); - if ( _model_params.search1 != NOMAD::NO_MODEL ) - { - out << NOMAD::open_block ( "model search" ); - if ( _model_params.search2 == NOMAD::NO_MODEL ) - out << "models type : " << _model_params.search1 << std::endl; - else - out << "models types : " - << _model_params.search1 << " and " - << _model_params.search2 << std::endl; - out << "project to mesh: "; - out.display_yes_or_no ( _model_params.search_proj_to_mesh ); - out << std::endl - << "optimistic : "; - out.display_yes_or_no ( _model_params.search_optimistic ); - out << std::endl - << "max trial pts : " << _model_params.search_max_trial_pts - << std::endl << NOMAD::close_block(); - } - else - out << "no model search" << std::endl; - - // model ordering: - if ( _model_params.eval_sort != NOMAD::NO_MODEL ) { - if ( _model_params.eval_sort == NOMAD::QUADRATIC_MODEL ) { - out << NOMAD::open_block ( "model ordering" ) - << "models type : " << _model_params.eval_sort - << std::endl << "cautious model ordering: "; - out.display_yes_or_no ( _model_params.eval_sort_cautious ); - out << std::endl << NOMAD::close_block(); - } - else - out << "model ordering: " << _model_params.eval_sort << std::endl; - } - else - out << "no model ordering" << std::endl; - - - if ( has_direction_type(NOMAD::ORTHO_NP1_QUAD) ) - { - out << NOMAD::open_block ( "Quad model (n+1)th dynamic direction for Ortho N+1" ) - << "models type : QUADRATIC " - << std::endl << "cautious model ordering: "; - out.display_yes_or_no ( _model_params.eval_sort_cautious ); - out << std::endl << "quad model epsilon for ortho n+1: " - << _model_params.model_np1_quad_epsilon << std::endl; - out << std::endl << NOMAD::close_block(); - } - - // quadratic model parameters: - if ( _model_params.eval_sort == NOMAD::QUADRATIC_MODEL || - _model_params.search1 == NOMAD::QUADRATIC_MODEL || - _model_params.search2 == NOMAD::QUADRATIC_MODEL ) { - out << NOMAD::open_block ( "quadratic model parameters" ) - << "radius factor: " << _model_params.quad_radius_factor << std::endl - << "use WP : "; - out.display_yes_or_no ( _model_params.quad_use_WP ); - out << std::endl << "min Y size : "; - if ( _model_params.quad_min_Y_size < 0 ) - out << "n+1"; - else - out << _model_params.quad_min_Y_size; - out << std::endl - << "max Y size : " << _model_params.quad_max_Y_size - << std::endl << NOMAD::close_block(); - } - - // TGP model parameters: - if ( _model_params.eval_sort == NOMAD::TGP_MODEL || - _model_params.search1 == NOMAD::TGP_MODEL || - _model_params.search2 == NOMAD::TGP_MODEL ) { - out << NOMAD::open_block ( "TGP model parameters" ) - << "mode : " << _model_params.tgp_mode << std::endl - << "reuse model: " << _model_params.tgp_reuse_model << std::endl - << NOMAD::close_block(); - } - out.close_block(); - } - else { - out << "use models : "; - out.display_yes_or_no ( false ); - out << std::endl; - } - } - - // SPECULATIVE_SEARCH: - out << "speculative search : "; - out.display_yes_or_no ( _speculative_search ); - out << std::endl; - - // VNS_SEARCH: - out << "VNS search : "; - out.display_yes_or_no ( _VNS_search ); - if ( _VNS_search ) - out << " [trigger=" << _VNS_trigger << "]"; - out << std::endl; - - // LH_SEARCH: - out << "Latin-Hypercube (LH) search : "; - if ( _LH_search_p0 > 0 || _LH_search_pi > 0 ) { - out << "#init:" << _LH_search_p0 - << ", #iter:" << _LH_search_pi - << ", opport:"; - out.display_yes_or_no ( _opportunistic_LH ); - } - else - out.display_yes_or_no ( false ); - out << std::endl; - - // CACHE_SEARCH: - out << "cache search : "; - if ( _cache_search ) { - out.display_yes_or_no ( true ); - out << ", opport:"; - out.display_yes_or_no ( _opportunistic_cache_search ); - } - else - out.display_yes_or_no ( false ); - out << std::endl; - - // random seed / unique tag / run id: - out << "random seed / run id : " << _seed << std::endl; - - // EPSILON: - out << "epsilon : " - << NOMAD::Double::get_epsilon() << std::endl; - - // UNDEF_STR: - out << "undefined string : " - << NOMAD::Double::get_undef_str() << std::endl; - - // INF_STR: - out << "infinity string : " - << NOMAD::Double::get_inf_str() << std::endl; - - // DISPLAY_DEGREEs: - out << NOMAD::open_block ( "display degrees" ) - << "general : " << _out.get_gen_dd() << std::endl - << "search : " << _out.get_search_dd() << std::endl - << "poll : " << _out.get_poll_dd() << std::endl - << "iterative: " << _out.get_iter_dd() << std::endl - << NOMAD::close_block(); - - // DISPLAY_STATS: - out << "display stats : "; - std::list<std::string>::const_iterator end = _display_stats.end(); - for ( it = _display_stats.begin() ; it != end ; ++it ) { - if ( it->empty() ) - out << " "; - else - out << *it; - } - out << std::endl; - - // DISPLAY_ALL_EVAL: - out << "display all evaluations : "; - out.display_yes_or_no ( _display_all_eval ); - out << std::endl; - - // POINT_DISPLAY_LIMIT: - out << "point display limit : "; - if ( NOMAD::Point::get_display_limit() > 0 ) - out << NOMAD::Point::get_display_limit() << std::endl; - else - out << "no limit" << std::endl; - - // MAX_EVAL: - if ( _max_eval > 0 ) - out << "max eval. (bb+cache) : " << _max_eval << std::endl; - - // MAX_BB_EVAL: - if ( _max_bb_eval >= 0 ) { - out << "max number of blackbox eval. : " << _max_bb_eval; - if ( _max_bb_eval == 0 ) - out << " (no blackbox eval. allowed)"; - out << std::endl; - } - - // MAX_SIM_BB_EVAL: - if ( _max_sim_bb_eval >= 0 ) - out << "max simulated blackbox eval. : " << _max_sim_bb_eval << std::endl; - - // MAX_SGTE_EVAL: - if ( _sgte_max_eval >= 0 ) { - out << "max surrogate eval. : " << _sgte_max_eval; - if ( _sgte_max_eval == 0 ) - out << " (no surrogate eval. allowed)"; - out << std::endl; - } - - // MAX_ITERATIONS: - if ( _max_iterations >= 0 ) { - out << "max iterations : " << _max_iterations; - if ( _max_iterations == 0 ) - out << " (no iterations allowed)"; - out << std::endl; - } - - // MAX_CONSECUTIVE_FAILED_ITERATIONS: - if ( _max_cons_failed_it > 0 ) - out << "max consecutive failed it. : " << _max_cons_failed_it << std::endl; - - // MAX_CACHE_MEMORY: - if ( _max_cache_memory > 0 ) - out << "max cache memory : " << _max_cache_memory - << " MB" << std::endl; - - // MAX_TIME: - if ( _max_time > 0 ) - out << "max wall-clock time : " << _max_time << "s" << std::endl; - - // F_TARGET: - if ( _f_target.is_defined() ) { - out << "objective target : "; - if ( _f_target.size() > 1 ) { - out << "( "; - _f_target.display ( out , " " , 4 , -1 ); - out << " )" << std::endl; - } - else - out << _f_target[0] << std::endl; - } - - // STAT_SUM_TARGET: - if ( _stat_sum_target.is_defined() ) - out << "stat sum target : " - << _stat_sum_target << std::endl; - - // L_CURVE_TARGET: - if ( _L_curve_target.is_defined() ) - out << "L-curve target : " - << _L_curve_target << std::endl; - - // STOP_IF_FEASIBLE: - if ( _stop_if_feasible ) { - out << "stop if feasible : "; - out.display_yes_or_no ( _stop_if_feasible ); - out << std::endl; - } + + // USER_CALLS_ENABLED: + if ( !_user_calls_enabled ) + out << "user calls : disabled" << std::endl; + + // SNAP_TO_BOUNDS: + out << "snap to bounds : "; + out.display_yes_or_no ( _snap_to_bounds ); + out << std::endl; + + // opportunistic strategy: + { + out << "opportunistic evaluations : "; + out.display_yes_or_no ( _opportunistic_eval ); + out << std::endl; + if ( _opportunistic_eval ) { + if ( _opportunistic_min_nb_success > 0 ) + out << "opportunistic min nb success : " + << _opportunistic_min_nb_success << std::endl; + if ( _opportunistic_min_eval > 0 ) + out << "opportunistic min nb eval : " + << _opportunistic_min_eval << std::endl; + if ( _opportunistic_min_f_imprvmt.is_defined() ) + out << "opportunistic min obj improvement: " + << _opportunistic_min_f_imprvmt << "%" + << std::endl; + if ( _opportunistic_lucky_eval ) + out << "opportunistic lucky eval : " + << _opportunistic_lucky_eval << std::endl; + } + } + + // models: + if (_disable_models) + { + out << NOMAD::open_block ( "models" ); + out << "models usage has been forcefully disabled: " + << std::endl << NOMAD::close_block(); + } + else + { + if ( _model_params.search1 != NOMAD::NO_MODEL || + _model_params.eval_sort != NOMAD::NO_MODEL ) + { + out << NOMAD::open_block ( "models" ); + if ( _model_params.search1 != NOMAD::NO_MODEL ) + { + out << NOMAD::open_block ( "model search" ); + if ( _model_params.search2 == NOMAD::NO_MODEL ) + out << "models type : " << _model_params.search1 << std::endl; + else + out << "models types : " + << _model_params.search1 << " and " + << _model_params.search2 << std::endl; + out << "project to mesh: "; + out.display_yes_or_no ( _model_params.search_proj_to_mesh ); + out << std::endl + << "optimistic : "; + out.display_yes_or_no ( _model_params.search_optimistic ); + out << std::endl + << "max trial pts : " << _model_params.search_max_trial_pts + << std::endl << NOMAD::close_block(); + } + else + out << "no model search" << std::endl; + + // model ordering: + if ( _model_params.eval_sort != NOMAD::NO_MODEL ) { + if ( _model_params.eval_sort == NOMAD::QUADRATIC_MODEL ) { + out << NOMAD::open_block ( "model ordering" ) + << "models type : " << _model_params.eval_sort + << std::endl << "cautious model ordering: "; + out.display_yes_or_no ( _model_params.eval_sort_cautious ); + out << std::endl << NOMAD::close_block(); + } + else + out << "model ordering: " << _model_params.eval_sort << std::endl; + } + else + out << "no model ordering" << std::endl; + + + if ( has_direction_type(NOMAD::ORTHO_NP1_QUAD) ) + { + out << NOMAD::open_block ( "Quad model (n+1)th dynamic direction for Ortho N+1" ) + << "models type : QUADRATIC " + << std::endl << "cautious model ordering: "; + out.display_yes_or_no ( _model_params.eval_sort_cautious ); + out << std::endl << "quad model epsilon for ortho n+1: " + << _model_params.model_np1_quad_epsilon << std::endl; + out << std::endl << NOMAD::close_block(); + } + + // quadratic model parameters: + if ( _model_params.eval_sort == NOMAD::QUADRATIC_MODEL || + _model_params.search1 == NOMAD::QUADRATIC_MODEL || + _model_params.search2 == NOMAD::QUADRATIC_MODEL ) { + out << NOMAD::open_block ( "quadratic model parameters" ) + << "radius factor: " << _model_params.quad_radius_factor << std::endl + << "use WP : "; + out.display_yes_or_no ( _model_params.quad_use_WP ); + out << std::endl << "min Y size : "; + if ( _model_params.quad_min_Y_size < 0 ) + out << "n+1"; + else + out << _model_params.quad_min_Y_size; + out << std::endl + << "max Y size : " << _model_params.quad_max_Y_size + << std::endl << NOMAD::close_block(); + } + + // TGP model parameters: + if ( _model_params.eval_sort == NOMAD::TGP_MODEL || + _model_params.search1 == NOMAD::TGP_MODEL || + _model_params.search2 == NOMAD::TGP_MODEL ) { + out << NOMAD::open_block ( "TGP model parameters" ) + << "mode : " << _model_params.tgp_mode << std::endl + << "reuse model: " << _model_params.tgp_reuse_model << std::endl + << NOMAD::close_block(); + } + out.close_block(); + } + else { + out << "use models : "; + out.display_yes_or_no ( false ); + out << std::endl; + } + } + + // SPECULATIVE_SEARCH: + out << "speculative search : "; + out.display_yes_or_no ( _speculative_search ); + out << std::endl; + + // VNS_SEARCH: + out << "VNS search : "; + out.display_yes_or_no ( _VNS_search ); + if ( _VNS_search ) + out << " [trigger=" << _VNS_trigger << "]"; + out << std::endl; + + // LH_SEARCH: + out << "Latin-Hypercube (LH) search : "; + if ( _LH_search_p0 > 0 || _LH_search_pi > 0 ) { + out << "#init:" << _LH_search_p0 + << ", #iter:" << _LH_search_pi + << ", opport:"; + out.display_yes_or_no ( _opportunistic_LH ); + } + else + out.display_yes_or_no ( false ); + out << std::endl; + + // CACHE_SEARCH: + out << "cache search : "; + if ( _cache_search ) { + out.display_yes_or_no ( true ); + out << ", opport:"; + out.display_yes_or_no ( _opportunistic_cache_search ); + } + else + out.display_yes_or_no ( false ); + out << std::endl; + + // random seed / unique tag / run id: + out << "random seed / run id : " << _seed << std::endl; + + // EPSILON: + out << "epsilon : " + << NOMAD::Double::get_epsilon() << std::endl; + + // UNDEF_STR: + out << "undefined string : " + << NOMAD::Double::get_undef_str() << std::endl; + + // INF_STR: + out << "infinity string : " + << NOMAD::Double::get_inf_str() << std::endl; + + // DISPLAY_DEGREEs: + out << NOMAD::open_block ( "display degrees" ) + << "general : " << _out.get_gen_dd() << std::endl + << "search : " << _out.get_search_dd() << std::endl + << "poll : " << _out.get_poll_dd() << std::endl + << "iterative: " << _out.get_iter_dd() << std::endl + << NOMAD::close_block(); + + // DISPLAY_STATS: + out << "display stats : "; + std::list<std::string>::const_iterator end = _display_stats.end(); + for ( it = _display_stats.begin() ; it != end ; ++it ) { + if ( it->empty() ) + out << " "; + else + out << *it; + } + out << std::endl; + + // DISPLAY_ALL_EVAL: + out << "display all evaluations : "; + out.display_yes_or_no ( _display_all_eval ); + out << std::endl; + + // POINT_DISPLAY_LIMIT: + out << "point display limit : "; + if ( NOMAD::Point::get_display_limit() > 0 ) + out << NOMAD::Point::get_display_limit() << std::endl; + else + out << "no limit" << std::endl; + + // MAX_EVAL: + if ( _max_eval > 0 ) + out << "max eval. (bb+cache) : " << _max_eval << std::endl; + + // MAX_BB_EVAL: + if ( _max_bb_eval >= 0 ) { + out << "max number of blackbox eval. : " << _max_bb_eval; + if ( _max_bb_eval == 0 ) + out << " (no blackbox eval. allowed)"; + out << std::endl; + } + + // MAX_SIM_BB_EVAL: + if ( _max_sim_bb_eval >= 0 ) + out << "max simulated blackbox eval. : " << _max_sim_bb_eval << std::endl; + + // MAX_SGTE_EVAL: + if ( _sgte_max_eval >= 0 ) { + out << "max surrogate eval. : " << _sgte_max_eval; + if ( _sgte_max_eval == 0 ) + out << " (no surrogate eval. allowed)"; + out << std::endl; + } + + // MAX_ITERATIONS: + if ( _max_iterations >= 0 ) { + out << "max iterations : " << _max_iterations; + if ( _max_iterations == 0 ) + out << " (no iterations allowed)"; + out << std::endl; + } + + // MAX_CONSECUTIVE_FAILED_ITERATIONS: + if ( _max_cons_failed_it > 0 ) + out << "max consecutive failed it. : " << _max_cons_failed_it << std::endl; + + // MAX_CACHE_MEMORY: + if ( _max_cache_memory > 0 ) + out << "max cache memory : " << _max_cache_memory + << " MB" << std::endl; + + // MAX_TIME: + if ( _max_time > 0 ) + out << "max wall-clock time : " << _max_time << "s" << std::endl; + + // F_TARGET: + if ( _f_target.is_defined() ) { + out << "objective target : "; + if ( _f_target.size() > 1 ) { + out << "( "; + _f_target.display ( out , " " , 4 , -1 ); + out << " )" << std::endl; + } + else + out << _f_target[0] << std::endl; + } + + // STAT_SUM_TARGET: + if ( _stat_sum_target.is_defined() ) + out << "stat sum target : " + << _stat_sum_target << std::endl; + + // L_CURVE_TARGET: + if ( _L_curve_target.is_defined() ) + out << "L-curve target : " + << _L_curve_target << std::endl; + + // STOP_IF_FEASIBLE: + if ( _stop_if_feasible ) { + out << "stop if feasible : "; + out.display_yes_or_no ( _stop_if_feasible ); + out << std::endl; + } } /*---------------------------------------*/ @@ -3442,8 +3537,8 @@ void NOMAD::Parameters::display ( const NOMAD::Display & out ) const /*---------------------------------------*/ void NOMAD::Parameters::reset_stats_file ( void ) { - _stats_file.clear(); - _stats_file_name.clear(); + _stats_file.clear(); + _stats_file_name.clear(); } /*---------------------------------------*/ @@ -3454,18 +3549,18 @@ void NOMAD::Parameters::reset_stats_file ( void ) void NOMAD::Parameters::reset_variable_groups ( std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & vg ) const { - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::const_iterator end = vg.end() , it; - for ( it = vg.begin() ; it != end ; ++it ) - delete *it; - vg.clear(); + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::const_iterator end = vg.end() , it; + for ( it = vg.begin() ; it != end ; ++it ) + delete *it; + vg.clear(); } // 2/2 (public): void NOMAD::Parameters::reset_variable_groups ( void ) { - _to_be_checked = true; - reset_variable_groups ( _var_groups ); - reset_variable_groups ( _user_var_groups ); + _to_be_checked = true; + reset_variable_groups ( _var_groups ); + reset_variable_groups ( _user_var_groups ); } /*---------------------------------------*/ @@ -3473,8 +3568,8 @@ void NOMAD::Parameters::reset_variable_groups ( void ) /*---------------------------------------*/ void NOMAD::Parameters::reset_fixed_variables ( void ) { - _to_be_checked = true; - _fixed_variables.clear(); + _to_be_checked = true; + _fixed_variables.clear(); } /*---------------------------------------*/ @@ -3482,8 +3577,8 @@ void NOMAD::Parameters::reset_fixed_variables ( void ) /*---------------------------------------*/ void NOMAD::Parameters::reset_periodic_variables ( void ) { - _to_be_checked = true; - _periodic_variables.clear(); + _to_be_checked = true; + _periodic_variables.clear(); } /*---------------------------------------*/ @@ -3491,9 +3586,9 @@ void NOMAD::Parameters::reset_periodic_variables ( void ) /*---------------------------------------*/ void NOMAD::Parameters::reset_bounds ( void ) { - _to_be_checked = true; - _lb.clear(); - _ub.clear(); + _to_be_checked = true; + _lb.clear(); + _ub.clear(); } /*---------------------------------------*/ @@ -3501,1028 +3596,1150 @@ void NOMAD::Parameters::reset_bounds ( void ) /*---------------------------------------*/ void NOMAD::Parameters::reset_scaling ( void ) { - _to_be_checked = true; - _scaling.clear(); + _to_be_checked = true; + _scaling.clear(); } /*----------------------------------------*/ /* check the parameters */ /*----------------------------------------*/ void NOMAD::Parameters::check ( bool remove_history_file , - bool remove_solution_file , - bool remove_stats_file ) -{ - if ( !_to_be_checked ) - return; - - int i; - - /*--------------------------------------------------*/ - /* display degree and NOMAD::Point::display_limit */ - /*--------------------------------------------------*/ - { - + bool remove_solution_file , + bool remove_stats_file ) +{ + if ( !_to_be_checked ) + return; + + int i; + + /*--------------------------------------------------*/ + /* display degree and NOMAD::Point::display_limit */ + /*--------------------------------------------------*/ + { + #ifdef USE_MPI - if ( !NOMAD::Slave::is_master() ) - _out.set_degrees ( NOMAD::NO_DISPLAY ); + if ( !NOMAD::Slave::is_master() ) + _out.set_degrees ( NOMAD::NO_DISPLAY ); #endif - + #ifdef DEBUG #ifdef USE_MPI - if ( NOMAD::Slave::is_master() ) + if ( NOMAD::Slave::is_master() ) +#endif + _out.set_degrees ( NOMAD::FULL_DISPLAY ); #endif - _out.set_degrees ( NOMAD::FULL_DISPLAY ); + + if ( _out.get_gen_dd() == NOMAD::FULL_DISPLAY ) + set_POINT_DISPLAY_LIMIT ( -1 ); + } + + /*----------------------------*/ + /* DIMENSION */ + /*----------------------------*/ + if ( _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DIMENSION" ); + if ( _dimension > NOMAD::MAX_DIMENSION ) + { + std::ostringstream oss; + oss << "invalid parameter: DIMENSION (must be <= " + << NOMAD::MAX_DIMENSION << ")"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , oss.str() ); + } + + /*----------------------------*/ + /* BB_INPUT_TYPE */ + /*----------------------------*/ + if ( static_cast<int>(_bb_input_type.size()) != _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_TYPE" ); + + + /*----------------------------*/ + /* BOUNDS */ + /*----------------------------*/ + { + if ( _lb.size() > _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: LOWER_BOUND" ); + if ( _lb.size() < _dimension ) + _lb.resize ( _dimension ); + + if ( _ub.size() > _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: UPPER_BOUND" ); + if ( _ub.size() < _dimension ) + _ub.resize ( _dimension ); + + for ( i = 0 ; i < _dimension ; ++i ) + { + if ( _lb[i].is_defined() && _ub[i].is_defined() ) + { + if ( _lb[i] > _ub[i] ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: LOWER_BOUND or UPPER_BOUND" ); + if ( _lb[i] == _ub[i] ) + set_FIXED_VARIABLE ( i , _lb[i] ); + + } + // Check that x0s are within bounds when defined + if(_lb[i].is_defined()) + { + std::vector<NOMAD::Point *>::iterator it; + for(it=_x0s.begin();it<_x0s.end();it++) + { + // Compare values only if dimension is the same + if ( (*it)->size()==_lb.size() && (**it)[i] < _lb[i] ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: x0 < LOWER_BOUND " ); + } + } + if(_ub[i].is_defined()) + { + std::vector<NOMAD::Point *>::iterator it; + for(it=_x0s.begin();it<_x0s.end();it++) + { + // Compare values only if dimension is the same + if ( (*it)->size()==_ub.size() && (**it)[i] > _ub[i] ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: x0 > UPPER_BOUND " ); + } + } + // integer, binary, and categorical variables: + if ( _bb_input_type[i] != NOMAD::CONTINUOUS ) + { + + // binary variables: + if ( _bb_input_type[i] == NOMAD::BINARY ) + { + _lb[i] = 0.0; + _ub[i] = 1.0; + } + // integer and categorical variables: + else + { + if ( _lb[i].is_defined() ) + _lb[i] = ceil(_lb[i].value()); + if ( _ub[i].is_defined() ) + _ub[i] = floor(_ub[i].value()); + } + } + } + } + + + /*----------------------------*/ + /* FIXED_VARIABLES */ + /*----------------------------*/ + if ( _fixed_variables.size() > _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: FIXED_VARIABLE" ); + + if ( _fixed_variables.size() < _dimension ) + _fixed_variables.resize ( _dimension ); + + int nb_fixed = 0; + for ( i = 0; i < _dimension; ++i ) + if ( _fixed_variables[i].is_defined() ) + { + ++nb_fixed; + if ( (_lb[i].is_defined() && _fixed_variables[i] < _lb[i]) || + (_ub[i].is_defined() && _fixed_variables[i] > _ub[i]) || + ( (_bb_input_type[i] == NOMAD::INTEGER || + _bb_input_type[i] == NOMAD::CATEGORICAL ) + && !_fixed_variables[i].is_integer() ) || + ( _bb_input_type[i] == NOMAD::BINARY && !_fixed_variables[i].is_binary() ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: FIXED_VARIABLE" ); + } + + if ( nb_fixed == _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: FIXED_VARIABLE - all variables are fixed" ); + + _nb_free_variables = _dimension - nb_fixed; + + /*----------------------------*/ + /* Poll and Mesh */ + /*----------------------------*/ + { + + if ( _use_smesh && _anisotropic_mesh ) + { + _anisotropic_mesh=false; + if ( !_warning_has_been_displayed ) + _out << NOMAD::open_block("Warning:") + << "Anisotropic mesh is disabled when using smesh." << std::endl + << NOMAD::close_block(); + } + + + // mesh sizes: + if ( _initial_mesh_size.size() != _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_MESH_SIZE must have same dimension as problem" ); + + // poll sizes + if ( _initial_poll_size.size() != _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_POLL_SIZE must have same dimension as problem" ); + + if ( _initial_mesh_size.is_defined() && _initial_poll_size.is_defined() ) + { + if ( !_warning_has_been_displayed ) + _out << NOMAD::open_block("Warning:") + << "Initial mesh size and initial poll size are provided. Only the initial poll size will be considered." << std::endl + << NOMAD::close_block(); + _initial_mesh_size.clear(); + _initial_mesh_size.reset ( _dimension ); + } + + + // initial mesh size or poll size: + // -------------------------------- + bool use_x0 = !_x0s.empty() && _x0s[0]->size() == _dimension; + for ( i = 0 ; i < _dimension ; ++i ) + { + + // continuous variables: + // --------------------- + if ( _bb_input_type[i] == NOMAD::CONTINUOUS ) + { + + // Determine _initial_mesh_size from _initial_poll_size (this will disappear in future version) + if ( _initial_mesh_size[i].is_defined() ) + _initial_poll_size[i]=_initial_mesh_size[i]*pow(_dimension,0.5); + + // default value for initial mesh size + if ( !_initial_poll_size[i].is_defined() ) + { + + if (_lb[i].is_defined() && _ub[i].is_defined()) + { + set_INITIAL_POLL_SIZE ( i , 0.1 , true ); + if ( _lb[i] == _ub[i] ) + set_INITIAL_POLL_SIZE (i, 1 ,false); + + } + else if ( _lb[i].is_defined() && use_x0 && (*_x0s[0])[i].is_defined() && _lb[i]!=(*_x0s[0])[i]) + { + _initial_poll_size[i] = ((*_x0s[0])[i]-_lb[i])/10.0; // Case x0 < lb tested elsewhere + } + else if ( _ub[i].is_defined()&& use_x0 && (*_x0s[0])[i].is_defined() && _ub[i]!=(*_x0s[0])[i]) + { + _initial_poll_size[i] = (_ub[i]-(*_x0s[0])[i])/10.0; // Case x0 > ub tested elsewhere + } + else + { + if ( use_x0 && (*_x0s[0])[i].is_defined() && (*_x0s[0])[i].abs() > NOMAD::Double::get_epsilon()*10.0 ) + _initial_poll_size[i] = (*_x0s[0])[i].abs()/10.0; + else + { + _initial_poll_size[i] = 1.0; + + if (_out.get_gen_dd()>=NOMAD::NORMAL_DISPLAY && !_warning_has_been_displayed) + _out << NOMAD::open_block("Warning:") + << "Initial mesh size for variable " << i << " has been arbitrarily fixed to 1." << std::endl + << " In the absence of bounds and initial values different than zero," << std::endl + << " it is recommended to explicitely provide this parameter." << std::endl + << NOMAD::close_block(); + } + } + } + else if ( !_fixed_variables[i].is_defined() && + ( _initial_poll_size[i].value() < NOMAD::Double::get_epsilon() || + _initial_poll_size[i].value() <= 0.0 ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_MESH_SIZE" ); + } + // binary/categorical variables: + // ----------------------------- + else if ( _bb_input_type[i] == NOMAD::BINARY || + _bb_input_type[i] == NOMAD::CATEGORICAL ) + { + // mesh and poll sizes not used for binary and categorical + // but set to prevent warning when creating signature + _initial_mesh_size[i] = 1.0; + _initial_poll_size[i] = 1.0; + } + // integer variables: + // ------------------ + else + { + // Determine mesh size from poll size + if ( _initial_poll_size[i].is_defined() ) + _initial_mesh_size[i]=_initial_poll_size[i]*pow(_dimension,-0.5); + + + if ( _initial_mesh_size[i].is_defined() ) + { + _initial_mesh_size[i]=_initial_mesh_size[i].round(); + if ( _initial_mesh_size[i] < 1.0 ) + _initial_mesh_size[i] = 1.0; + + } + else // that is no initial_mesh_size and no initial_poll_size + { + + // default value for initial mesh size + // (r0.1 if there are bounds + rounding to nearest integer not zero, 1.0 otherwise): + if ( !_lb[i].is_defined() || !_ub[i].is_defined() ) + _initial_mesh_size[i] = 1.0; + else + { + set_INITIAL_POLL_SIZE ( i , 0.1 , true ); + _initial_mesh_size[i]=_initial_poll_size[i]*pow(_dimension,-0.5); + _initial_mesh_size[i]=_initial_mesh_size[i].round(); + if ( _initial_mesh_size[i] < 1.0 ) + _initial_mesh_size[i] = 1.0; + + } + } + _initial_poll_size[i]=_initial_mesh_size[i]*pow(_dimension,0.5); + + } + // Determine _initial_mesh_size from _initial_poll_size (this will disappear in future version) + if ( !_initial_mesh_size[i].is_defined() ) + _initial_mesh_size[i]=_initial_poll_size[i]*pow(_dimension,-0.5); + + } + + // min mesh size \delta_min: + if ( _min_mesh_size.is_defined() ) + { + + if ( _min_mesh_size.size() != _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_MESH_SIZE" ); + + for ( i = 0 ; i < _dimension ; ++i ) + if ( _min_mesh_size[i].is_defined() && + (_min_mesh_size[i].value() < NOMAD::Double::get_epsilon() || + _min_mesh_size[i].value() <= 0.0 ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameters: MIN_MESH_SIZE" ); + } + + // min poll size \Delta^p_min: + if ( _min_poll_size.is_defined() ) + { + + _min_poll_size_defined = true; + + if ( _min_poll_size.size() != _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_POLL_SIZE" ); + + for ( i = 0 ; i < _dimension ; ++i ) + { + // continuous variables: + if ( _bb_input_type[i] == NOMAD::CONTINUOUS ) + { + if ( _min_poll_size[i].is_defined() && + (_min_poll_size[i].value() < NOMAD::Double::get_epsilon() || + _min_poll_size[i].value() <= 0.0 ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameters: MIN_POLL_SIZE" ); + } + + // integer and binary variables: + else if ( _bb_input_type[i] != NOMAD::CATEGORICAL ) + { + if ( _min_poll_size[i].is_defined() ) + { + if ( _min_poll_size[i] < 1.0 ) + _min_poll_size[i] = 1.0; + } + else + _min_poll_size[i] = 1.0; + } + } + } + + // default min poll size for non-continuous variables: + else + { + + _min_poll_size_defined = false; + + _min_poll_size = NOMAD::Point ( _dimension ); + for ( i = 0 ; i < _dimension ; ++i ) + if ( _bb_input_type[i] == NOMAD::INTEGER ) + _min_poll_size[i] = 1.0; + } + + // default value for _mesh_update_basis (tau): + if ( _mesh_update_basis <= 1.0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameters: MESH_UPDATE_BASIS (must be >1)" ); + + if ( _poll_update_basis <= 1.0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameters: POLL_UPDATE_BASIS (must be >1)" ); + } + + + int nb_obj = static_cast<int>(_index_obj.size()); + + /*----------------------------*/ + /* DISPLAY_STATS */ + /*----------------------------*/ + if ( _display_stats.empty() ) + { + std::list<std::string> ls; + if ( nb_obj == 1 ) + { + ls.push_back ( NOMAD::Display::get_display_stats_keyword ( NOMAD::DS_BBE ) ); + ls.push_back ( std::string() ); + } + ls.push_back ( NOMAD::Display::get_display_stats_keyword ( NOMAD::DS_OBJ ) ); + set_DISPLAY_STATS ( ls ); + } + + else if ( !check_display_stats ( _display_stats ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DISPLAY_STATS" ); + + /*----------------------------*/ + /* STATS_FILE */ + /*----------------------------*/ + if ( !_stats_file_name.empty() ) + { + if ( _stats_file.empty() ) + { + std::list<std::string> ls; + ls.push_back ( NOMAD::Display::get_display_stats_keyword ( NOMAD::DS_BBE ) ); + ls.push_back ( std::string() ); + ls.push_back ( NOMAD::Display::get_display_stats_keyword ( NOMAD::DS_OBJ ) ); + set_STATS_FILE ( _stats_file_name , ls ); + } + else if ( !check_display_stats ( _stats_file ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: STATS_FILE" ); + } + + /*----------------------------*/ + /* SCALING */ + /*----------------------------*/ + if ( _scaling.size() > _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SCALING" ); + + if ( _scaling.size() < _dimension ) + _scaling.resize ( _dimension ); + + for ( i = 0; i < _dimension; ++i ) + if ( _scaling[i].is_defined() && _scaling[i] == 0.0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SCALING (zero value)" ); + + /*---------------------------*/ + /* blackbox outputs */ + /*---------------------------*/ + if ( _bb_output_type.empty() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_OUTPUT_TYPE" ); + if ( _bb_output_type.empty() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_OUTPUT_TYPE - undefined" ); + + size_t m = _bb_output_type.size(); + + if ( !_bb_exe.empty() && m != _bb_exe.size() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_EXE: wrong number of blackbox executable names" ); + + // surrogate: + if ( !_sgte_exe.empty() ) + { + + _has_sgte = true; + + if ( _bb_exe.empty() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_EXE - no BB_EXE is defined" ); + + std::map<std::string,std::string>::const_iterator it; + std::map<std::string,std::string>::const_iterator end = _sgte_exe.end(); + std::list<std::string>::const_iterator bb_exe_begin = _bb_exe.begin(); + std::list<std::string>::const_iterator bb_exe_end = _bb_exe.end(); + + // an empty string in _sgte_exe means that there is a unique + // blackbox with the associated surrogate + // (SGTE_EXE parameter with only one argument): + it = _sgte_exe.find(""); + if ( it != end ) { + if ( _sgte_exe.size() != 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_EXE - impossible to interpret with one argument" ); + + std::string bb_exe_name = *bb_exe_begin; + std::list<std::string>::const_iterator it2 = ++bb_exe_begin; + while ( it2 != bb_exe_end ) { + if ( *it2 != bb_exe_name ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: unique SGTE_EXE without unique blackbox executable" ); + ++it2; + } + + std::string sgte_name = it->second; + + _sgte_exe.clear(); + _sgte_exe[bb_exe_name] = sgte_name; + } + else + for ( it = _sgte_exe.begin() ; it != end ; ++it ) + if ( find ( bb_exe_begin , bb_exe_end , it->first ) == bb_exe_end ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_EXE" ); + } + else if ( !_has_sgte ) + { + _sgte_eval_sort = false; + _sgte_cost = -1; + + if ( _opt_only_sgte ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: OPT_ONLY_SGTE" ); + } + + if ( _opt_only_sgte ) + _sgte_eval_sort = false; + + size_t k; + + // CNT_EVAL, _STAT_SUM_ and _STAT_AVG_ checks (each one have to be unique): + _index_cnt_eval = _index_stat_sum = _index_stat_avg = -1; + for ( k = 0 ; k < m ; ++k ) + { + if ( _bb_output_type[k] == NOMAD::STAT_SUM ) + { + if ( _index_stat_sum >= 0 ) + { + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_EXE: more than one STAT_SUM output" ); + } + _index_stat_sum = static_cast<int>(k); + } + else if ( _bb_output_type[k] == NOMAD::STAT_AVG ) + { + if ( _index_stat_avg >= 0 ) + { + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_EXE: more than one STAT_AVG output" ); + } + _index_stat_avg = static_cast<int>(k); + } + else if ( _bb_output_type[k] == NOMAD::CNT_EVAL ) + { + if ( _index_cnt_eval >= 0 ) + { + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_EXE: more than one CNT_EVAL output" ); + } + _index_cnt_eval = static_cast<int>(k); + } + } + + // F_TARGET: + if ( _f_target.is_defined() && nb_obj != _f_target.size() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: F_TARGET of bad dimension" ); + + /*----------------------------*/ + /* directions */ + /*----------------------------*/ + bool use_ortho_mads = false; + + { + bool use_mads = false; + bool use_ortho_mads_only = true; + std::set<NOMAD::direction_type>::const_iterator it , end = _direction_types.end(); + + // default value for primary poll directions: + if ( _direction_types.empty() ) + { + set_DIRECTION_TYPE ( NOMAD::ORTHO_NP1_QUAD ); // Default setting that maybe changed if models are disabled + use_mads = true; + use_ortho_mads = true; + use_ortho_mads_only = true; // OrthoMads (2n or n+1) not mixed with LT or GPS + } + else + for ( it = _direction_types.begin() ; it != end ; ++it ) + { + if ( NOMAD::dir_is_mads ( *it ) ) + use_mads = true; + if ( NOMAD::dir_is_orthomads ( *it ) ) + use_ortho_mads = true; + if ( ! NOMAD::dir_is_orthomads ( *it ) ) + use_ortho_mads_only = false; + + } + + if ( ! use_ortho_mads_only && _anisotropic_mesh ) + { + _anisotropic_mesh=false; + if ( !_warning_has_been_displayed ) + _out << NOMAD::open_block("Warning:") + << "Anisotropic mesh is disabled for direction types other than OrthoMads." << std::endl + << NOMAD::close_block(); + } + + + + + // default value for secondary poll directions: + if ( _barrier_type == NOMAD::PB || _barrier_type == NOMAD::PEB_P ) + { + + if ( _sec_poll_dir_types.empty() ) + { + if ( use_mads ) + { + if ( _direction_types.size() == 1 ) + { + NOMAD::direction_type dt = *(_direction_types.begin()); + if ( dt == NOMAD::ORTHO_1 || dt == NOMAD::ORTHO_2 ) + set_SEC_POLL_DIR_TYPE ( NOMAD::ORTHO_1 ); + else if ( dt == NOMAD::LT_1 || dt == NOMAD::LT_2 ) + set_SEC_POLL_DIR_TYPE ( NOMAD::LT_1 ); + else + set_SEC_POLL_DIR_TYPE ( (use_ortho_mads) ? NOMAD::ORTHO_2 : NOMAD::LT_2 ); + } + else + set_SEC_POLL_DIR_TYPE ( (use_ortho_mads) ? NOMAD::ORTHO_2 : NOMAD::LT_2 ); + } + else + set_SEC_POLL_DIR_TYPE ( NOMAD::GPS_NP1_STATIC ); + } + + else + { + bool old_uom = use_ortho_mads; + bool old_um = use_mads; + end = _sec_poll_dir_types.end(); + for ( it = _sec_poll_dir_types.begin() ; it != end ; ++it ) + { + if ( *it == NOMAD::NO_DIRECTION ) + { + _sec_poll_dir_types.clear(); + use_ortho_mads = old_uom; + use_mads = old_um; + break; + } + if ( NOMAD::dir_is_orthomads (*it) ) + use_ortho_mads = true; + if ( NOMAD::dir_is_mads ( *it ) ) + use_mads = true; + } + } + } + else + _sec_poll_dir_types.clear(); + + /*----------------------------*/ + /* SPECULATIVE_SEARCH */ + /*----------------------------*/ + if ( !use_mads ) + _speculative_search = false; + } + + /*----------------------------*/ + /* periodic variables */ + /*----------------------------*/ + if ( !_periodic_variables.empty() ) { + + // check the size: + if ( _dimension != static_cast<int>(_periodic_variables.size()) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: PERIODIC_VARIABLE - bad size" ); + + // check the bounds: + for ( int k = 0 ; k < _dimension ; ++k ) + if ( _periodic_variables[k] ) { + if ( !_lb[k].is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: PERIODIC_VARIABLE - lower bound not defined" ); + if ( !_ub[k].is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: PERIODIC_VARIABLE - upper bound not defined" ); + } + } + + + /*---------------------------*/ + /* model parameters */ + /*---------------------------*/ + { + + // disable models upon request + if ( _disable_models) + { + _model_params.search1 = _model_params.search2 = _model_params.eval_sort = NOMAD::NO_MODEL; + if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) + { + _out << NOMAD::open_block("Warning:") + << "Model use is forcefully disabled." << std::endl + << NOMAD::close_block(); + + if (has_direction_type(NOMAD::ORTHO_NP1_QUAD)) + { + _out << NOMAD::open_block("Warning:") + << "Model use is disabled for direction type. Direction types ORTHO N+1 QUAD are changed to ORTHO N+1 NEG." << std::endl + << NOMAD::close_block(); + } + } + set_DIRECTION_TYPE_NO_MODEL(); + + } + + // disable models when requested or for more than 50 variables, + // for categorical variables and for surrogate optimization: + bool has_categorical=false; + bool has_binary=false; + for ( i = 0 ; i < _dimension ; ++i ) + { + if ( !_fixed_variables[i].is_defined() && _bb_input_type[i] == NOMAD::CATEGORICAL ) + { + has_categorical=true; + } + if ( !_fixed_variables[i].is_defined() && _bb_input_type[i] == NOMAD::BINARY ) + { + has_binary=true; + } + } + + if ( _nb_free_variables >= 50 || has_categorical || _opt_only_sgte ) + { + _model_params.search1 = _model_params.search2 = _model_params.eval_sort = NOMAD::NO_MODEL; + set_DIRECTION_TYPE_NO_MODEL(); + + if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) + { + if ( _opt_only_sgte) + _out << NOMAD::open_block("Warning:") + << "Model use is disabled when setting the option OPT_ONLY_SGTE to yes." << std::endl; + if ( has_categorical) + _out << NOMAD::open_block("Warning:") + << "Model use is disabled for problem with categorical variables." << std::endl + << NOMAD::close_block(); + if ( _nb_free_variables >= 50) + _out << NOMAD::open_block("Warning:") + << "Model use is disabled for problem with dimension greater than 50." << std::endl + << NOMAD::close_block(); + } + } + + + // disable PEB constraints when categorical variables are present + if ( has_categorical && _barrier_type == NOMAD::PEB_P) + { + + change_PEB_to_PB(); + + if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) + _out << NOMAD::open_block("Warning:") + << "PEB constraints are disabled when using categorical variables. To continue, PEB constraints have been replaced by PB constraints." << std::endl + << NOMAD::close_block(); + + } + + if ( ( has_categorical || has_binary ) && _anisotropic_mesh ) + { + _anisotropic_mesh=false; + if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) + _out << NOMAD::open_block("Warning:") + << "Default anisotropic mesh is disabled with categorical and binary variables." << std::endl + << NOMAD::close_block(); + + } + + // disable model use in parallel mode: +#ifdef USE_MPI + _model_params.search1 = _model_params.search2 = _model_params.eval_sort = NOMAD::NO_MODEL; + set_DIRECTION_TYPE_NO_MODEL(); + if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) + _out << NOMAD::open_block("Warning:") + << "Model use is disabled in parallel mode (MPI)." << std::endl + << NOMAD::close_block(); + + + if ((has_direction_type(NOMAD::ORTHO_NP1_QUAD) || has_direction_type(NOMAD::ORTHO_NP1_NEG)) && _asynchronous) + { + set_ASYNCHRONOUS(false); + if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) + _out << NOMAD::open_block("Warning:") + << "Asynchronous mode is disabled in parallel mode (MPI) when dynamic directions (ortho n+1) are used." << std::endl + << NOMAD::close_block(); + } #endif - - if ( _out.get_gen_dd() == NOMAD::FULL_DISPLAY ) - set_POINT_DISPLAY_LIMIT ( -1 ); - } - - /*----------------------------*/ - /* DIMENSION */ - /*----------------------------*/ - if ( _dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DIMENSION" ); - if ( _dimension > NOMAD::MAX_DIMENSION ) - { - std::ostringstream oss; - oss << "invalid parameter: DIMENSION (must be <= " - << NOMAD::MAX_DIMENSION << ")"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , oss.str() ); - } - - /*----------------------------*/ - /* BB_INPUT_TYPE */ - /*----------------------------*/ - if ( static_cast<int>(_bb_input_type.size()) != _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_TYPE" ); - - /*----------------------------*/ - /* BOUNDS */ - /*----------------------------*/ - { - if ( _lb.size() > _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: LOWER_BOUND" ); - if ( _lb.size() < _dimension ) - _lb.resize ( _dimension ); - - if ( _ub.size() > _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: UPPER_BOUND" ); - if ( _ub.size() < _dimension ) - _ub.resize ( _dimension ); - - for ( i = 0 ; i < _dimension ; ++i ) - { - if ( _lb[i].is_defined() && _ub[i].is_defined() ) - { - if ( _lb[i] > _ub[i] ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: LOWER_BOUND or UPPER_BOUND" ); - if ( _lb[i] == _ub[i] ) - set_FIXED_VARIABLE ( i , _lb[i] ); - - } - // Check that x0s are within bounds when defined - if(_lb[i].is_defined()) - { - std::vector<NOMAD::Point *>::iterator it; - for(it=_x0s.begin();it<_x0s.end();it++) - { - // Compare values only if dimension is the same - if ( (*it)->size()==_lb.size() && (**it)[i] < _lb[i] ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: x0 < LOWER_BOUND " ); - } - } - if(_ub[i].is_defined()) - { - std::vector<NOMAD::Point *>::iterator it; - for(it=_x0s.begin();it<_x0s.end();it++) - { - // Compare values only if dimension is the same - if ( (*it)->size()==_ub.size() && (**it)[i] > _ub[i] ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: x0 > UPPER_BOUND " ); - } - } - // integer, binary, and categorical variables: - if ( _bb_input_type[i] != NOMAD::CONTINUOUS ) - { - - // binary variables: - if ( _bb_input_type[i] == NOMAD::BINARY ) - { - _lb[i] = 0.0; - _ub[i] = 1.0; - } - // integer and categorical variables: - else - { - if ( _lb[i].is_defined() ) - _lb[i] = ceil(_lb[i].value()); - if ( _ub[i].is_defined() ) - _ub[i] = floor(_ub[i].value()); - } - } - } - } - - - - /*----------------------------*/ - /* FIXED_VARIABLES */ - /*----------------------------*/ - if ( _fixed_variables.size() > _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: FIXED_VARIABLE" ); - - if ( _fixed_variables.size() < _dimension ) - _fixed_variables.resize ( _dimension ); - - int nb_fixed = 0; - for ( i = 0; i < _dimension; ++i ) - if ( _fixed_variables[i].is_defined() ) { - ++nb_fixed; - if ( (_lb[i].is_defined() && _fixed_variables[i] < _lb[i]) || - (_ub[i].is_defined() && _fixed_variables[i] > _ub[i]) || - ( (_bb_input_type[i] == NOMAD::INTEGER || - _bb_input_type[i] == NOMAD::CATEGORICAL ) - && !_fixed_variables[i].is_integer() ) || - ( _bb_input_type[i] == NOMAD::BINARY && !_fixed_variables[i].is_binary() ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: FIXED_VARIABLE" ); - } - - if ( nb_fixed == _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: FIXED_VARIABLE - all variables are fixed" ); - - _nb_free_variables = _dimension - nb_fixed; - - /*----------------------------*/ - /* Mesh */ - /*----------------------------*/ - { - // mesh sizes: - - - if ( _initial_mesh_size.size() != _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: INITIAL_MESH_SIZE must have same dimension as problem" ); - - // initial mesh size: - // ------------------ - bool use_x0 = !_x0s.empty() && _x0s[0]->size() == _dimension; - - for ( i = 0 ; i < _dimension ; ++i ) - { - - // continuous variables: - // --------------------- - if ( _bb_input_type[i] == NOMAD::CONTINUOUS ) - { - // default value for initial mesh size - if ( !_initial_mesh_size[i].is_defined() ) - { - - if (_lb[i].is_defined() && _ub[i].is_defined()) - set_INITIAL_MESH_SIZE ( i , 0.1 , true ); - else if ( _lb[i].is_defined() && use_x0 && (*_x0s[0])[i].is_defined() && _lb[i]!=(*_x0s[0])[i]) - { - _initial_mesh_size[i] = (*_x0s[0])[i]-_lb[i]; // Case x0 < lb tested elsewhere - } - else if ( _ub[i].is_defined()&& use_x0 && (*_x0s[0])[i].is_defined() && _ub[i]!=(*_x0s[0])[i]) - { - _initial_mesh_size[i] = _ub[i]-(*_x0s[0])[i]; // Case x0 > ub tested elsewhere - } - else - { - if ( use_x0 && (*_x0s[0])[i].is_defined() && (*_x0s[0])[i].abs() > 1.0 ) - _initial_mesh_size[i] = (*_x0s[0])[i].abs(); - else - _initial_mesh_size[i] = 1.0; - - if (_initial_mesh_size[i] == 1.0 && _out.get_gen_dd()>=NOMAD::NORMAL_DISPLAY && !_warning_has_been_displayed) - _out << NOMAD::open_block("Warning:") - << "Initial mesh size for variable " << i << " has been arbitrarily fixed to 1." << std::endl - << " In the absence of bounds and initial values different than zero," << std::endl - << " it is recommended to explicitely provide this parameter." << std::endl - << NOMAD::close_block(); - } - } - - else if ( !_fixed_variables[i].is_defined() && - ( _initial_mesh_size[i].value() < NOMAD::Double::get_epsilon() || - _initial_mesh_size[i].value() <= 0.0 ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: INITIAL_MESH_SIZE" ); - } - - // binary/categorical variables: - // ----------------------------- - else if ( _bb_input_type[i] == NOMAD::BINARY || - _bb_input_type[i] == NOMAD::CATEGORICAL ) - { - _initial_mesh_size[i] = 1.0; - } - - // integer variables: - // ------------------ - else - { - - if ( _initial_mesh_size[i].is_defined() ) - { - _initial_mesh_size[i]=_initial_mesh_size[i].round(); - if ( _initial_mesh_size[i] < 1.0 ) - _initial_mesh_size[i] = 1.0; - } - else - { - - // default value for initial mesh size - // (r0.1 if there are bounds + rounding to nearest integer not zero, 1.0 otherwise): - if ( !_lb[i].is_defined() || !_ub[i].is_defined() ) - _initial_mesh_size[i] = 1.0; - else - { - set_INITIAL_MESH_SIZE ( i , 0.1 , true ); - _initial_mesh_size[i]=_initial_mesh_size[i].round(); - if ( _initial_mesh_size[i] < 1.0 ) - _initial_mesh_size[i] = 1.0; - } - } - } - } - - // min mesh size \Delta^m_min: - if ( _min_mesh_size.is_defined() ) - { - - if ( _min_mesh_size.size() != _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_MESH_SIZE" ); - - for ( i = 0 ; i < _dimension ; ++i ) - if ( _min_mesh_size[i].is_defined() && - (_min_mesh_size[i].value() < NOMAD::Double::get_epsilon() || - _min_mesh_size[i].value() <= 0.0 ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameters: MIN_MESH_SIZE" ); - } - - // min poll size \Delta^p_min: - if ( _min_poll_size.is_defined() ) - { - - _min_poll_size_defined = true; - - if ( _min_poll_size.size() != _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_POLL_SIZE" ); - - for ( i = 0 ; i < _dimension ; ++i ) - { - // continuous variables: - if ( _bb_input_type[i] == NOMAD::CONTINUOUS ) - { - if ( _min_poll_size[i].is_defined() && - (_min_poll_size[i].value() < NOMAD::Double::get_epsilon() || - _min_poll_size[i].value() <= 0.0 ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameters: MIN_POLL_SIZE" ); - } - - // integer and binary variables: - else if ( _bb_input_type[i] != NOMAD::CATEGORICAL ) - { - if ( _min_poll_size[i].is_defined() ) - { - if ( _min_poll_size[i] < 1.0 ) - _min_poll_size[i] = 1.0; - } - else - _min_poll_size[i] = 1.0; - } - } - } - - // default min poll size for non-continuous variables: - else - { - - _min_poll_size_defined = false; - - _min_poll_size = NOMAD::Point ( _dimension ); - for ( i = 0 ; i < _dimension ; ++i ) - if ( _bb_input_type[i] != NOMAD::CONTINUOUS && - _bb_input_type[i] != NOMAD::CATEGORICAL ) - _min_poll_size[i] = 1.0; - } - - // default value for _mesh_update_basis (tau): - if ( !_mesh_update_basis.is_defined() ) - _mesh_update_basis = 4.0; - else if ( _mesh_update_basis <= 0.0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameters: MESH_UPDATE_BASIS" ); - - // compare l0 and lmax: - if ( _max_mesh_index != NOMAD::UNDEFINED_L && _initial_mesh_index > _max_mesh_index ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameters: MAX_MESH_INDEX or INITIAL_MESH_INDEX" ); - } - - int nb_obj = static_cast<int>(_index_obj.size()); - - /*----------------------------*/ - /* DISPLAY_STATS */ - /*----------------------------*/ - if ( _display_stats.empty() ) { - std::list<std::string> ls; - if ( nb_obj == 1 ) { - ls.push_back ( NOMAD::Display::get_display_stats_keyword ( NOMAD::DS_BBE ) ); - ls.push_back ( std::string() ); - } - ls.push_back ( NOMAD::Display::get_display_stats_keyword ( NOMAD::DS_OBJ ) ); - set_DISPLAY_STATS ( ls ); - } - - else if ( !check_display_stats ( _display_stats ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DISPLAY_STATS" ); - - /*----------------------------*/ - /* STATS_FILE */ - /*----------------------------*/ - if ( !_stats_file_name.empty() ) { - if ( _stats_file.empty() ) { - std::list<std::string> ls; - ls.push_back ( NOMAD::Display::get_display_stats_keyword ( NOMAD::DS_BBE ) ); - ls.push_back ( std::string() ); - ls.push_back ( NOMAD::Display::get_display_stats_keyword ( NOMAD::DS_OBJ ) ); - set_STATS_FILE ( _stats_file_name , ls ); - } - else if ( !check_display_stats ( _stats_file ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: STATS_FILE" ); - } - - /*----------------------------*/ - /* SCALING */ - /*----------------------------*/ - if ( _scaling.size() > _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SCALING" ); - - if ( _scaling.size() < _dimension ) - _scaling.resize ( _dimension ); - - for ( i = 0; i < _dimension; ++i ) - if ( _scaling[i].is_defined() && _scaling[i] == 0.0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SCALING (zero value)" ); - - /*---------------------------*/ - /* blackbox outputs */ - /*---------------------------*/ - if ( _bb_output_type.empty() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_OUTPUT_TYPE" ); - if ( _bb_output_type.empty() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_OUTPUT_TYPE - undefined" ); - - size_t m = _bb_output_type.size(); - - if ( !_bb_exe.empty() && m != _bb_exe.size() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_EXE: wrong number of blackbox executable names" ); - - // surrogate: - if ( !_sgte_exe.empty() ) - { - - _has_sgte = true; - - if ( _bb_exe.empty() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_EXE - no BB_EXE is defined" ); - - std::map<std::string,std::string>::const_iterator it; - std::map<std::string,std::string>::const_iterator end = _sgte_exe.end(); - std::list<std::string>::const_iterator bb_exe_begin = _bb_exe.begin(); - std::list<std::string>::const_iterator bb_exe_end = _bb_exe.end(); - - // an empty string in _sgte_exe means that there is a unique - // blackbox with the associated surrogate - // (SGTE_EXE parameter with only one argument): - it = _sgte_exe.find(""); - if ( it != end ) { - if ( _sgte_exe.size() != 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_EXE - impossible to interpret with one argument" ); - - std::string bb_exe_name = *bb_exe_begin; - std::list<std::string>::const_iterator it2 = ++bb_exe_begin; - while ( it2 != bb_exe_end ) { - if ( *it2 != bb_exe_name ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: unique SGTE_EXE without unique blackbox executable" ); - ++it2; - } - - std::string sgte_name = it->second; - - _sgte_exe.clear(); - _sgte_exe[bb_exe_name] = sgte_name; - } - else - for ( it = _sgte_exe.begin() ; it != end ; ++it ) - if ( find ( bb_exe_begin , bb_exe_end , it->first ) == bb_exe_end ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_EXE" ); - } - else if ( !_has_sgte ) - { - _sgte_eval_sort = false; - _sgte_cost = -1; - - if ( _opt_only_sgte ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: OPT_ONLY_SGTE" ); - } - - if ( _opt_only_sgte ) - _sgte_eval_sort = false; - - size_t k; - - // _STAT_SUM_ and _STAT_AVG_ checks (each one have to be unique): - _index_stat_sum = _index_stat_avg = -1; - for ( k = 0 ; k < m ; ++k ) { - if ( _bb_output_type[k] == NOMAD::STAT_SUM ) { - if ( _index_stat_sum >= 0 ) { - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_EXE: more than one STAT_SUM output" ); - } - _index_stat_sum = static_cast<int>(k); - } - else if ( _bb_output_type[k] == NOMAD::STAT_AVG ) { - if ( _index_stat_avg >= 0 ) { - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_EXE: more than one STAT_AVG output" ); - } - _index_stat_avg = static_cast<int>(k); - } - else if ( _bb_output_type[k] == NOMAD::CNT_EVAL ) { - if ( _index_cnt_eval >= 0 ) { - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_EXE: more than one CNT_EVAL output" ); - } - _index_cnt_eval = static_cast<int>(k); - } - } - - // F_TARGET: - if ( _f_target.is_defined() && nb_obj != _f_target.size() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: F_TARGET of bad dimension" ); - - /*----------------------------*/ - /* directions */ - /*----------------------------*/ - bool use_ortho_mads = false; - - { - bool use_mads = false; - std::set<NOMAD::direction_type>::const_iterator it , end = _direction_types.end(); - - // default value for primary poll directions: - if ( _direction_types.empty() ) - { - set_DIRECTION_TYPE ( NOMAD::ORTHO_NP1_QUAD ); // Default setting that maybe changed if models are disabled - use_mads = true; - use_ortho_mads = true; - } - else - for ( it = _direction_types.begin() ; it != end ; ++it ) - { - if ( NOMAD::dir_is_mads ( *it ) ) - use_mads = true; - if ( NOMAD::dir_is_orthomads ( *it ) ) - use_ortho_mads = true; - } - - // default value for secondary poll directions: - if ( _barrier_type == NOMAD::PB || _barrier_type == NOMAD::PEB_P ) - { - - if ( _sec_poll_dir_types.empty() ) - { - if ( use_mads ) { - if ( _direction_types.size() == 1 ) - { - NOMAD::direction_type dt = *(_direction_types.begin()); - if ( dt == NOMAD::ORTHO_1 || dt == NOMAD::ORTHO_2 ) - set_SEC_POLL_DIR_TYPE ( NOMAD::ORTHO_1 ); - else if ( dt == NOMAD::LT_1 || dt == NOMAD::LT_2 ) - set_SEC_POLL_DIR_TYPE ( NOMAD::LT_1 ); - else - set_SEC_POLL_DIR_TYPE ( (use_ortho_mads) ? NOMAD::ORTHO_2 : NOMAD::LT_2 ); - } - else - set_SEC_POLL_DIR_TYPE ( (use_ortho_mads) ? NOMAD::ORTHO_2 : NOMAD::LT_2 ); - } - else - set_SEC_POLL_DIR_TYPE ( NOMAD::GPS_NP1_STATIC ); - } - - else { - bool old_uom = use_ortho_mads; - bool old_um = use_mads; - end = _sec_poll_dir_types.end(); - for ( it = _sec_poll_dir_types.begin() ; it != end ; ++it ) { - if ( *it == NOMAD::NO_DIRECTION ) { - _sec_poll_dir_types.clear(); - use_ortho_mads = old_uom; - use_mads = old_um; - break; - } - if ( NOMAD::dir_is_orthomads (*it) ) - use_ortho_mads = true; - if ( NOMAD::dir_is_mads ( *it ) ) - use_mads = true; - } - } - } - else - _sec_poll_dir_types.clear(); - - /*----------------------------*/ - /* SPECULATIVE_SEARCH */ - /*----------------------------*/ - if ( !use_mads ) - _speculative_search = false; - } - - /*----------------------------*/ - /* periodic variables */ - /*----------------------------*/ - if ( !_periodic_variables.empty() ) { - - // check the size: - if ( _dimension != static_cast<int>(_periodic_variables.size()) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: PERIODIC_VARIABLE - bad size" ); - - // check the bounds: - for ( int k = 0 ; k < _dimension ; ++k ) - if ( _periodic_variables[k] ) { - if ( !_lb[k].is_defined() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: PERIODIC_VARIABLE - lower bound not defined" ); - if ( !_ub[k].is_defined() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: PERIODIC_VARIABLE - upper bound not defined" ); - } - } - - - /*---------------------------*/ - /* model parameters */ - /*---------------------------*/ - { - - // disable models upon request - if ( _disable_models) - { - _model_params.search1 = _model_params.search2 = _model_params.eval_sort = NOMAD::NO_MODEL; - if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) - { - _out << NOMAD::open_block("Warning:") - << "Model use is forcefully disabled." << std::endl - << NOMAD::close_block(); - - if (has_direction_type(NOMAD::ORTHO_NP1_QUAD)) - { - _out << NOMAD::open_block("Warning:") - << "Model use is disabled for direction type. Direction types ORTHO N+1 QUAD are changed to ORTHO N+1 NEG." << std::endl - << NOMAD::close_block(); - } - } - set_DIRECTION_TYPE_NO_MODEL(); - - } - - // disable models when requested or for more than 50 variables, - // for categorical variables and for surrogate optimization: - bool has_categorical=false; - for ( i = 0 ; i < _dimension ; ++i ) - { - if ( !_fixed_variables[i].is_defined() && _bb_input_type[i] == NOMAD::CATEGORICAL ) - { - has_categorical=true; - break; - } - } - - if ( _nb_free_variables >= 50 || has_categorical || _opt_only_sgte ) - { - _model_params.search1 = _model_params.search2 = _model_params.eval_sort = NOMAD::NO_MODEL; - set_DIRECTION_TYPE_NO_MODEL(); - - if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) - { - if ( _opt_only_sgte) - _out << NOMAD::open_block("Warning:") - << "Model use is disabled when setting the option OPT_ONLY_SGTE to yes." << std::endl; - if ( has_categorical) - _out << NOMAD::open_block("Warning:") - << "Model use is disabled for problem with categorical variables." << std::endl - << NOMAD::close_block(); - if ( _nb_free_variables >= 50) - _out << NOMAD::open_block("Warning:") - << "Model use is disabled for problem with dimension greater than 50." << std::endl - << NOMAD::close_block(); - } - } - - // disable PEB constraints when categorical variables are present - if ( has_categorical && _barrier_type == NOMAD::PEB_P) - { - - change_PEB_to_PB(); - - if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) - _out << NOMAD::open_block("Warning:") - << "PEB constraints are disabled when using categorical variables. PEB constraints have been replaced by PB constraints." << std::endl - << NOMAD::close_block(); - - } - - - // disable model use in parallel mode: + + // other checks: + if ( ( _model_params.search1 == NOMAD::NO_MODEL && + _model_params.search2 != NOMAD::NO_MODEL ) || + ( _model_params.search1 != NOMAD::NO_MODEL && + _model_params.search1 == _model_params.search2 ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH (conflict with the two types of search)" ); + + if ( _model_params.quad_radius_factor <= 0.0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_RADIUS_FACTOR (must be > 0)" ); + + if ( _model_params.quad_min_Y_size < 0 ) + _model_params.quad_min_Y_size = -1; + else if ( _model_params.quad_min_Y_size < 2 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_QUAD_MIN_Y_SIZE (must be in {'N+1',-1,2,3,...})" ); + + if ( _model_params.model_np1_quad_epsilon <= 0.0 || _model_params.model_np1_quad_epsilon >= 1.0) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_NP1_QUAD_EPSILON (must be > 0 and < 1)" ); + + if ( _model_params.quad_max_Y_size <= _nb_free_variables ) + _model_params.quad_max_Y_size = _nb_free_variables + 1; + + if ( _model_params.search_max_trial_pts < 1 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH_MAX_TRIAL_PTS (must be >= 1)" ); + } + + /*----------------------------*/ + /* EVAL SORT */ + /*----------------------------*/ + if (_disable_eval_sort) + { + + _model_params.eval_sort = NOMAD::NO_MODEL; + _sgte_eval_sort = false; + NOMAD::Priority_Eval_Point::set_lexicographic_order(true); + if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) + _out << NOMAD::open_block("Warning:") + << "Eval sort is forcefully disabled (using models, surrogates, user eval priority, etc.). Only lexicographic order is used." << std::endl + << NOMAD::close_block(); + + } + else + NOMAD::Priority_Eval_Point::set_lexicographic_order(false); + + + /*----------------------------*/ + /* variable groups */ + /*----------------------------*/ + { + + // reset variable groups: + reset_variable_groups ( _var_groups ); + + std::vector<bool> in_group ( _dimension ); + for ( i = 0 ; i < _dimension ; ++i ) + in_group[i] = false; + + NOMAD::Variable_Group * vg; + std::set<NOMAD::direction_type> direction_types , sec_poll_dir_types; + + // 1. user groups: + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::const_iterator + end = _user_var_groups.end() , it; + + bool mod; + for ( it = _user_var_groups.begin() ; it != end ; ++it ) + { + + if ( !(*it)->check ( _fixed_variables , _bb_input_type , &in_group, mod ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VARIABLE_GROUP" ); + + direction_types = (*it)->get_direction_types(); + sec_poll_dir_types = (*it)->get_sec_poll_dir_types(); + + if ( direction_types.empty() ) + direction_types = _direction_types; + + if ( sec_poll_dir_types.empty() ) + sec_poll_dir_types = _sec_poll_dir_types; + + vg = new NOMAD::Variable_Group ( (*it)->get_var_indexes() , + direction_types , + sec_poll_dir_types , + _out ); + + _var_groups.insert ( vg ); + } + + + // 2. 'automatic' groups for other variables: + std::set<int> vi_cbi; // list of cont./bin./int. variables + std::set<int> vi_cat; // list of categorical variables + + for ( i = 0 ; i < _dimension ; ++i ) + { + if ( !in_group[i] && !_fixed_variables[i].is_defined() ) { + if ( _bb_input_type[i] != NOMAD::CATEGORICAL ) + vi_cbi.insert(i); + else + vi_cat.insert(i); + } + } + + // creation of a group for cont./bin./int. variables: + if ( !vi_cbi.empty() ) + { + vg = new NOMAD::Variable_Group ( vi_cbi , + _direction_types , + _sec_poll_dir_types , + _out ); + + _var_groups.insert ( vg ); + } + + // creation of a group for categorical variables: + if ( !vi_cat.empty() ) + { + vg = new NOMAD::Variable_Group ( vi_cat , + _direction_types , + _sec_poll_dir_types , + _out ); + _var_groups.insert ( vg ); + } + } + + /*----------------------------*/ + /* TMP_DIR */ + /*----------------------------*/ + { + if ( _tmp_dir.empty() ) + _tmp_dir = _problem_dir; + + // check the directory: + if ( !_tmp_dir.empty() && !NOMAD::check_read_file ( _tmp_dir ) ) + { + std::string err = "invalid parameter: TMP_DIR: cannot access \'" + _tmp_dir + "\'"; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + } + + /*------------------------------------------------------*/ + /* SOLUTION_FILE, HISTORY_FILE and STATS_FILE */ + /* (depending on the value of ADD_SEED_TO_FILE_NAMES, */ + /* the seed is added the file names) */ + /*------------------------------------------------------*/ + if ( _add_seed_to_file_names ) + { + + std::string s_seed = NOMAD::itos(_seed); + int n_seed = static_cast<int>(s_seed.size()); + + add_seed_to_file_name ( n_seed , s_seed , _solution_file ); + add_seed_to_file_name ( n_seed , s_seed , _history_file ); + add_seed_to_file_name ( n_seed , s_seed , _stats_file_name ); + } + + // remove old history, solution, and stats files: + std::string old_file; + if ( remove_history_file && !_history_file.empty() ) + { + old_file = _problem_dir + _history_file; + remove ( old_file.c_str() ); + } + if ( remove_stats_file && !_stats_file_name.empty() ) + { + old_file = _problem_dir + _stats_file_name; + remove ( old_file.c_str() ); + } + if ( remove_solution_file && !_solution_file.empty() ) + { + old_file = _problem_dir + _solution_file; + remove ( old_file.c_str() ); + } + + /*----------------------------*/ + /* opportunistic strategy */ + /*----------------------------*/ + if ( !_opportunistic_eval ) + { + _model_params.eval_sort = NOMAD::NO_MODEL; + _sgte_eval_sort = false; + _opportunistic_lucky_eval = false; + _opportunistic_min_nb_success = -1; + _opportunistic_min_eval = -1; + _opportunistic_min_f_imprvmt.clear(); + } + + // opportunistic default strategy for LH search: + // single-objective: the default is taken the same as OPPORTUNISTIC_EVAL + // multi-objective : the default is 'no' + if ( !_opp_LH_is_defined ) + _opportunistic_LH = ( nb_obj > 1 ) ? false : _opportunistic_eval; + + // opportunistic default strategy for cache search + // (the same as OPPORTUNISTIC_EVAL): + if ( !_opp_CS_is_defined ) + _opportunistic_cache_search = false; + + if (_bb_max_block_size<=0) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Parameters::check(): invalid block size for list evaluation (>0)" ); + + if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed && _bb_max_block_size > 1 && (_max_bb_eval>0 || _max_sim_bb_eval>0 || _max_eval>0)) + _out << NOMAD::open_block("Warning:") + << "The maximum number of evaluations may be exceeded when BB_MAX_BLOCK_SIZE>1." << std::endl + << NOMAD::close_block(); + + #ifdef USE_MPI - _model_params.search1 = _model_params.search2 = _model_params.eval_sort = NOMAD::NO_MODEL; - set_DIRECTION_TYPE_NO_MODEL(); - if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) - _out << NOMAD::open_block("Warning:") - << "Model use is disabled in parallel mode." << std::endl - << NOMAD::close_block(); - - - if ((has_direction_type(NOMAD::ORTHO_NP1_QUAD) || has_direction_type(NOMAD::ORTHO_NP1_NEG)) && _asynchronous) - { - set_ASYNCHRONOUS(false); - if (_out.get_gen_dd()>NOMAD::MINIMAL_DISPLAY && !_warning_has_been_displayed) - _out << NOMAD::open_block("Warning:") - << "Asynchronous mode is disabled in parallel mode when dynamic directions (ortho n+1) are used." << std::endl - << NOMAD::close_block(); - } + if (_bb_max_block_size >1) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Parameters::check(): List evaluation by block of size > 1 are not allowed when using MPI." ); #endif - - // other checks: - if ( ( _model_params.search1 == NOMAD::NO_MODEL && - _model_params.search2 != NOMAD::NO_MODEL ) || - ( _model_params.search1 != NOMAD::NO_MODEL && - _model_params.search1 == _model_params.search2 ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH (conflict with the two types of search)" ); - - if ( _model_params.quad_radius_factor <= 0.0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_RADIUS_FACTOR (must be > 0)" ); - - if ( _model_params.quad_min_Y_size < 0 ) - _model_params.quad_min_Y_size = -1; - else if ( _model_params.quad_min_Y_size < 2 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_QUAD_MIN_Y_SIZE (must be in {'N+1',-1,2,3,...})" ); - - if ( _model_params.model_np1_quad_epsilon <= 0.0 || _model_params.model_np1_quad_epsilon >= 1.0) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_NP1_QUAD_EPSILON (must be > 0 and < 1)" ); - - if ( _model_params.quad_max_Y_size <= _nb_free_variables ) - _model_params.quad_max_Y_size = _nb_free_variables + 1; - - if ( _model_params.search_max_trial_pts < 1 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH_MAX_TRIAL_PTS (must be >= 1)" ); - } - - - /*----------------------------*/ - /* variable groups */ - /* (and Halton seed) */ - /*----------------------------*/ - { - - // reset variable groups: - reset_variable_groups ( _var_groups ); - - // Halton seed: - if ( _halton_seed < 0 ) { - int * primes = new int [_dimension]; - NOMAD::construct_primes ( _dimension , primes ); - _halton_seed = primes[_dimension-1]; - delete [] primes; - } - - int def_halton_seed = _halton_seed , halton_seed; - - std::vector<bool> in_group ( _dimension ); - for ( i = 0 ; i < _dimension ; ++i ) - in_group[i] = false; - - NOMAD::Variable_Group * vg; - std::set<NOMAD::direction_type> direction_types , sec_poll_dir_types; - - // 1. user groups: - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::const_iterator - end = _user_var_groups.end() , it; - - bool mod; - for ( it = _user_var_groups.begin() ; it != end ; ++it ) - { - - if ( !(*it)->check ( _fixed_variables , _bb_input_type , &in_group, mod ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VARIABLE_GROUP" ); - - halton_seed = (*it)->get_halton_seed(); - if ( use_ortho_mads && halton_seed < 0 ) - halton_seed = def_halton_seed++; - - direction_types = (*it)->get_direction_types(); - sec_poll_dir_types = (*it)->get_sec_poll_dir_types(); - - if ( direction_types.empty() ) - direction_types = _direction_types; - - if ( sec_poll_dir_types.empty() ) - sec_poll_dir_types = _sec_poll_dir_types; - - vg = new NOMAD::Variable_Group ( (*it)->get_var_indexes() , - direction_types , - sec_poll_dir_types , - halton_seed , - _out ); - - _var_groups.insert ( vg ); - } - - - // 2. 'automatic' groups for other variables: - std::set<int> vi_cbi; // list of cont./bin./int. variables - std::set<int> vi_cat; // list of categorical variables - - for ( i = 0 ; i < _dimension ; ++i ) - { - if ( !in_group[i] && !_fixed_variables[i].is_defined() ) { - if ( _bb_input_type[i] != NOMAD::CATEGORICAL ) - vi_cbi.insert(i); - else - vi_cat.insert(i); - } - } - - // creation of a group for cont./bin./int. variables: - if ( !vi_cbi.empty() ) - { - - halton_seed = -1; - if ( use_ortho_mads ) - halton_seed = def_halton_seed++; - - vg = new NOMAD::Variable_Group ( vi_cbi , - _direction_types , - _sec_poll_dir_types , - halton_seed , - _out ); - - _var_groups.insert ( vg ); - } - - // creation of a group for categorical variables: - if ( !vi_cat.empty() ) - { - vg = new NOMAD::Variable_Group ( vi_cat , - _direction_types , - _sec_poll_dir_types , - -1 , // no use of Halton seed - _out ); - _var_groups.insert ( vg ); - } - } - - /*----------------------------*/ - /* TMP_DIR */ - /*----------------------------*/ - { - if ( _tmp_dir.empty() ) - _tmp_dir = _problem_dir; - - // check the directory: - if ( !_tmp_dir.empty() && !NOMAD::check_read_file ( _tmp_dir ) ) - { - std::string err = "invalid parameter: TMP_DIR: cannot access \'" + _tmp_dir + "\'"; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - } - - /*------------------------------------------------------*/ - /* SOLUTION_FILE, HISTORY_FILE and STATS_FILE */ - /* (depending on the value of ADD_SEED_TO_FILE_NAMES, */ - /* the seed is added the file names) */ - /*------------------------------------------------------*/ - if ( _add_seed_to_file_names ) - { - - std::string s_seed = NOMAD::itos(_seed); - int n_seed = static_cast<int>(s_seed.size()); - - add_seed_to_file_name ( n_seed , s_seed , _solution_file ); - add_seed_to_file_name ( n_seed , s_seed , _history_file ); - add_seed_to_file_name ( n_seed , s_seed , _stats_file_name ); - } - - // remove old history, solution, and stats files: - std::string old_file; - if ( remove_history_file && !_history_file.empty() ) - { - old_file = _problem_dir + _history_file; - remove ( old_file.c_str() ); - } - if ( remove_stats_file && !_stats_file_name.empty() ) - { - old_file = _problem_dir + _stats_file_name; - remove ( old_file.c_str() ); - } - if ( remove_solution_file && !_solution_file.empty() ) - { - old_file = _problem_dir + _solution_file; - remove ( old_file.c_str() ); - } - - /*----------------------------*/ - /* opportunistic strategy */ - /*----------------------------*/ - if ( !_opportunistic_eval ) - { - _model_params.eval_sort = NOMAD::NO_MODEL; - _sgte_eval_sort = false; - _opportunistic_lucky_eval = false; - _opportunistic_min_nb_success = -1; - _opportunistic_min_eval = -1; - _opportunistic_min_f_imprvmt.clear(); - } - - // opportunistic default strategy for LH search: - // single-objective: the default is taken the same as OPPORTUNISTIC_EVAL - // multi-objective : the default is 'no' - if ( !_opp_LH_is_defined ) - _opportunistic_LH = ( nb_obj > 1 ) ? false : _opportunistic_eval; - - // opportunistic default strategy for cache search - // (the same as OPPORTUNISTIC_EVAL): - if ( !_opp_CS_is_defined ) - _opportunistic_cache_search = false; - - /*----------------------------*/ - /* MULTI-MADS */ - /*----------------------------*/ - if ( nb_obj > 1 ) - { - - if ( _multi_formulation == NOMAD::UNDEFINED_FORMULATION ) - _multi_formulation = ( _VNS_search ) ? NOMAD::DIST_L2 : NOMAD::PRODUCT; - - if ( _multi_nb_mads_runs < 0 ) - { - - if ( _multi_overall_bb_eval < 0 ) - { - _multi_nb_mads_runs = 30; - if ( !_max_bbe_decided ) - { - _max_bb_eval = 25 * _nb_free_variables; - - if ( _LH_search_p0 < 0 ) - _LH_search_p0 = _max_bb_eval; - } - } - else if ( !_max_bbe_decided ) - { - _max_bb_eval = static_cast<int> - ( ceil ( sqrt ( 1.0 * _nb_free_variables * _multi_overall_bb_eval ) ) ); - - if ( _LH_search_p0 < 0 ) - _LH_search_p0 = _max_bb_eval; - } - } - else if ( _multi_overall_bb_eval > 0 && !_max_bbe_decided ) - { - _max_bb_eval = _multi_overall_bb_eval / _multi_nb_mads_runs; - if ( _multi_nb_mads_runs * _max_bb_eval < _multi_overall_bb_eval ) - ++_max_bb_eval; - } - } - - /*----------------------------------*/ - /* signature (standard or extern) */ - /*----------------------------------*/ - NOMAD::Signature * new_s = new NOMAD::Signature ( _dimension , - _bb_input_type , - _initial_mesh_size , - _min_mesh_size , - _min_poll_size , - _lb , - _ub , - _scaling , - _fixed_variables , - _periodic_variables , - _var_groups ); - // extern signature: - if ( _extern_signature ) - { - - bool fail = ( *new_s != *_extern_signature ); - delete new_s; - if ( fail ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "Parameters::check(): incompatible extern signature" ); - } - - // standard signature: - else - { - - if ( _std_signature ) - { - delete new_s; - - _std_signature->reset ( _dimension , - _bb_input_type , - _initial_mesh_size , - _min_mesh_size , - _min_poll_size , - _lb , - _ub , - _scaling , - _fixed_variables , - _periodic_variables , - _var_groups ); - } - else - { - _std_signature = new_s; - _std_signature->set_std(); - } - } - - bool has_categorical - = ( (_std_signature) ? _std_signature : _extern_signature )->has_categorical(); - - - /*----------------------------*/ - /* X0 */ - /*----------------------------*/ - { - if ( _x0s.empty() && _x0_cache_file.empty() ) { - if ( _LH_search_p0 <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "Parameters::check(): no starting point" ); - else if ( has_categorical ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "Parameters::check(): no starting point with categorical variables" ); - } - - size_t x0n = _x0s.size(); - for ( size_t k = 0 ; k < x0n ; ++k ) - if ( !_x0s[k]->is_complete() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: x0 with missing coordinates" ); - - // avoid _x0_cache_file == _sgte_cache_file : - if ( !_opt_only_sgte && - !_x0_cache_file.empty() && - !_sgte_cache_file.empty() && - _x0_cache_file == _sgte_cache_file ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: x0 and sgte cache file are the same" ); - } - - - /*----------------------*/ - - _to_be_checked = false; - _warning_has_been_displayed=true; + + /*----------------------------*/ + /* MULTI-MADS */ + /*----------------------------*/ + if ( nb_obj > 1 ) + { + + if ( _multi_formulation == NOMAD::UNDEFINED_FORMULATION ) + _multi_formulation = ( _VNS_search ) ? NOMAD::DIST_L2 : NOMAD::PRODUCT; + + if ( _multi_nb_mads_runs < 0 ) + { + + if ( _multi_overall_bb_eval < 0 ) + { + _multi_nb_mads_runs = 30; + if ( !_max_bbe_decided ) + { + _max_bb_eval = 25 * _nb_free_variables; + + if ( _LH_search_p0 < 0 ) + _LH_search_p0 = _max_bb_eval; + } + } + else if ( !_max_bbe_decided ) + { + _max_bb_eval = static_cast<int> + ( ceil ( sqrt ( 1.0 * _nb_free_variables * _multi_overall_bb_eval ) ) ); + + if ( _LH_search_p0 < 0 ) + _LH_search_p0 = _max_bb_eval; + } + } + else if ( _multi_overall_bb_eval > 0 && !_max_bbe_decided ) + { + _max_bb_eval = _multi_overall_bb_eval / _multi_nb_mads_runs; + if ( _multi_nb_mads_runs * _max_bb_eval < _multi_overall_bb_eval ) + ++_max_bb_eval; + } + } + + /*----------------------------------*/ + /* signature (standard or extern) */ + /*----------------------------------*/ + NOMAD::Signature * new_s = new NOMAD::Signature ( _dimension , + _bb_input_type , + _lb , + _ub , + _use_smesh , + _anisotropic_mesh , + _initial_poll_size, + _min_poll_size, + _min_mesh_size, + _mesh_update_basis, + _poll_update_basis, + _mesh_coarsening_exponent, + _mesh_refining_exponent, + _initial_mesh_index, + _scaling , + _fixed_variables , + _periodic_variables , + _var_groups ); + + // extern signature: + if ( _extern_signature ) + { + + bool fail = ( *new_s != *_extern_signature ); + delete new_s; + if ( fail ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Parameters::check(): incompatible extern signature" ); + } + + // standard signature: + else + { + if ( _std_signature ) + { + delete new_s; + + _std_signature->reset ( _dimension , + _bb_input_type , + _lb , + _ub , + _scaling , + _fixed_variables , + _periodic_variables , + _var_groups ); + } + else + { + _std_signature = new_s; + _std_signature->set_std(); + } + } + + bool has_categorical + = ( (_std_signature) ? _std_signature : _extern_signature )->has_categorical(); + + + /*----------------------------*/ + /* X0 */ + /*----------------------------*/ + { + if ( _x0s.empty() && _x0_cache_file.empty() ) { + if ( _LH_search_p0 <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Parameters::check(): no starting point" ); + else if ( has_categorical ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Parameters::check(): no starting point with categorical variables" ); + } + + size_t x0n = _x0s.size(); + for ( size_t k = 0 ; k < x0n ; ++k ) + { + if ( !_x0s[k]->is_complete() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: x0 with missing coordinates" ); + + // check that x0 is consistent with input type + for ( i = 0 ; i < _dimension ; ++i ) + { + const NOMAD::Double xi = (*_x0s[k])[i]; + if ( _bb_input_type[i] != NOMAD::CONTINUOUS && ! xi.is_integer() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: x0 with variables values inconistent with their type (integer, binary, categorical." ); + + } + + } + + + // avoid _x0_cache_file == _sgte_cache_file : + if ( !_opt_only_sgte && + !_x0_cache_file.empty() && + !_sgte_cache_file.empty() && + _x0_cache_file == _sgte_cache_file ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: x0 and sgte cache file are the same" ); + } + + + /*----------------------*/ + + _to_be_checked = false; + _warning_has_been_displayed=true; } /*-----------------------------------------------------------------*/ @@ -4530,27 +4747,27 @@ void NOMAD::Parameters::check ( bool remove_history_file , /* (static, private) */ /*-----------------------------------------------------------------*/ void NOMAD::Parameters::add_seed_to_file_name ( int n_seed , - const std::string & s_seed , - std::string & file_name ) -{ - int n_pn = static_cast<int>(file_name.size()); - - if ( n_pn == 0 ) - return; - - int k = static_cast<int>(file_name.find_last_of(".")); - std::string ext = ""; - std::string fic = file_name; - - if ( k >= 0 && k < n_pn ) { - fic = file_name.substr ( 0 , k ); - ext = file_name.substr ( k , n_pn-k ); - n_pn = k; - } - - if ( n_pn <= n_seed+1 || - fic.substr ( n_pn-n_seed , n_pn-1 ) != s_seed ) - file_name = fic + "." + s_seed + ext; + const std::string & s_seed , + std::string & file_name ) +{ + int n_pn = static_cast<int>(file_name.size()); + + if ( n_pn == 0 ) + return; + + int k = static_cast<int>(file_name.find_last_of(".")); + std::string ext = ""; + std::string fic = file_name; + + if ( k >= 0 && k < n_pn ) { + fic = file_name.substr ( 0 , k ); + ext = file_name.substr ( k , n_pn-k ); + n_pn = k; + } + + if ( n_pn <= n_seed+1 || + fic.substr ( n_pn-n_seed , n_pn-1 ) != s_seed ) + file_name = fic + "." + s_seed + ext; } /*----------------------------------------*/ @@ -4560,208 +4777,199 @@ void NOMAD::Parameters::add_seed_to_file_name ( int n_seed , // get_signature: NOMAD::Signature * NOMAD::Parameters::get_signature ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_signature(), Parameters::check() must be invoked" ); - if ( !_std_signature && !_extern_signature ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_signature(), no signature is set" ); - return (_std_signature) ? _std_signature : _extern_signature; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_signature(), Parameters::check() must be invoked" ); + if ( !_std_signature && !_extern_signature ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_signature(), no signature is set" ); + return (_std_signature) ? _std_signature : _extern_signature; } // get_dimension: int NOMAD::Parameters::get_dimension ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_dimension(), Parameters::check() must be invoked" ); - return _dimension; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_dimension(), Parameters::check() must be invoked" ); + return _dimension; } // get_nb_free_variables: int NOMAD::Parameters::get_nb_free_variables ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_nb_free_variables(), Parameters::check() must be invoked" ); - return _nb_free_variables; -} - -// get_halton_seed: -int NOMAD::Parameters::get_halton_seed ( void ) const -{ - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_halton_seed(), Parameters::check() must be invoked" ); - return _halton_seed; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_nb_free_variables(), Parameters::check() must be invoked" ); + return _nb_free_variables; } // get_add_seed_to_file_names: bool NOMAD::Parameters::get_add_seed_to_file_names ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_add_seed_to_file_names(), Parameters::check() must be invoked" ); - return _add_seed_to_file_names; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_add_seed_to_file_names(), Parameters::check() must be invoked" ); + return _add_seed_to_file_names; } // get_snap_to_bounds: bool NOMAD::Parameters::get_snap_to_bounds ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_snap_to_bounds(), Parameters::check() must be invoked" ); - return _snap_to_bounds; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_snap_to_bounds(), Parameters::check() must be invoked" ); + return _snap_to_bounds; } // get_speculative_search: bool NOMAD::Parameters::get_speculative_search ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_speculative_search(), Parameters::check() must be invoked" ); - return _speculative_search; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_speculative_search(), Parameters::check() must be invoked" ); + return _speculative_search; } // get_cache_search: bool NOMAD::Parameters::get_cache_search ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_cache_search(), Parameters::check() must be invoked" ); - return _cache_search; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_cache_search(), Parameters::check() must be invoked" ); + return _cache_search; } // access to all the models parameters: void NOMAD::Parameters::get_model_parameters ( NOMAD::model_params_type & mp ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_parameters(), Parameters::check() must be invoked" ); - mp = _model_params; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_parameters(), Parameters::check() must be invoked" ); + mp = _model_params; } // get_model_search: NOMAD::model_type NOMAD::Parameters::get_model_search ( int i ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_search(), Parameters::check() must be invoked" ); - - if ( i != 1 && i != 2 ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_search(i), i must be 1 or 2" ); - - return ( i == 1 ) ? _model_params.search1 : _model_params.search2; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_search(), Parameters::check() must be invoked" ); + + if ( i != 1 && i != 2 ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_search(i), i must be 1 or 2" ); + + return ( i == 1 ) ? _model_params.search1 : _model_params.search2; } // has_model_search: bool NOMAD::Parameters::has_model_search ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::has_model_search(), Parameters::check() must be invoked" ); - return _model_params.search1 != NOMAD::NO_MODEL; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::has_model_search(), Parameters::check() must be invoked" ); + return _model_params.search1 != NOMAD::NO_MODEL; } // get_model_search_optimistic: bool NOMAD::Parameters::get_model_search_optimistic ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_search_optimistic(), Parameters::check() must be invoked" ); - return _model_params.search_optimistic; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_search_optimistic(), Parameters::check() must be invoked" ); + return _model_params.search_optimistic; } // get_model_search_proj_to_mesh: bool NOMAD::Parameters::get_model_search_proj_to_mesh ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_search_proj_to_mesh(), Parameters::check() must be invoked" ); - return _model_params.search_proj_to_mesh; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_search_proj_to_mesh(), Parameters::check() must be invoked" ); + return _model_params.search_proj_to_mesh; } // get_model_quad_radius_factor: const NOMAD::Double & NOMAD::Parameters::get_model_quad_radius_factor ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_quad_radius_factor(), Parameters::check() must be invoked" ); - return _model_params.quad_radius_factor; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_quad_radius_factor(), Parameters::check() must be invoked" ); + return _model_params.quad_radius_factor; } // get_model_quad_use_WP: bool NOMAD::Parameters::get_model_quad_use_WP ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_quad_use_WP(), Parameters::check() must be invoked" ); - return _model_params.quad_use_WP; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_quad_use_WP(), Parameters::check() must be invoked" ); + return _model_params.quad_use_WP; } // get_model_quad_max_Y_size: int NOMAD::Parameters::get_model_quad_max_Y_size ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_quad_max_Y_size(), Parameters::check() must be invoked" ); - return _model_params.quad_max_Y_size; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_quad_max_Y_size(), Parameters::check() must be invoked" ); + return _model_params.quad_max_Y_size; } // get_model_np1_quad_epsilon: const NOMAD::Double & NOMAD::Parameters::get_model_np1_quad_epsilon ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_np1_quad_epsilon(), Parameters::check() must be invoked" ); - return _model_params.model_np1_quad_epsilon; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_np1_quad_epsilon(), Parameters::check() must be invoked" ); + return _model_params.model_np1_quad_epsilon; } // get_model_quad_min_Y_size: int NOMAD::Parameters::get_model_quad_min_Y_size ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_quad_min_Y_size(), Parameters::check() must be invoked" ); - return _model_params.quad_min_Y_size; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_quad_min_Y_size(), Parameters::check() must be invoked" ); + return _model_params.quad_min_Y_size; } // get_model_tgp_mode: NOMAD::TGP_mode_type NOMAD::Parameters::get_model_tgp_mode ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_tgp_mode(), Parameters::check() must be invoked" ); - return _model_params.tgp_mode; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_tgp_mode(), Parameters::check() must be invoked" ); + return _model_params.tgp_mode; } // get_model_tgp_reuse_model: bool NOMAD::Parameters::get_model_tgp_reuse_model ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_tgp_reuse_model(), Parameters::check() must be invoked" ); - return _model_params.tgp_reuse_model; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_tgp_reuse_model(), Parameters::check() must be invoked" ); + return _model_params.tgp_reuse_model; } // get_model_search_max_trial_pts: int NOMAD::Parameters::get_model_search_max_trial_pts ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_search_max_trial_pts(), Parameters::check() must be invoked" ); - return _model_params.search_max_trial_pts; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_search_max_trial_pts(), Parameters::check() must be invoked" ); + return _model_params.search_max_trial_pts; } // get_model_eval_sort: NOMAD::model_type NOMAD::Parameters::get_model_eval_sort ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_eval_sort(), Parameters::check() must be invoked" ); - return _model_params.eval_sort; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_eval_sort(), Parameters::check() must be invoked" ); + return _model_params.eval_sort; } @@ -4769,939 +4977,977 @@ NOMAD::model_type NOMAD::Parameters::get_model_eval_sort ( void ) const // get_model_eval_sort_cautious: bool NOMAD::Parameters::get_model_eval_sort_cautious ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_model_eval_sort_cautious(), Parameters::check() must be invoked" ); - return _model_params.eval_sort_cautious; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_model_eval_sort_cautious(), Parameters::check() must be invoked" ); + return _model_params.eval_sort_cautious; } // get_VNS_search: bool NOMAD::Parameters::get_VNS_search ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_VNS_search(), Parameters::check() must be invoked" ); - return _VNS_search; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_VNS_search(), Parameters::check() must be invoked" ); + return _VNS_search; } // get_VNS_trigger: const NOMAD::Double & NOMAD::Parameters::get_VNS_trigger ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_VNS_trigger(), Parameters::check() must be invoked" ); - return _VNS_trigger; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_VNS_trigger(), Parameters::check() must be invoked" ); + return _VNS_trigger; } // get_LH_search_p0: int NOMAD::Parameters::get_LH_search_p0 ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_LH_search_p0(), Parameters::check() must be invoked" ); - return _LH_search_p0; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_LH_search_p0(), Parameters::check() must be invoked" ); + return _LH_search_p0; } // get_LH_search_p0: int NOMAD::Parameters::get_LH_search_pi ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_LH_search_pi(), Parameters::check() must be invoked" ); - return _LH_search_pi; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_LH_search_pi(), Parameters::check() must be invoked" ); + return _LH_search_pi; } // get_direction_types: const std::set<NOMAD::direction_type> & NOMAD::Parameters::get_direction_types ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_direction_types(), Parameters::check() must be invoked" ); - return _direction_types; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_direction_types(), Parameters::check() must be invoked" ); + return _direction_types; } // get_sec_poll_dir_types: const std::set<NOMAD::direction_type> & NOMAD::Parameters::get_sec_poll_dir_types ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_sec_poll_dir_types(), Parameters::check() must be invoked" ); - return _sec_poll_dir_types; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_sec_poll_dir_types(), Parameters::check() must be invoked" ); + return _sec_poll_dir_types; } // check if there are Ortho-MADS directions: bool NOMAD::Parameters::has_orthomads_directions ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::has_orthomads_directions(), Parameters::check() must be invoked" ); - bool use_ortho_mads = NOMAD::dirs_have_orthomads ( _direction_types ); - if ( !use_ortho_mads ) - use_ortho_mads = NOMAD::dirs_have_orthomads ( _sec_poll_dir_types ); - return use_ortho_mads; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::has_orthomads_directions(), Parameters::check() must be invoked" ); + bool use_ortho_mads = NOMAD::dirs_have_orthomads ( _direction_types ); + if ( !use_ortho_mads ) + use_ortho_mads = NOMAD::dirs_have_orthomads ( _sec_poll_dir_types ); + return use_ortho_mads; } // check if there are dynamic directions to complete the (n+1)th direction: bool NOMAD::Parameters::has_dynamic_direction ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::has_dynamic_direction(), Parameters::check() must be invoked" ); - - return (has_direction_type(NOMAD::ORTHO_NP1_QUAD) || has_direction_type(NOMAD::ORTHO_NP1_NEG)); + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::has_dynamic_direction(), Parameters::check() must be invoked" ); + + return (has_direction_type(NOMAD::ORTHO_NP1_QUAD) || has_direction_type(NOMAD::ORTHO_NP1_NEG)); } // check that a given direction type is present (private) -bool NOMAD::Parameters::has_direction_type ( NOMAD::direction_type dt ) const +bool NOMAD::Parameters::has_direction_type ( NOMAD::direction_type dt ) const +{ + std::set<NOMAD::direction_type>::const_iterator it , end = _direction_types.end(); + for ( it = _direction_types.begin() ; it != end ; ++it ) + if ( (*it)==dt) + return true; + return false; +} + + +// anisotropic mesh : +bool NOMAD::Parameters::get_anisotropic_mesh ( void ) const { - std::set<NOMAD::direction_type>::const_iterator it , end = _direction_types.end(); - for ( it = _direction_types.begin() ; it != end ; ++it ) - if ( (*it)==dt) - return true; - return false; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_anisotropic_mesh, Parameters::check() must be invoked" ); + return _anisotropic_mesh; } +// smesh: +bool NOMAD::Parameters::get_use_smesh ( void ) const +{ + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_use_smesh, Parameters::check() must be invoked" ); + return _use_smesh; +} + // get_mesh_update_basis: const NOMAD::Double & NOMAD::Parameters::get_mesh_update_basis ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_mesh_update_basis(), Parameters::check() must be invoked" ); - return _mesh_update_basis; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_mesh_update_basis(), Parameters::check() must be invoked" ); + return _mesh_update_basis; +} + +// get_poll_update_basis: +const NOMAD::Double & NOMAD::Parameters::get_poll_update_basis ( void ) const +{ + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_poll_update_basis(), Parameters::check() must be invoked" ); + return _poll_update_basis; } // get_mesh_coarsening_exponent: int NOMAD::Parameters::get_mesh_coarsening_exponent ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_mesh_coarsening_exponent(), Parameters::check() must be invoked" ); - return _mesh_coarsening_exponent; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_mesh_coarsening_exponent(), Parameters::check() must be invoked" ); + return _mesh_coarsening_exponent; } // get_mesh_refining_exponent: int NOMAD::Parameters::get_mesh_refining_exponent ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_mesh_refining_exponent(), Parameters::check() must be invoked" ); - return _mesh_refining_exponent; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_mesh_refining_exponent(), Parameters::check() must be invoked" ); + return _mesh_refining_exponent; } // get_initial_mesh_index: int NOMAD::Parameters::get_initial_mesh_index ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_initial_mesh_index(), Parameters::check() must be invoked" ); - return _initial_mesh_index; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_initial_mesh_index(), Parameters::check() must be invoked" ); + return _initial_mesh_index; } -// get_max_mesh_index: -int NOMAD::Parameters::get_max_mesh_index ( void ) const +// get_initial_mesh_size: +const NOMAD::Point & NOMAD::Parameters::get_initial_mesh_size ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_max_mesh_index(), Parameters::check() must be invoked" ); - return _max_mesh_index; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_initial_mesh_size(), Parameters::check() must be invoked" ); + return _initial_mesh_size; } -// get_initial_mesh_size: -const NOMAD::Point & NOMAD::Parameters::get_initial_mesh_size ( void ) const +// get_initial_poll_size: +const NOMAD::Point & NOMAD::Parameters::get_initial_poll_size ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_initial_mesh_size(), Parameters::check() must be invoked" ); - return _initial_mesh_size; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_initial_poll_size(), Parameters::check() must be invoked" ); + return _initial_poll_size; } // get_min_mesh_size: const NOMAD::Point & NOMAD::Parameters::get_min_mesh_size ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_min_mesh_size(), Parameters::check() must be invoked" ); - return _min_mesh_size; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_min_mesh_size(), Parameters::check() must be invoked" ); + return _min_mesh_size; } // get_min_poll_size: const NOMAD::Point & NOMAD::Parameters::get_min_poll_size ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_min_poll_size(), Parameters::check() must be invoked" ); - return _min_poll_size; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_min_poll_size(), Parameters::check() must be invoked" ); + return _min_poll_size; } // get_min_poll_size_defined: bool NOMAD::Parameters::get_min_poll_size_defined ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_min_poll_size_defined(), Parameters::check() must be invoked" ); - return _min_poll_size_defined; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_min_poll_size_defined(), Parameters::check() must be invoked" ); + return _min_poll_size_defined; } // get_neighbors_exe: const std::string & NOMAD::Parameters::get_neighbors_exe ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_neighbors_exe(), Parameters::check() must be invoked" ); - return _neighbors_exe; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_neighbors_exe(), Parameters::check() must be invoked" ); + return _neighbors_exe; } // get_extended_poll_trigger: const NOMAD::Double & NOMAD::Parameters::get_extended_poll_trigger ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_extended_poll_trigger(), Parameters::check() must be invoked" ); - return _extended_poll_trigger; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_extended_poll_trigger(), Parameters::check() must be invoked" ); + return _extended_poll_trigger; } // get_relative_ept: bool NOMAD::Parameters::get_relative_ept ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_relative_ept(), Parameters::check() must be invoked" ); - return _relative_ept; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_relative_ept(), Parameters::check() must be invoked" ); + return _relative_ept; } // get_extended_poll_enabled: bool NOMAD::Parameters::get_extended_poll_enabled ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_extended_poll_enabled(), Parameters::check() must be invoked" ); - return _extended_poll_enabled; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_extended_poll_enabled(), Parameters::check() must be invoked" ); + return _extended_poll_enabled; } // get_user_calls_enabled: bool NOMAD::Parameters::get_user_calls_enabled ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_user_calls_enabled(), Parameters::check() must be invoked" ); - return _user_calls_enabled; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_user_calls_enabled(), Parameters::check() must be invoked" ); + return _user_calls_enabled; } // get_asynchronous: bool NOMAD::Parameters::get_asynchronous ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_asynchronous(), Parameters::check() must be invoked" ); - return _asynchronous; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_asynchronous(), Parameters::check() must be invoked" ); + return _asynchronous; } // get_x0s: const std::vector<NOMAD::Point *> & NOMAD::Parameters::get_x0s ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_x0s(), Parameters::check() must be invoked" ); - return _x0s; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_x0s(), Parameters::check() must be invoked" ); + return _x0s; } // get_x0_cache_file: const std::string & NOMAD::Parameters::get_x0_cache_file ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_x0_cache_file(), Parameters::check() must be invoked" ); - return _x0_cache_file; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_x0_cache_file(), Parameters::check() must be invoked" ); + return _x0_cache_file; } // get_lb: const NOMAD::Point & NOMAD::Parameters::get_lb ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_lb(), Parameters::check() must be invoked" ); - return _lb; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_lb(), Parameters::check() must be invoked" ); + return _lb; } // get_ub: const NOMAD::Point & NOMAD::Parameters::get_ub ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_ub(), Parameters::check() must be invoked" ); - return _ub; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_ub(), Parameters::check() must be invoked" ); + return _ub; } // get_scaling: const NOMAD::Point & NOMAD::Parameters::get_scaling ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_scaling(), Parameters::check() must be invoked" ); - return _scaling; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_scaling(), Parameters::check() must be invoked" ); + return _scaling; } // get_fixed_variables: const NOMAD::Point & NOMAD::Parameters::get_fixed_variables ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_fixed_variables(), Parameters::check() must be invoked" ); - return _fixed_variables; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_fixed_variables(), Parameters::check() must be invoked" ); + return _fixed_variables; } // variable_is_fixed: bool NOMAD::Parameters::variable_is_fixed ( int index ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::variable_is_fixed(), Parameters::check() must be invoked" ); - if ( index < 0 || index >= _fixed_variables.size() ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::variable_is_fixed(), bad variable index" ); - return _fixed_variables[index].is_defined(); + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::variable_is_fixed(), Parameters::check() must be invoked" ); + if ( index < 0 || index >= _fixed_variables.size() ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::variable_is_fixed(), bad variable index" ); + return _fixed_variables[index].is_defined(); } // get_bb_nb_outputs: int NOMAD::Parameters::get_bb_nb_outputs ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_bb_nb_outputs(), Parameters::check() must be invoked" ); - return static_cast<int>(_bb_output_type.size()); + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_bb_nb_outputs(), Parameters::check() must be invoked" ); + return static_cast<int>(_bb_output_type.size()); } // get_bb_exe: const std::list<std::string> & NOMAD::Parameters::get_bb_exe ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_bb_exe(), Parameters::check() must be invoked" ); - return _bb_exe; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_bb_exe(), Parameters::check() must be invoked" ); + return _bb_exe; } // get_sgte_eval_sort: bool NOMAD::Parameters::get_sgte_eval_sort ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_sgte_eval_sort(), Parameters::check() must be invoked" ); - return _sgte_eval_sort; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_sgte_eval_sort(), Parameters::check() must be invoked" ); + return _sgte_eval_sort; } // has_sgte: bool NOMAD::Parameters::has_sgte ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::has_sgte(), Parameters::check() must be invoked" ); - return _has_sgte; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::has_sgte(), Parameters::check() must be invoked" ); + return _has_sgte; } // get_opt_only_sgte: bool NOMAD::Parameters::get_opt_only_sgte ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_opt_only_sgte(), Parameters::check() must be invoked" ); - return _opt_only_sgte; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_opt_only_sgte(), Parameters::check() must be invoked" ); + return _opt_only_sgte; } // has_sgte_exe: bool NOMAD::Parameters::has_sgte_exe ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::has_sgte_exe(), Parameters::check() must be invoked" ); - return !_sgte_exe.empty(); + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::has_sgte_exe(), Parameters::check() must be invoked" ); + return !_sgte_exe.empty(); } // get_sgte_cost: int NOMAD::Parameters::get_sgte_cost ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_sgte_cost(), Parameters::check() must be invoked" ); - return _sgte_cost; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_sgte_cost(), Parameters::check() must be invoked" ); + return _sgte_cost; } // get_sgte_exe (returns an empty string if bb_exe has no surrogate): std::string NOMAD::Parameters::get_sgte_exe ( const std::string & bb_exe ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_sgte_exe(), Parameters::check() must be invoked" ); - std::map<std::string,std::string>::const_iterator it = _sgte_exe.find(bb_exe); - std::string s; - if ( it != _sgte_exe.end() ) - s = it->second; - return s; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_sgte_exe(), Parameters::check() must be invoked" ); + std::map<std::string,std::string>::const_iterator it = _sgte_exe.find(bb_exe); + std::string s; + if ( it != _sgte_exe.end() ) + s = it->second; + return s; } // get_index_obj: const std::list<int> & NOMAD::Parameters::get_index_obj ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_index_obj(), Parameters::check() must be invoked" ); - return _index_obj; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_index_obj(), Parameters::check() must be invoked" ); + return _index_obj; } // get_nb_obj: int NOMAD::Parameters::get_nb_obj ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_nb_obj(), Parameters::check() must be invoked" ); - return static_cast<int>(_index_obj.size()); + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_nb_obj(), Parameters::check() must be invoked" ); + return static_cast<int>(_index_obj.size()); } // get_bb_input_include_tag: bool NOMAD::Parameters::get_bb_input_include_tag ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_bb_input_include_tag(), Parameters::check() must be invoked" ); - return _bb_input_include_tag; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_bb_input_include_tag(), Parameters::check() must be invoked" ); + return _bb_input_include_tag; } // get_bb_input_include_seed: bool NOMAD::Parameters::get_bb_input_include_seed ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_bb_input_include_seed(), Parameters::check() must be invoked" ); - return _bb_input_include_seed; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_bb_input_include_seed(), Parameters::check() must be invoked" ); + return _bb_input_include_seed; } // get_bb_redirection: bool NOMAD::Parameters::get_bb_redirection ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_bb_redirection(), Parameters::check() must be invoked" ); - return _bb_redirection; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_bb_redirection(), Parameters::check() must be invoked" ); + return _bb_redirection; } // get_bb_input_type: const std::vector<NOMAD::bb_input_type> & NOMAD::Parameters::get_bb_input_type ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_bb_input_type(), Parameters::check() must be invoked" ); - return _bb_input_type; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_bb_input_type(), Parameters::check() must be invoked" ); + return _bb_input_type; } // get_bb_output_type: const std::vector<NOMAD::bb_output_type> & NOMAD::Parameters::get_bb_output_type ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_bb_output_type(), Parameters::check() must be invoked" ); - return _bb_output_type; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_bb_output_type(), Parameters::check() must be invoked" ); + return _bb_output_type; } // get_seed: int NOMAD::Parameters::get_seed ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_seed(), Parameters::check() must be invoked" ); - return _seed; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_seed(), Parameters::check() must be invoked" ); + return _seed; } // get_display_all_eval: bool NOMAD::Parameters::get_display_all_eval ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_display_all_eval(), Parameters::check() must be invoked" ); - return _display_all_eval; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_display_all_eval(), Parameters::check() must be invoked" ); + return _display_all_eval; } // get_display_stats: const std::list<std::string> & NOMAD::Parameters::get_display_stats ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_display_stats(), Parameters::check() must be invoked" ); - return _display_stats; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_display_stats(), Parameters::check() must be invoked" ); + return _display_stats; } // get_stats_file_name: const std::string & NOMAD::Parameters::get_stats_file_name ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_stats_file_name(), Parameters::check() must be invoked" ); - return _stats_file_name; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_stats_file_name(), Parameters::check() must be invoked" ); + return _stats_file_name; } // get_stats_file: const std::list<std::string> & NOMAD::Parameters::get_stats_file ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_stats_file(), Parameters::check() must be invoked" ); - return _stats_file; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_stats_file(), Parameters::check() must be invoked" ); + return _stats_file; } // get_point_display_limit: int NOMAD::Parameters::get_point_display_limit ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_point_display_limit(), Parameters::check() must be invoked" ); - return NOMAD::Point::get_display_limit(); + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_point_display_limit(), Parameters::check() must be invoked" ); + return NOMAD::Point::get_display_limit(); } // out (ex get_display()): const NOMAD::Display & NOMAD::Parameters::out ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::out(), Parameters::check() must be invoked" ); - return _out; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::out(), Parameters::check() must be invoked" ); + return _out; } // get_display_degree 1/2: void NOMAD::Parameters::get_display_degree ( std::string & d ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_display_degree(), Parameters::check() must be invoked" ); - _out.get_display_degree ( d ); + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_display_degree(), Parameters::check() must be invoked" ); + _out.get_display_degree ( d ); } // get_display_degree 2/2: int NOMAD::Parameters::get_display_degree ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_display_degree(), Parameters::check() must be invoked" ); - return _out.get_gen_dd(); + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_display_degree(), Parameters::check() must be invoked" ); + return _out.get_gen_dd(); } // get_max_eval: int NOMAD::Parameters::get_max_eval ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_max_eval(), Parameters::check() must be invoked" ); - return _max_eval; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_max_eval(), Parameters::check() must be invoked" ); + return _max_eval; } // get_max_bb_eval: int NOMAD::Parameters::get_max_bb_eval ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_max_bb_eval(), Parameters::check() must be invoked" ); - return _max_bb_eval; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_max_bb_eval(), Parameters::check() must be invoked" ); + return _max_bb_eval; } // get_max_sim_bb_eval: int NOMAD::Parameters::get_max_sim_bb_eval ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_max_sim_bb_eval(), Parameters::check() must be invoked" ); - return _max_sim_bb_eval; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_max_sim_bb_eval(), Parameters::check() must be invoked" ); + return _max_sim_bb_eval; } // get_max_sgte_eval: int NOMAD::Parameters::get_max_sgte_eval ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_max_sgte_eval(), Parameters::check() must be invoked" ); - return _sgte_max_eval; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_max_sgte_eval(), Parameters::check() must be invoked" ); + return _sgte_max_eval; } // get_max_time: int NOMAD::Parameters::get_max_time ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_max_time(), Parameters::check() must be invoked" ); - return _max_time; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_max_time(), Parameters::check() must be invoked" ); + return _max_time; } // get_max_iterations: int NOMAD::Parameters::get_max_iterations ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_max_iterations(), Parameters::check() must be invoked" ); - return _max_iterations; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_max_iterations(), Parameters::check() must be invoked" ); + return _max_iterations; } // get_max_consecutive_failed_iterations: int NOMAD::Parameters::get_max_consecutive_failed_iterations ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_max_consecutive_failed_iterations(), Parameters::check() must be invoked" ); - return _max_cons_failed_it; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_max_consecutive_failed_iterations(), Parameters::check() must be invoked" ); + return _max_cons_failed_it; } // get_max_cache_memory: float NOMAD::Parameters::get_max_cache_memory ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_max_cache_memory(), Parameters::check() must be invoked" ); - return _max_cache_memory; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_max_cache_memory(), Parameters::check() must be invoked" ); + return _max_cache_memory; } // get_cache_save_period: int NOMAD::Parameters::get_cache_save_period ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_cache_save_period(), Parameters::check() must be invoked" ); - return _cache_save_period; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_cache_save_period(), Parameters::check() must be invoked" ); + return _cache_save_period; } // get_stop_if_feasible: bool NOMAD::Parameters::get_stop_if_feasible ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_stop_if_feasible(), Parameters::check() must be invoked" ); - return _stop_if_feasible; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_stop_if_feasible(), Parameters::check() must be invoked" ); + return _stop_if_feasible; } // get_f_target: const NOMAD::Point & NOMAD::Parameters::get_f_target ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_f_target(), Parameters::check() must be invoked" ); - return _f_target; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_f_target(), Parameters::check() must be invoked" ); + return _f_target; } // get_stat_sum_target: const NOMAD::Double & NOMAD::Parameters::get_stat_sum_target ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_stat_sum_target(), Parameters::check() must be invoked" ); - return _stat_sum_target; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_stat_sum_target(), Parameters::check() must be invoked" ); + return _stat_sum_target; } // get_L_curve_target: const NOMAD::Double & NOMAD::Parameters::get_L_curve_target ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_L_curve_target(), Parameters::check() must be invoked" ); - return _L_curve_target; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_L_curve_target(), Parameters::check() must be invoked" ); + return _L_curve_target; } // get_problem_dir: const std::string & NOMAD::Parameters::get_problem_dir ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_problem_dir(), Parameters::check() must be invoked" ); - return _problem_dir; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_problem_dir(), Parameters::check() must be invoked" ); + return _problem_dir; } // get_tmp_dir: const std::string & NOMAD::Parameters::get_tmp_dir ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_tmp_dir(), Parameters::check() must be invoked" ); - return _tmp_dir; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_tmp_dir(), Parameters::check() must be invoked" ); + return _tmp_dir; } // get_solution_file: const std::string & NOMAD::Parameters::get_solution_file ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_solution_file(), Parameters::check() must be invoked" ); - return _solution_file; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_solution_file(), Parameters::check() must be invoked" ); + return _solution_file; } // get_history_file: const std::string & NOMAD::Parameters::get_history_file ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_history_file(), Parameters::check() must be invoked" ); - return _history_file; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_history_file(), Parameters::check() must be invoked" ); + return _history_file; } // get_cache_file: const std::string & NOMAD::Parameters::get_cache_file ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_cache_file(), Parameters::check() must be invoked" ); - return _cache_file; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_cache_file(), Parameters::check() must be invoked" ); + return _cache_file; } // get_sgte_cache_file: const std::string & NOMAD::Parameters::get_sgte_cache_file ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_sgte_cache_file(), Parameters::check() must be invoked" ); - return _sgte_cache_file; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_sgte_cache_file(), Parameters::check() must be invoked" ); + return _sgte_cache_file; } // get_rho: const NOMAD::Double & NOMAD::Parameters::get_rho ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_rho(), Parameters::check() must be invoked" ); - return _rho; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_rho(), Parameters::check() must be invoked" ); + return _rho; } // get_h_min: const NOMAD::Double & NOMAD::Parameters::get_h_min ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_h_min(), Parameters::check() must be invoked" ); - return _h_min; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_h_min(), Parameters::check() must be invoked" ); + return _h_min; } // get_h_max_0: const NOMAD::Double & NOMAD::Parameters::get_h_max_0 ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_h_max_0(), Parameters::check() must be invoked" ); - return _h_max_0; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_h_max_0(), Parameters::check() must be invoked" ); + return _h_max_0; } // get_h_norm: NOMAD::hnorm_type NOMAD::Parameters::get_h_norm ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_h_norm(), Parameters::check() must be invoked" ); - return _h_norm; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_h_norm(), Parameters::check() must be invoked" ); + return _h_norm; } // use_sec_poll_center: bool NOMAD::Parameters::use_sec_poll_center ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::use_second_poll_center(), Parameters::check() must be invoked" ); - return _barrier_type == NOMAD::PB || _barrier_type == NOMAD::PEB_P; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::use_second_poll_center(), Parameters::check() must be invoked" ); + return _barrier_type == NOMAD::PB || _barrier_type == NOMAD::PEB_P; } // get_barrier_type: NOMAD::bb_output_type NOMAD::Parameters::get_barrier_type ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_filter_type(), Parameters::check() must be invoked" ); - return _barrier_type; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_filter_type(), Parameters::check() must be invoked" ); + return _barrier_type; } // has_constraints: bool NOMAD::Parameters::has_constraints ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::has_constraints(), Parameters::check() must be invoked" ); - return _has_constraints; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::has_constraints(), Parameters::check() must be invoked" ); + return _has_constraints; } // has_EB_constraints: bool NOMAD::Parameters::has_EB_constraints ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::has_EB_constraints(), Parameters::check() must be invoked" ); - return _has_EB_constraints; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::has_EB_constraints(), Parameters::check() must be invoked" ); + return _has_EB_constraints; } // get_multi_nb_mads_runs: int NOMAD::Parameters::get_multi_nb_mads_runs ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_multi_nb_mads_runs(), Parameters::check() must be invoked" ); - return _multi_nb_mads_runs; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_multi_nb_mads_runs(), Parameters::check() must be invoked" ); + return _multi_nb_mads_runs; } // get_multi_overall_bb_eval: int NOMAD::Parameters::get_multi_overall_bb_eval ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_multi_overall_bb_eval(), Parameters::check() must be invoked" ); - return _multi_overall_bb_eval; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_multi_overall_bb_eval(), Parameters::check() must be invoked" ); + return _multi_overall_bb_eval; } // get_multi_use_delta_crit: bool NOMAD::Parameters::get_multi_use_delta_crit ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_multi_use_delta_crit(), Parameters::check() must be invoked" ); - return _multi_use_delta_crit; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_multi_use_delta_crit(), Parameters::check() must be invoked" ); + return _multi_use_delta_crit; } // get_multi_f_bounds: const NOMAD::Point & NOMAD::Parameters::get_multi_f_bounds ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_multi_f_bounds(), Parameters::check() must be invoked" ); - return _multi_f_bounds; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_multi_f_bounds(), Parameters::check() must be invoked" ); + return _multi_f_bounds; } // get_multi_formulation: NOMAD::multi_formulation_type NOMAD::Parameters::get_multi_formulation ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_multi_formulation(), Parameters::check() must be invoked" ); - return _multi_formulation; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_multi_formulation(), Parameters::check() must be invoked" ); + return _multi_formulation; } // get_opportunistic_cache_search: bool NOMAD::Parameters::get_opportunistic_cache_search ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_opportunistic_cache_search(), Parameters::check() must be invoked" ); - return _opportunistic_cache_search; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_opportunistic_cache_search(), Parameters::check() must be invoked" ); + return _opportunistic_cache_search; } // get_opportunistic_LH: bool NOMAD::Parameters::get_opportunistic_LH ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_opportunistic_LH(), Parameters::check() must be invoked" ); - return _opportunistic_LH; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_opportunistic_LH(), Parameters::check() must be invoked" ); + return _opportunistic_LH; } // get_opportunistic_eval: bool NOMAD::Parameters::get_opportunistic_eval ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_opportunistic_eval(), Parameters::check() must be invoked" ); - return _opportunistic_eval; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_opportunistic_eval(), Parameters::check() must be invoked" ); + return _opportunistic_eval; } // get_opportunistic_min_nb_success int NOMAD::Parameters::get_opportunistic_min_nb_success ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_opportunistic_min_nb_success(), Parameters::check() must be invoked"); - return _opportunistic_min_nb_success; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_opportunistic_min_nb_success(), Parameters::check() must be invoked"); + return _opportunistic_min_nb_success; } // get_opportunistic_min_eval int NOMAD::Parameters::get_opportunistic_min_eval ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_opportunistic_min_eval(), Parameters::check() must be invoked" ); - return _opportunistic_min_eval; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_opportunistic_min_eval(), Parameters::check() must be invoked" ); + return _opportunistic_min_eval; +} + +// get_bb_max_block_size +int NOMAD::Parameters::get_bb_max_block_size ( void ) const +{ + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_bb_max_block_size(), Parameters::check() must be invoked" ); + return _bb_max_block_size; } + // get_opportunistic_min_f_imprvmt const NOMAD::Double & NOMAD::Parameters::get_opportunistic_min_f_imprvmt ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_opportunistic_min_f_imprvmt(), Parameters::check() must be invoked" ); - return _opportunistic_min_f_imprvmt; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_opportunistic_min_f_imprvmt(), Parameters::check() must be invoked" ); + return _opportunistic_min_f_imprvmt; } // get_opportunistic_lucky_eval: bool NOMAD::Parameters::get_opportunistic_lucky_eval ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_opportunistic_lucky_eval(), Parameters::check() must be invoked" ); - return _opportunistic_lucky_eval; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_opportunistic_lucky_eval(), Parameters::check() must be invoked" ); + return _opportunistic_lucky_eval; } // check_stat_sum: bool NOMAD::Parameters::check_stat_sum ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::check_stat_sum(), Parameters::check() must be invoked" ); - return ( _index_stat_sum >= 0 ); + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::check_stat_sum(), Parameters::check() must be invoked" ); + return ( _index_stat_sum >= 0 ); } // check_stat_avg: bool NOMAD::Parameters::check_stat_avg ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::check_stat_avg(), Parameters::check() must be invoked" ); - return ( _index_stat_avg >= 0 ); + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::check_stat_avg(), Parameters::check() must be invoked" ); + return ( _index_stat_avg >= 0 ); } // get_index_stat_sum: int NOMAD::Parameters::get_index_stat_sum ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_index_stat_sum(), Parameters::check() must be invoked" ); - return _index_stat_sum; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_index_stat_sum(), Parameters::check() must be invoked" ); + return _index_stat_sum; } // get_index_stat_avg: int NOMAD::Parameters::get_index_stat_avg ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_index_stat_avg(), Parameters::check() must be invoked" ); - return _index_stat_avg; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_index_stat_avg(), Parameters::check() must be invoked" ); + return _index_stat_avg; } // get_index_cnt_eval: int NOMAD::Parameters::get_index_cnt_eval ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_index_cnt_eval(), Parameters::check() must be invoked" ); - return _index_cnt_eval; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_index_cnt_eval(), Parameters::check() must be invoked" ); + return _index_cnt_eval; } // get_periodic_variables: const std::vector<bool> & NOMAD::Parameters::get_periodic_variables ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_periodic_variables(), Parameters::check() must be invoked" ); - return _periodic_variables; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_periodic_variables(), Parameters::check() must be invoked" ); + return _periodic_variables; } // get_variable_groups: const std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & NOMAD::Parameters::get_variable_groups ( void ) const { - if ( _to_be_checked ) - throw Bad_Access ( "Parameters.cpp" , __LINE__ , - "Parameters::get_variable_groups(), Parameters::check() must be invoked" ); - return _var_groups; + if ( _to_be_checked ) + throw Bad_Access ( "Parameters.cpp" , __LINE__ , + "Parameters::get_variable_groups(), Parameters::check() must be invoked" ); + return _var_groups; } /*----------------------------------------*/ @@ -5711,185 +5957,185 @@ NOMAD::Parameters::get_variable_groups ( void ) const // set_POINT_DISPLAY_LIMIT: void NOMAD::Parameters::set_POINT_DISPLAY_LIMIT ( int dl ) { - NOMAD::Point::set_display_limit ( dl ); + NOMAD::Point::set_display_limit ( dl ); } // set_DIMENSION: bool NOMAD::Parameters::set_DIMENSION ( int dim ) { - if ( _dimension > 0 ) { - _dimension = -1; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DIMENSION - defined twice" ); - return false; - } - - _to_be_checked = true; - _dimension = dim; - if ( _dimension <= 0 ) { - _dimension = -1; - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DIMENSION" ); - return false; - } - - // all variables are initially considered continuous: - _bb_input_type.resize ( _dimension ); - for ( int i = 0 ; i < _dimension ; ++i ) - _bb_input_type[i] = NOMAD::CONTINUOUS; - - // resize of _initial_mesh_size: - _initial_mesh_size.reset ( _dimension ); - - return true; + if ( _dimension > 0 ) { + _dimension = -1; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DIMENSION - defined twice" ); + return false; + } + + _to_be_checked = true; + _dimension = dim; + if ( _dimension <= 0 ) { + _dimension = -1; + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DIMENSION" ); + return false; + } + + // all variables are initially considered continuous: + _bb_input_type.resize ( _dimension ); + for ( int i = 0 ; i < _dimension ; ++i ) + _bb_input_type[i] = NOMAD::CONTINUOUS; + + // resize of _initial_mesh_size: + _initial_mesh_size.reset ( _dimension ); + _initial_poll_size.reset ( _dimension ); + + return true; } // set_EXTERN_SIGNATURE (set a new extern signature and // delete the standard signature): void NOMAD::Parameters::set_EXTERN_SIGNATURE ( NOMAD::Signature * s ) { - if ( _std_signature && s == _std_signature ) - return; - - // standard signature: - delete _std_signature; - _std_signature = NULL; - _extern_signature = s; - - // dimension: - _dimension = -1; - set_DIMENSION ( s->get_n() ); - - // input types: - set_BB_INPUT_TYPE ( s->get_input_types() ); - - // bounds: - set_LOWER_BOUND ( s->get_lb() ); - set_UPPER_BOUND ( s->get_ub() ); - - // scaling: - set_SCALING ( s->get_scaling() ); - - // fixed variables: - set_FIXED_VARIABLE ( s->get_fixed_variables() ); - - // periodic variables: - set_PERIODIC_VARIABLE ( s->get_periodic_variables() ); - - // variable groups: - reset_variable_groups(); - set_VARIABLE_GROUP ( s->get_var_groups() ); - - _to_be_checked = true; -} - -// set_HALTON_SEED: -void NOMAD::Parameters::set_HALTON_SEED ( int hs ) -{ - _to_be_checked = true; - _halton_seed = ( hs < 0 ) ? -1 : hs; + if ( _std_signature && s == _std_signature ) + return; + + // standard signature: + delete _std_signature; + _std_signature = NULL; + _extern_signature = s; + + // dimension: + _dimension = -1; + set_DIMENSION ( s->get_n() ); + + // input types: + set_BB_INPUT_TYPE ( s->get_input_types() ); + + // bounds: + set_LOWER_BOUND ( s->get_lb() ); + set_UPPER_BOUND ( s->get_ub() ); + + // scaling: + set_SCALING ( s->get_scaling() ); + + // fixed variables: + set_FIXED_VARIABLE ( s->get_fixed_variables() ); + + // periodic variables: + set_PERIODIC_VARIABLE ( s->get_periodic_variables() ); + + // variable groups: + reset_variable_groups(); + set_VARIABLE_GROUP ( s->get_var_groups() ); + + _to_be_checked = true; } // set_SNAP_TO_BOUNDS: void NOMAD::Parameters::set_SNAP_TO_BOUNDS ( bool stb ) { - _to_be_checked = true; - _snap_to_bounds = stb; + _to_be_checked = true; + _snap_to_bounds = stb; } // set_SPECULATIVE_SEARCH: void NOMAD::Parameters::set_SPECULATIVE_SEARCH ( bool ss ) { - _to_be_checked = true; - _speculative_search = ss; + _to_be_checked = true; + _speculative_search = ss; } // set_CACHE_SEARCH: void NOMAD::Parameters::set_CACHE_SEARCH ( bool s ) { - _to_be_checked = true; - _cache_search = s; + _to_be_checked = true; + _cache_search = s; } // Disable use of models void NOMAD::Parameters::set_DISABLE_MODELS ( void ) { - _disable_models=true; + _disable_models=true; +} + +// Disable use of models +void NOMAD::Parameters::set_DISABLE_EVAL_SORT ( void ) +{ + _disable_eval_sort=true; } // set all the models parameters: void NOMAD::Parameters::set_model_parameters ( const NOMAD::model_params_type & mp ) { - _to_be_checked = true; - set_MODEL_SEARCH ( 1 , mp.search1 ); - set_MODEL_SEARCH ( 2 , mp.search2 ); - set_MODEL_EVAL_SORT ( mp.eval_sort ); - set_MODEL_SEARCH_OPTIMISTIC ( mp.search_optimistic ); - set_MODEL_SEARCH_PROJ_TO_MESH ( mp.search_proj_to_mesh ); - set_MODEL_SEARCH_MAX_TRIAL_PTS ( mp.search_max_trial_pts ); - set_MODEL_EVAL_SORT_CAUTIOUS ( mp.eval_sort_cautious ); - set_MODEL_QUAD_RADIUS_FACTOR ( mp.quad_radius_factor ); - set_MODEL_QUAD_USE_WP ( mp.quad_use_WP ); - set_MODEL_QUAD_MIN_Y_SIZE ( mp.quad_min_Y_size ); - set_MODEL_QUAD_MAX_Y_SIZE ( mp.quad_max_Y_size ); - set_MODEL_TGP_MODE ( mp.tgp_mode ); - set_MODEL_TGP_REUSE_MODEL ( mp.tgp_reuse_model ); + _to_be_checked = true; + set_MODEL_SEARCH ( 1 , mp.search1 ); + set_MODEL_SEARCH ( 2 , mp.search2 ); + set_MODEL_EVAL_SORT ( mp.eval_sort ); + set_MODEL_SEARCH_OPTIMISTIC ( mp.search_optimistic ); + set_MODEL_SEARCH_PROJ_TO_MESH ( mp.search_proj_to_mesh ); + set_MODEL_SEARCH_MAX_TRIAL_PTS ( mp.search_max_trial_pts ); + set_MODEL_EVAL_SORT_CAUTIOUS ( mp.eval_sort_cautious ); + set_MODEL_QUAD_RADIUS_FACTOR ( mp.quad_radius_factor ); + set_MODEL_QUAD_USE_WP ( mp.quad_use_WP ); + set_MODEL_QUAD_MIN_Y_SIZE ( mp.quad_min_Y_size ); + set_MODEL_QUAD_MAX_Y_SIZE ( mp.quad_max_Y_size ); + set_MODEL_TGP_MODE ( mp.tgp_mode ); + set_MODEL_TGP_REUSE_MODEL ( mp.tgp_reuse_model ); } // set_MODEL_SEARCH (1/3): void NOMAD::Parameters::set_MODEL_SEARCH ( int i , NOMAD::model_type ms ) { - _to_be_checked = true; - + _to_be_checked = true; + #ifndef USE_TGP - if ( ms == NOMAD::TGP_MODEL ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_SEARCH: this version has not been compiled for TGP" ); + if ( ms == NOMAD::TGP_MODEL ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_SEARCH: this version has not been compiled for TGP" ); #endif - - if ( i != 1 && i != 2 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "NOMAD::Parameters::set_MODEL_SEARCH(i,m): bad value for argument i (must be 1 or 2)" ); - - if ( i == 1 ) { - if ( _model_params.search2 != NOMAD::NO_MODEL ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "NOMAD::Parameters::set_MODEL_SEARCH(1,m): already a second model search" ); - - _model_params.search1 = ms; - } - else { - - if ( _model_params.search1 == NOMAD::NO_MODEL && ms != NOMAD::NO_MODEL ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "NOMAD::Parameters::set_MODEL_SEARCH(2,m): no first model search" ); - - if ( _model_params.search1 != NOMAD::NO_MODEL && _model_params.search1 == ms ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "NOMAD::Parameters::set_MODEL_SEARCH(2,m): second model search of the same type" ); - - _model_params.search2 = ms; - } + + if ( i != 1 && i != 2 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "NOMAD::Parameters::set_MODEL_SEARCH(i,m): bad value for argument i (must be 1 or 2)" ); + + if ( i == 1 ) { + if ( _model_params.search2 != NOMAD::NO_MODEL ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "NOMAD::Parameters::set_MODEL_SEARCH(1,m): already a second model search" ); + + _model_params.search1 = ms; + } + else { + + if ( _model_params.search1 == NOMAD::NO_MODEL && ms != NOMAD::NO_MODEL ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "NOMAD::Parameters::set_MODEL_SEARCH(2,m): no first model search" ); + + if ( _model_params.search1 != NOMAD::NO_MODEL && _model_params.search1 == ms ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "NOMAD::Parameters::set_MODEL_SEARCH(2,m): second model search of the same type" ); + + _model_params.search2 = ms; + } } // set_MODEL_SEARCH (2/3): void NOMAD::Parameters::set_MODEL_SEARCH ( bool ms ) { - if ( ms ) { - set_MODEL_SEARCH ( 1 , NOMAD::QUADRATIC_MODEL ); - set_MODEL_SEARCH ( 2 , NOMAD::NO_MODEL ); - } - else { - set_MODEL_SEARCH ( 1 , NOMAD::NO_MODEL ); - set_MODEL_SEARCH ( 2 , NOMAD::NO_MODEL ); - } + if ( ms ) { + set_MODEL_SEARCH ( 1 , NOMAD::QUADRATIC_MODEL ); + set_MODEL_SEARCH ( 2 , NOMAD::NO_MODEL ); + } + else { + set_MODEL_SEARCH ( 1 , NOMAD::NO_MODEL ); + set_MODEL_SEARCH ( 2 , NOMAD::NO_MODEL ); + } } // set_MODEL_SEARCH (3/3): void NOMAD::Parameters::set_MODEL_SEARCH ( NOMAD::model_type ms ) { - set_MODEL_SEARCH ( 1 , ms ); - set_MODEL_SEARCH ( 2 , NOMAD::NO_MODEL ); + set_MODEL_SEARCH ( 1 , ms ); + set_MODEL_SEARCH ( 2 , NOMAD::NO_MODEL ); } @@ -5897,71 +6143,71 @@ void NOMAD::Parameters::set_MODEL_SEARCH ( NOMAD::model_type ms ) void NOMAD::Parameters::set_MODEL_EVAL_SORT ( NOMAD::model_type mes ) { #ifndef USE_TGP - if ( mes == NOMAD::TGP_MODEL ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_EVAL_SORT: this version has not been compiled for TGP" ); + if ( mes == NOMAD::TGP_MODEL ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_EVAL_SORT: this version has not been compiled for TGP" ); #endif - _to_be_checked = true; - _model_params.eval_sort = mes; + _to_be_checked = true; + _model_params.eval_sort = mes; } // set_MODEL_EVAL_SORT (2/2): void NOMAD::Parameters::set_MODEL_EVAL_SORT ( bool mes ) { - if ( mes ) - set_MODEL_EVAL_SORT ( NOMAD::QUADRATIC_MODEL ); - else - set_MODEL_EVAL_SORT ( NOMAD::NO_MODEL ); + if ( mes ) + set_MODEL_EVAL_SORT ( NOMAD::QUADRATIC_MODEL ); + else + set_MODEL_EVAL_SORT ( NOMAD::NO_MODEL ); } // set_MODEL_SEARCH_OPTIMISTIC: void NOMAD::Parameters::set_MODEL_SEARCH_OPTIMISTIC ( bool mso ) { - _to_be_checked = true; - _model_params.search_optimistic = mso; + _to_be_checked = true; + _model_params.search_optimistic = mso; } // set_MODEL_SEARCH_PROJ_TO_MESH: void NOMAD::Parameters::set_MODEL_SEARCH_PROJ_TO_MESH ( bool ptm ) { - _to_be_checked = true; - _model_params.search_proj_to_mesh = ptm; + _to_be_checked = true; + _model_params.search_proj_to_mesh = ptm; } // set_MODEL_QUAD_RADIUS_FACTOR: void NOMAD::Parameters::set_MODEL_QUAD_RADIUS_FACTOR ( const NOMAD::Double & r ) { - _to_be_checked = true; - _model_params.quad_radius_factor = r; + _to_be_checked = true; + _model_params.quad_radius_factor = r; } // set_MODEL_QUAD_USE_WP: void NOMAD::Parameters::set_MODEL_QUAD_USE_WP ( bool uwp ) { - _to_be_checked = true; - _model_params.quad_use_WP = uwp; + _to_be_checked = true; + _model_params.quad_use_WP = uwp; } // set_MODEL_QUAD_MAX_Y_SIZE: void NOMAD::Parameters::set_MODEL_QUAD_MAX_Y_SIZE ( int s ) { - _to_be_checked = true; - _model_params.quad_max_Y_size = s; + _to_be_checked = true; + _model_params.quad_max_Y_size = s; } // set_MODEL_QUAD_MIN_Y_SIZE: void NOMAD::Parameters::set_MODEL_QUAD_MIN_Y_SIZE ( int s ) { - _to_be_checked = true; - _model_params.quad_min_Y_size = (s < 0) ? -1 : s; + _to_be_checked = true; + _model_params.quad_min_Y_size = (s < 0) ? -1 : s; } // set_MODEL_QUAD_HYPERCUBE_LOWER_LIM: void NOMAD::Parameters::set_MODEL_NP1_QUAD_EPSILON ( const NOMAD::Double & d ) { - _to_be_checked = true; - _model_params.model_np1_quad_epsilon = d; + _to_be_checked = true; + _model_params.model_np1_quad_epsilon = d; } @@ -5969,402 +6215,401 @@ void NOMAD::Parameters::set_MODEL_NP1_QUAD_EPSILON ( const NOMAD::Double & d ) // set_MODEL_TGP_MODE: void NOMAD::Parameters::set_MODEL_TGP_MODE ( NOMAD::TGP_mode_type m ) { - if ( m == NOMAD::TGP_USER ) { - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MODEL_TGP_MODE: the TGP user mode is only a debugging option" ); - } - - _to_be_checked = true; - _model_params.tgp_mode = m; + if ( m == NOMAD::TGP_USER ) { + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MODEL_TGP_MODE: the TGP user mode is only a debugging option" ); + } + + _to_be_checked = true; + _model_params.tgp_mode = m; } // set_MODEL_TGP_REUSE_MODEL: void NOMAD::Parameters::set_MODEL_TGP_REUSE_MODEL ( bool rm ) { - _to_be_checked = true; - _model_params.tgp_reuse_model = rm; + _to_be_checked = true; + _model_params.tgp_reuse_model = rm; } // set_MODEL_SEARCH_MAX_TRIAL_PTS: void NOMAD::Parameters::set_MODEL_SEARCH_MAX_TRIAL_PTS ( int s ) { - _to_be_checked = true; - _model_params.search_max_trial_pts = s; + _to_be_checked = true; + _model_params.search_max_trial_pts = s; } // set_MODEL_EVAL_SORT_CAUTIOUS: void NOMAD::Parameters::set_MODEL_EVAL_SORT_CAUTIOUS ( bool mesc ) { - _to_be_checked = true; - _model_params.eval_sort_cautious = mesc; + _to_be_checked = true; + _model_params.eval_sort_cautious = mesc; } // set_VNS_SEARCH (1/2): void NOMAD::Parameters::set_VNS_SEARCH ( bool s ) { - _to_be_checked = true; - _VNS_search = s; - _VNS_trigger = ( s ) ? 0.75 : NOMAD::Double(); + _to_be_checked = true; + _VNS_search = s; + _VNS_trigger = ( s ) ? 0.75 : NOMAD::Double(); } // set_VNS_SEARCH (2/2): void NOMAD::Parameters::set_VNS_SEARCH ( const NOMAD::Double & trigger ) { - _to_be_checked = true; - if ( !trigger.is_defined() ) { - _VNS_search = false; - return; - } - - if ( trigger < 0.0 || trigger > 1.0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VNS_SEARCH: must be in [0;1]" ); - - _VNS_search = ( trigger > 0.0 ); - _VNS_trigger = trigger; + _to_be_checked = true; + if ( !trigger.is_defined() ) { + _VNS_search = false; + return; + } + + if ( trigger < 0.0 || trigger > 1.0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VNS_SEARCH: must be in [0;1]" ); + + _VNS_search = ( trigger > 0.0 ); + _VNS_trigger = trigger; } // set_LH_SEARCH: void NOMAD::Parameters::set_LH_SEARCH ( int p0 , int pi ) { - _to_be_checked = true; - _LH_search_p0 = (p0 <= 0 ) ? 0 : p0; - _LH_search_pi = (pi <= 0 ) ? 0 : pi; + _to_be_checked = true; + _LH_search_p0 = (p0 <= 0 ) ? 0 : p0; + _LH_search_pi = (pi <= 0 ) ? 0 : pi; } // set_DIRECTION_TYPE (1/2): void NOMAD::Parameters::set_DIRECTION_TYPE ( NOMAD::direction_type dt ) { - _to_be_checked = true; - if ( dt == NOMAD::UNDEFINED_DIRECTION || - dt == NOMAD::NO_DIRECTION || - dt == NOMAD::MODEL_SEARCH_DIR ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: DIRECTION_TYPE" ); - _direction_types.insert ( dt ); + _to_be_checked = true; + if ( dt == NOMAD::UNDEFINED_DIRECTION || + dt == NOMAD::NO_DIRECTION || + dt == NOMAD::MODEL_SEARCH_DIR ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: DIRECTION_TYPE" ); + _direction_types.insert ( dt ); } // set_DIRECTION_TYPE (2/2): void NOMAD::Parameters::set_DIRECTION_TYPE ( const std::set<NOMAD::direction_type> & dt ) { - std::set<NOMAD::direction_type>::const_iterator it , end = dt.end(); - for ( it = dt.begin() ; it != end ; ++it ) - set_DIRECTION_TYPE ( *it ); + std::set<NOMAD::direction_type>::const_iterator it , end = dt.end(); + for ( it = dt.begin() ; it != end ; ++it ) + set_DIRECTION_TYPE ( *it ); } void NOMAD::Parameters::set_DIRECTION_TYPE_NO_MODEL ( void ) { - std::set<NOMAD::direction_type>::iterator it=_direction_types.find(NOMAD::ORTHO_NP1_QUAD); - std::set<NOMAD::direction_type>::iterator end = _direction_types.end(); - while (it != end) - { - _direction_types.erase(it); - _direction_types.insert(NOMAD::ORTHO_NP1_NEG); - it=_direction_types.find(NOMAD::ORTHO_NP1_QUAD); - } + std::set<NOMAD::direction_type>::iterator it=_direction_types.find(NOMAD::ORTHO_NP1_QUAD); + std::set<NOMAD::direction_type>::iterator end = _direction_types.end(); + while (it != end) + { + _direction_types.erase(it); + _direction_types.insert(NOMAD::ORTHO_NP1_NEG); + it=_direction_types.find(NOMAD::ORTHO_NP1_QUAD); + } } // set_SEC_POLL_DIR_TYPE (1/2): void NOMAD::Parameters::set_SEC_POLL_DIR_TYPE ( NOMAD::direction_type dt ) { - _to_be_checked = true; - if ( dt == NOMAD::UNDEFINED_DIRECTION || dt == NOMAD::MODEL_SEARCH_DIR ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SEC_POLL_DIR_TYPE" ); - _sec_poll_dir_types.insert ( dt ); + _to_be_checked = true; + if ( dt == NOMAD::UNDEFINED_DIRECTION || dt == NOMAD::MODEL_SEARCH_DIR ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SEC_POLL_DIR_TYPE" ); + _sec_poll_dir_types.insert ( dt ); } // set_SEC_POLL_DIR_TYPE (2/2): void NOMAD::Parameters::set_SEC_POLL_DIR_TYPE ( const std::set<NOMAD::direction_type> & dt ) { - std::set<NOMAD::direction_type>::const_iterator it , end = dt.end(); - for ( it = dt.begin() ; it != end ; ++it ) - set_SEC_POLL_DIR_TYPE ( *it ); + std::set<NOMAD::direction_type>::const_iterator it , end = dt.end(); + for ( it = dt.begin() ; it != end ; ++it ) + set_SEC_POLL_DIR_TYPE ( *it ); } // set_RHO: void NOMAD::Parameters::set_RHO ( const NOMAD::Double & rho ) { - if ( !rho.is_defined() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: RHO" ); - _to_be_checked = true; - _rho = rho; + if ( !rho.is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: RHO" ); + _to_be_checked = true; + _rho = rho; } // set_H_MIN: void NOMAD::Parameters::set_H_MIN ( const NOMAD::Double & h_min ) { - if ( !h_min.is_defined() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: H_MIN" ); - _to_be_checked = true; - _h_min = h_min; + if ( !h_min.is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , "invalid parameter: H_MIN" ); + _to_be_checked = true; + _h_min = h_min; } // set_H_MAX_0: void NOMAD::Parameters::set_H_MAX_0 ( const NOMAD::Double & h_max ) { - _to_be_checked = true; - _h_max_0 = ( h_max.is_defined() ) ? h_max : NOMAD::INF; + _to_be_checked = true; + _h_max_0 = ( h_max.is_defined() ) ? h_max : NOMAD::INF; } // set_H_NORM: void NOMAD::Parameters::set_H_NORM ( NOMAD::hnorm_type h_norm ) { - _to_be_checked = true; - _h_norm = h_norm; + _to_be_checked = true; + _h_norm = h_norm; } // set_SCALING (1/2): void NOMAD::Parameters::set_SCALING ( int index , const NOMAD::Double & value ) { - _to_be_checked = true; - if ( index < 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SCALING" ); - if ( index >= _scaling.size() ) - _scaling.resize ( index + 1 ); - - _scaling[index] = value; + _to_be_checked = true; + if ( index < 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SCALING" ); + if ( index >= _scaling.size() ) + _scaling.resize ( index + 1 ); + + _scaling[index] = value; } // set_SCALING (2/2): void NOMAD::Parameters::set_SCALING ( const NOMAD::Point & s ) { - _to_be_checked = true; - _scaling = s; + _to_be_checked = true; + _scaling = s; } // set_FIXED_VARIABLE (1/3): void NOMAD::Parameters::set_FIXED_VARIABLE ( int index , const NOMAD::Double & value ) { - _to_be_checked = true; - if ( index < 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: FIXED_VARIABLE" ); - if ( index >= _fixed_variables.size() ) - _fixed_variables.resize ( index + 1 ); - - _fixed_variables[index] = value; + _to_be_checked = true; + if ( index < 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: FIXED_VARIABLE" ); + if ( index >= _fixed_variables.size() ) + _fixed_variables.resize ( index + 1 ); + + _fixed_variables[index] = value; } // set_FIXED_VARIABLE (2/3): void NOMAD::Parameters::set_FIXED_VARIABLE ( int index ) { - _to_be_checked = true; - if ( index < 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: FIXED_VARIABLE (index < 0)" ); - if ( _x0s.empty() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: FIXED_VARIABLE (no starting point defined)" ); - - if ( index >= _x0s[0]->size() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: FIXED_VARIABLE (incompatible starting point)" ); - - if ( index >= _fixed_variables.size() ) - _fixed_variables.resize ( index + 1 ); - - _fixed_variables[index] = (*_x0s[0])[index]; + _to_be_checked = true; + if ( index < 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: FIXED_VARIABLE (index < 0)" ); + if ( _x0s.empty() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: FIXED_VARIABLE (no starting point defined)" ); + + if ( index >= _x0s[0]->size() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: FIXED_VARIABLE (incompatible starting point)" ); + + if ( index >= _fixed_variables.size() ) + _fixed_variables.resize ( index + 1 ); + + _fixed_variables[index] = (*_x0s[0])[index]; } // set_FIXED_VARIABLE (2/3): void NOMAD::Parameters::set_FIXED_VARIABLE ( const NOMAD::Point & fv ) { - _to_be_checked = true; - _fixed_variables = fv; + _to_be_checked = true; + _fixed_variables = fv; } // set_LOWER_BOUND (1/2): void NOMAD::Parameters::set_LOWER_BOUND ( int index, const NOMAD::Double & value ) { - _to_be_checked = true; - if (index < 0) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: LOWER_BOUND" ); - if ( index >= _lb.size() ) - _lb.resize(index+1); - if ( !_lb[index].is_defined() || value > _lb[index] ) - _lb[index] = value; + _to_be_checked = true; + if (index < 0) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: LOWER_BOUND" ); + if ( index >= _lb.size() ) + _lb.resize(index+1); + if ( !_lb[index].is_defined() || value > _lb[index] ) + _lb[index] = value; } // set_LOWER_BOUND (2/2): void NOMAD::Parameters::set_LOWER_BOUND ( const NOMAD::Point & lb ) { - _to_be_checked = true; - _lb = lb; + _to_be_checked = true; + _lb = lb; } // set_UPPER_BOUND (1/2): void NOMAD::Parameters::set_UPPER_BOUND ( int index, const NOMAD::Double & value ) { - _to_be_checked = true; - if (index < 0) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: UPPER_BOUND" ); - if ( index >= _ub.size() ) - _ub.resize (index + 1); - if ( !_ub[index].is_defined() || value < _ub[index] ) - _ub[index] = value; + _to_be_checked = true; + if (index < 0) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: UPPER_BOUND" ); + if ( index >= _ub.size() ) + _ub.resize (index + 1); + if ( !_ub[index].is_defined() || value < _ub[index] ) + _ub[index] = value; } // set_UPPER_BOUND (2/2): void NOMAD::Parameters::set_UPPER_BOUND ( const NOMAD::Point & ub ) { - _to_be_checked = true; - _ub = ub; + _to_be_checked = true; + _ub = ub; } // set_SGTE_COST: void NOMAD::Parameters::set_SGTE_COST ( int c ) { - _to_be_checked = true; - _sgte_cost = ( c > 0 ) ? c : -1; + _to_be_checked = true; + _sgte_cost = ( c > 0 ) ? c : -1; } // set_SGTE_EVAL_SORT: void NOMAD::Parameters::set_SGTE_EVAL_SORT ( bool ses ) { - _to_be_checked = true; - _sgte_eval_sort = ses; + _to_be_checked = true; + _sgte_eval_sort = ses; } // set_HAS_SGTET: void NOMAD::Parameters::set_HAS_SGTE ( bool hs ) { - _to_be_checked = true; - _has_sgte = hs; + _to_be_checked = true; + _has_sgte = hs; } // set_OPT_ONLY_SGTE: void NOMAD::Parameters::set_OPT_ONLY_SGTE ( bool oos ) { - _to_be_checked = true; - _opt_only_sgte = oos; + _to_be_checked = true; + _opt_only_sgte = oos; } // set_SGTE_EXE: void NOMAD::Parameters::set_SGTE_EXE ( const std::string & bb_exe , - const std::string & sgte_exe ) + const std::string & sgte_exe ) { - _to_be_checked = true; - _sgte_exe[bb_exe] = sgte_exe; + _to_be_checked = true; + _sgte_exe[bb_exe] = sgte_exe; } // set_BB_EXE (1/3): void NOMAD::Parameters::set_BB_EXE ( const std::string & bbexe ) { - _to_be_checked = true; - if ( _bb_output_type.empty() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_EXE - BB_OUTPUT_TYPE must be defined first" ); - _bb_exe.clear(); - size_t nk = _bb_output_type.size(); - for ( size_t k = 0 ; k < nk ; ++k ) - _bb_exe.push_back ( bbexe ); + _to_be_checked = true; + if ( _bb_output_type.empty() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_EXE - BB_OUTPUT_TYPE must be defined first" ); + _bb_exe.clear(); + size_t nk = _bb_output_type.size(); + for ( size_t k = 0 ; k < nk ; ++k ) + _bb_exe.push_back ( bbexe ); } // set_BB_EXE (2/3): void NOMAD::Parameters::set_BB_EXE ( int m , const std::string * bbexe ) { - _to_be_checked = true; - - if ( m <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_EXE" ); - - if ( m != static_cast<int>(_bb_output_type.size()) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_EXE - number of names or BB_OUTPUT_TYPE undefined" ); - - size_t nk = _bb_output_type.size(); - for ( size_t k = 0 ; k < nk ; ++k ) - _bb_exe.push_back ( bbexe[k] ); + _to_be_checked = true; + + if ( m <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_EXE" ); + + if ( m != static_cast<int>(_bb_output_type.size()) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_EXE - number of names or BB_OUTPUT_TYPE undefined" ); + + size_t nk = _bb_output_type.size(); + for ( size_t k = 0 ; k < nk ; ++k ) + _bb_exe.push_back ( bbexe[k] ); } // set_BB_EXE (3/3): void NOMAD::Parameters::set_BB_EXE ( const std::list<std::string> & bbexe ) { - _to_be_checked = true; - if ( !bbexe.empty() && bbexe.size() != _bb_output_type.size() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_EXE - number of names or BB_OUTPUT_TYPE undefined" ); - _bb_exe = bbexe; + _to_be_checked = true; + if ( !bbexe.empty() && bbexe.size() != _bb_output_type.size() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_EXE - number of names or BB_OUTPUT_TYPE undefined" ); + _bb_exe = bbexe; } // set_BB_INPUT_INCLUDE_TAG: void NOMAD::Parameters::set_BB_INPUT_INCLUDE_TAG ( bool bbiit ) { - _to_be_checked = true; - _bb_input_include_tag = bbiit; + _to_be_checked = true; + _bb_input_include_tag = bbiit; } // set_BB_INPUT_INCLUDE_SEED: void NOMAD::Parameters::set_BB_INPUT_INCLUDE_SEED ( bool bbiis ) { - _to_be_checked = true; - _bb_input_include_seed = bbiis; + _to_be_checked = true; + _bb_input_include_seed = bbiis; } // set_BB_REDIRECTION: void NOMAD::Parameters::set_BB_REDIRECTION ( bool bbr ) { - _to_be_checked = true; - _bb_redirection = bbr; + _to_be_checked = true; + _bb_redirection = bbr; } // set_BB_INPUT_TYPE (1/3): void NOMAD::Parameters::set_BB_INPUT_TYPE ( int index , NOMAD::bb_input_type bbit ) { - _to_be_checked = true; - if ( index < 0 || index >= _dimension || - static_cast<int>(_bb_input_type.size()) != _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_INPUT_TYPE" ); - _bb_input_type[index] = bbit; + _to_be_checked = true; + if ( index < 0 || index >= _dimension || + static_cast<int>(_bb_input_type.size()) != _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_INPUT_TYPE" ); + _bb_input_type[index] = bbit; } // set_BB_INPUT_TYPE (2/3): void NOMAD::Parameters::set_BB_INPUT_TYPE ( const std::vector<NOMAD::bb_input_type > & bbit ) { - int n = static_cast<int>(bbit.size()); - for ( int i = 0 ; i < n ; ++i ) - set_BB_INPUT_TYPE ( i , bbit[i] ); + int n = static_cast<int>(bbit.size()); + for ( int i = 0 ; i < n ; ++i ) + set_BB_INPUT_TYPE ( i , bbit[i] ); } // set_BB_INPUT_TYPE (3/3): void NOMAD::Parameters::set_BB_INPUT_TYPE ( const std::list<NOMAD::bb_input_type > & bbit ) { - int i = 0; - std::list<NOMAD::bb_input_type>::const_iterator it , end = bbit.end(); - for ( it = bbit.begin() ; it != end ; ++it , ++i ) - set_BB_INPUT_TYPE ( i , *it ); + int i = 0; + std::list<NOMAD::bb_input_type>::const_iterator it , end = bbit.end(); + for ( it = bbit.begin() ; it != end ; ++it , ++i ) + set_BB_INPUT_TYPE ( i , *it ); } // reset_PEB_changes: void NOMAD::Parameters::reset_PEB_changes ( void ) const { - size_t nk = _bb_output_type.size(); - for ( size_t k = 0 ; k < nk ; ++k ) - if ( _bb_output_type[k] == NOMAD::PEB_E ) - _bb_output_type[k] = NOMAD::PEB_P; + size_t nk = _bb_output_type.size(); + for ( size_t k = 0 ; k < nk ; ++k ) + if ( _bb_output_type[k] == NOMAD::PEB_E ) + _bb_output_type[k] = NOMAD::PEB_P; } - // change PEB to PB constraints void NOMAD::Parameters::change_PEB_to_PB ( void ) { - size_t nk = _bb_output_type.size(); - for ( size_t k = 0 ; k < nk ; ++k ) - if ( _bb_output_type[k] == NOMAD::PEB_P || _bb_output_type[k] == NOMAD::PEB_E ) - { - _bb_output_type[k] = NOMAD::PB; - _barrier_type = NOMAD::PB; - } + size_t nk = _bb_output_type.size(); + for ( size_t k = 0 ; k < nk ; ++k ) + if ( _bb_output_type[k] == NOMAD::PEB_P || _bb_output_type[k] == NOMAD::PEB_E ) + { + _bb_output_type[k] = NOMAD::PB; + _barrier_type = NOMAD::PB; + } } @@ -6372,998 +6617,1100 @@ void NOMAD::Parameters::change_PEB_to_PB ( void ) // change_PEB_constraint_status: void NOMAD::Parameters::change_PEB_constraint_status ( int index ) const { - if ( index < 0 || - index >= static_cast<int>(_bb_output_type.size()) || - _bb_output_type[index] != NOMAD::PEB_P ) - throw NOMAD::Exception ( "Parameters.cpp" , __LINE__ , - "error in Parameters::change_PEB_constraint_status(i): bad i" ); - _bb_output_type[index] = NOMAD::PEB_E; + if ( index < 0 || + index >= static_cast<int>(_bb_output_type.size()) || + _bb_output_type[index] != NOMAD::PEB_P ) + throw NOMAD::Exception ( "Parameters.cpp" , __LINE__ , + "error in Parameters::change_PEB_constraint_status(i): bad i" ); + _bb_output_type[index] = NOMAD::PEB_E; } // set_BB_OUTPUT_TYPE (1/2): void NOMAD::Parameters::set_BB_OUTPUT_TYPE ( const std::list<NOMAD::bb_output_type> & bbot ) { - int i = 0; - std::vector<NOMAD::bb_output_type> bbot_vector ( bbot.size() ); - std::list<NOMAD::bb_output_type>::const_iterator end = bbot.end() , it; - for ( it = bbot.begin() ; it != end ; ++it ) - bbot_vector[i++] = *it; - set_BB_OUTPUT_TYPE ( bbot_vector ); + int i = 0; + std::vector<NOMAD::bb_output_type> bbot_vector ( bbot.size() ); + std::list<NOMAD::bb_output_type>::const_iterator end = bbot.end() , it; + for ( it = bbot.begin() ; it != end ; ++it ) + bbot_vector[i++] = *it; + set_BB_OUTPUT_TYPE ( bbot_vector ); } // set_BB_OUTPUT_TYPE (2/2): void NOMAD::Parameters::set_BB_OUTPUT_TYPE ( const std::vector<NOMAD::bb_output_type> & bbot ) { - _to_be_checked = true; - - _barrier_type = NOMAD::EB; - _has_constraints = false; - _has_EB_constraints = false; - _has_filter_constraints = false; - - _bb_output_type.clear(); - - int m = static_cast<int>(bbot.size()); - - if ( m <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_OUTPUT_TYPE" ); - if ( !_bb_output_type.empty() && - m != static_cast<int>(_bb_output_type.size()) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_OUTPUT_TYPE - number of types" ); - - _bb_output_type.resize (m); - - bool filter_used = false; - bool pb_used = false; - bool peb_used = false; - - _index_obj.clear(); - - for ( int i = 0 ; i < m ; ++i ) - { - - _bb_output_type[i] = bbot[i]; - - switch ( bbot[i] ) - { - - case NOMAD::OBJ: - _index_obj.push_back(i); - break; - - case NOMAD::EB: - _has_constraints = true; - _has_EB_constraints = true; - break; - - case NOMAD::FILTER: - _has_constraints = true; - _has_filter_constraints = true; - filter_used = true; - break; - - case NOMAD::PB: - _has_constraints = true; - _has_filter_constraints = true; - pb_used = true; - break; - - case NOMAD::PEB_P: - case NOMAD::PEB_E: - _has_constraints = true; - _has_filter_constraints = true; - pb_used = true; - peb_used = true; - _bb_output_type[i] = NOMAD::PEB_P; - break; - default: - break; - } - } - - if ( _index_obj.empty() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_OUTPUT_TYPE - OBJ not given" ); - if ( filter_used && pb_used ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: BB_OUTPUT_TYPE - F and PB/PEB used together" ); - - if ( filter_used ) - _barrier_type = NOMAD::FILTER; - else if ( pb_used ) - _barrier_type = (peb_used) ? NOMAD::PEB_P : NOMAD::PB; + _to_be_checked = true; + + _barrier_type = NOMAD::EB; + _has_constraints = false; + _has_EB_constraints = false; + _has_filter_constraints = false; + + _bb_output_type.clear(); + + int m = static_cast<int>(bbot.size()); + + if ( m <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_OUTPUT_TYPE" ); + if ( !_bb_output_type.empty() && + m != static_cast<int>(_bb_output_type.size()) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_OUTPUT_TYPE - number of types" ); + + _bb_output_type.resize (m); + + bool filter_used = false; + bool pb_used = false; + bool peb_used = false; + + _index_obj.clear(); + + for ( int i = 0 ; i < m ; ++i ) + { + + _bb_output_type[i] = bbot[i]; + + switch ( bbot[i] ) + { + + case NOMAD::OBJ: + _index_obj.push_back(i); + break; + + case NOMAD::EB: + _has_constraints = true; + _has_EB_constraints = true; + break; + + case NOMAD::FILTER: + _has_constraints = true; + _has_filter_constraints = true; + filter_used = true; + break; + + case NOMAD::PB: + _has_constraints = true; + _has_filter_constraints = true; + pb_used = true; + break; + + case NOMAD::PEB_P: + case NOMAD::PEB_E: + _has_constraints = true; + _has_filter_constraints = true; + pb_used = true; + peb_used = true; + _bb_output_type[i] = NOMAD::PEB_P; + break; + default: + break; + } + } + + if ( _index_obj.empty() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_OUTPUT_TYPE - OBJ not given" ); + if ( filter_used && pb_used ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: BB_OUTPUT_TYPE - F and PB/PEB used together" ); + + if ( filter_used ) + _barrier_type = NOMAD::FILTER; + else if ( pb_used ) + _barrier_type = (peb_used) ? NOMAD::PEB_P : NOMAD::PB; } // set_PROBLEM_DIR: void NOMAD::Parameters::set_PROBLEM_DIR ( const std::string & dir ) { - _to_be_checked = true; - _problem_dir = dir; - if ( !_problem_dir.empty() && !NOMAD::Parameters::check_directory ( _problem_dir ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: PROBLEM_DIR" ); + _to_be_checked = true; + _problem_dir = dir; + if ( !_problem_dir.empty() && !NOMAD::Parameters::check_directory ( _problem_dir ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: PROBLEM_DIR" ); } // set_TMP_DIR: void NOMAD::Parameters::set_TMP_DIR ( const std::string & dir ) { - _to_be_checked = true; - _tmp_dir = dir; - if ( !_tmp_dir.empty() && !NOMAD::Parameters::check_directory ( _tmp_dir ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: TMP_DIR" ); + _to_be_checked = true; + _tmp_dir = dir; + if ( !_tmp_dir.empty() && !NOMAD::Parameters::check_directory ( _tmp_dir ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: TMP_DIR" ); } // set_ADD_SEED_TO_FILE_NAMES: void NOMAD::Parameters::set_ADD_SEED_TO_FILE_NAMES ( bool astfn ) { - _to_be_checked = true; - _add_seed_to_file_names = astfn; + _to_be_checked = true; + _add_seed_to_file_names = astfn; } // set_SOLUTION_FILE: void NOMAD::Parameters::set_SOLUTION_FILE ( const std::string & sf ) { - _to_be_checked = true; - _solution_file = sf; - if ( sf.empty() ) - return; - if ( !NOMAD::Parameters::check_directory ( _solution_file ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SOLUTION_FILE" ); - _solution_file.resize ( _solution_file.size()-1 ); + _to_be_checked = true; + _solution_file = sf; + if ( sf.empty() ) + return; + if ( !NOMAD::Parameters::check_directory ( _solution_file ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SOLUTION_FILE" ); + _solution_file.resize ( _solution_file.size()-1 ); } // set_HISTORY_FILE: void NOMAD::Parameters::set_HISTORY_FILE ( const std::string & hf ) { - _to_be_checked = true; - _history_file = hf; - if ( hf.empty() ) - return; - if ( !NOMAD::Parameters::check_directory ( _history_file ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: HISTORY_FILE" ); - _history_file.resize ( _history_file.size()-1 ); + _to_be_checked = true; + _history_file = hf; + if ( hf.empty() ) + return; + if ( !NOMAD::Parameters::check_directory ( _history_file ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: HISTORY_FILE" ); + _history_file.resize ( _history_file.size()-1 ); } // set_CACHE_FILE: void NOMAD::Parameters::set_CACHE_FILE ( const std::string & cf ) { - _to_be_checked = true; - _cache_file = cf; - if ( cf.empty() ) - return; - if ( !NOMAD::Parameters::check_directory ( _cache_file ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: CACHE_FILE" ); - _cache_file.resize ( _cache_file.size()-1 ); + _to_be_checked = true; + _cache_file = cf; + if ( cf.empty() ) + return; + if ( !NOMAD::Parameters::check_directory ( _cache_file ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: CACHE_FILE" ); + _cache_file.resize ( _cache_file.size()-1 ); } // set_SGTE_CACHE_FILE: void NOMAD::Parameters::set_SGTE_CACHE_FILE ( const std::string & cf ) { - _to_be_checked = true; - _sgte_cache_file = cf; - if ( cf.empty() ) - return; - if ( !NOMAD::Parameters::check_directory ( _sgte_cache_file ) ) { - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: SGTE_CACHE_FILE"); - } - _sgte_cache_file.resize ( _sgte_cache_file.size()-1 ); + _to_be_checked = true; + _sgte_cache_file = cf; + if ( cf.empty() ) + return; + if ( !NOMAD::Parameters::check_directory ( _sgte_cache_file ) ) { + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: SGTE_CACHE_FILE"); + } + _sgte_cache_file.resize ( _sgte_cache_file.size()-1 ); } // set_X0: // add a new point in the list of starting points: void NOMAD::Parameters::set_X0 ( const NOMAD::Point & x0 ) { - _to_be_checked = true; - _x0s.push_back ( new NOMAD::Point ( x0 ) ); + _to_be_checked = true; + _x0s.push_back ( new NOMAD::Point ( x0 ) ); } // indicate a x0 file or a cache file containing starting points: void NOMAD::Parameters::set_X0 ( const std::string & file_name ) { - _to_be_checked = true; - - if ( file_name.empty() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "Parameters::set_X0(file_name): file_name is empty" ); - - if ( _dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "Parameters::set_X0() has been used before setting DIMENSION" ); - - NOMAD::Point tmp_x0 ( _dimension ); - std::string complete_file_name = _problem_dir + file_name; - std::ifstream fin ( complete_file_name.c_str() ); - - if ( fin.fail() ) { - std::string err = "invalid parameter: X0 - could not open file \'" - + complete_file_name + "\'"; - fin.close(); - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); - } - - bool flag = true; - try { - fin >> tmp_x0; - } - catch ( NOMAD::Point::Bad_Input & ) { - flag = false; - - // we suppose that the file name corresponds to a cache file: - _x0_cache_file = file_name; - } - - while ( flag ) { - - set_X0 ( tmp_x0 ); - - // other starting points in the file ? - flag = true; - try { - fin >> tmp_x0; - } - catch ( NOMAD::Point::Bad_Input & ) { - flag = false; - } - } - - fin.close(); + _to_be_checked = true; + + if ( file_name.empty() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Parameters::set_X0(file_name): file_name is empty" ); + + if ( _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "Parameters::set_X0() has been used before setting DIMENSION" ); + + NOMAD::Point tmp_x0 ( _dimension ); + std::string complete_file_name = _problem_dir + file_name; + std::ifstream fin ( complete_file_name.c_str() ); + + if ( fin.fail() ) { + std::string err = "invalid parameter: X0 - could not open file \'" + + complete_file_name + "\'"; + fin.close(); + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , err ); + } + + bool flag = true; + try { + fin >> tmp_x0; + } + catch ( NOMAD::Point::Bad_Input & ) { + flag = false; + + // we suppose that the file name corresponds to a cache file: + _x0_cache_file = file_name; + } + + while ( flag ) { + + set_X0 ( tmp_x0 ); + + // other starting points in the file ? + flag = true; + try { + fin >> tmp_x0; + } + catch ( NOMAD::Point::Bad_Input & ) { + flag = false; + } + } + + fin.close(); } // set_DISPLAY_ALL_EVAL: void NOMAD::Parameters::set_DISPLAY_ALL_EVAL ( bool dae ) { - _to_be_checked = true; - _display_all_eval = dae; + _to_be_checked = true; + _display_all_eval = dae; } // set_DISPLAY_STATS (1/2): void NOMAD::Parameters::set_DISPLAY_STATS ( const std::list<std::string> & ls ) { - _display_stats.clear(); - _display_stats = ls; + _display_stats.clear(); + _display_stats = ls; } // set_DISPLAY_STATS (2/2): void NOMAD::Parameters::set_DISPLAY_STATS ( const std::string & stats ) { - if ( stats.empty() ) { - _display_stats.clear(); - return; - } - - NOMAD::Parameter_Entry pe ( "DISPLAY_STATS " + stats , false ); - - std::list<std::string>::const_iterator end = pe.get_values().end() , - it = pe.get_values().begin(); - std::list<std::string> ls; - - while ( it != end ) { - ls.push_back ( *it ); - ++it; - } - - ls.resize ( ls.size()-1 ); - - set_DISPLAY_STATS ( ls ); + if ( stats.empty() ) { + _display_stats.clear(); + return; + } + + NOMAD::Parameter_Entry pe ( "DISPLAY_STATS " + stats , false ); + + std::list<std::string>::const_iterator end = pe.get_values().end() , + it = pe.get_values().begin(); + std::list<std::string> ls; + + while ( it != end ) { + ls.push_back ( *it ); + ++it; + } + + ls.resize ( ls.size()-1 ); + + set_DISPLAY_STATS ( ls ); } // set_STATS_FILE (1/2): void NOMAD::Parameters::set_STATS_FILE ( const std::string & file_name , - const std::list<std::string> & ls ) -{ - if ( file_name.empty() ) { - reset_stats_file(); - return; - } - - _to_be_checked = true; - _stats_file = ls; - _stats_file_name = file_name; - - if ( !NOMAD::Parameters::check_directory ( _stats_file_name ) ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: STATS_FILE" ); - - _stats_file_name.resize ( _stats_file_name.size()-1 ); + const std::list<std::string> & ls ) +{ + if ( file_name.empty() ) { + reset_stats_file(); + return; + } + + _to_be_checked = true; + _stats_file = ls; + _stats_file_name = file_name; + + if ( !NOMAD::Parameters::check_directory ( _stats_file_name ) ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: STATS_FILE" ); + + _stats_file_name.resize ( _stats_file_name.size()-1 ); } // set_STATS_FILE (2/2): void NOMAD::Parameters::set_STATS_FILE ( const std::string & file_name , - const std::string & stats ) -{ - NOMAD::Parameter_Entry pe ( "STATS_FILE " + file_name + " " + stats , false ); - std::list<std::string>::const_iterator end = pe.get_values().end() , - it = pe.get_values().begin(); - std::list<std::string> ls; - ++it; - while ( it != end ) { - ls.push_back(*it); - ++it; - } - - ls.resize ( ls.size()-1 ); - - set_STATS_FILE ( file_name , ls ); + const std::string & stats ) +{ + NOMAD::Parameter_Entry pe ( "STATS_FILE " + file_name + " " + stats , false ); + std::list<std::string>::const_iterator end = pe.get_values().end() , + it = pe.get_values().begin(); + std::list<std::string> ls; + ++it; + while ( it != end ) { + ls.push_back(*it); + ++it; + } + + ls.resize ( ls.size()-1 ); + + set_STATS_FILE ( file_name , ls ); } // set_DISPLAY_DEGREE (1/3) - (accepts also dd_type arguments): bool NOMAD::Parameters::set_DISPLAY_DEGREE ( int dd ) { #ifndef DEBUG - return set_DISPLAY_DEGREE ( NOMAD::itos(dd) ); + return set_DISPLAY_DEGREE ( NOMAD::itos(dd) ); #endif - return true; + return true; } // set_DISPLAY_DEGREE (2/3): bool NOMAD::Parameters::set_DISPLAY_DEGREE ( const std::string & dd ) { #ifndef DEBUG - { - std::string ddu = dd; - NOMAD::toupper ( ddu ); - - if ( ddu == "NO" || ddu == "NO_DISPLAY" ) { - set_DISPLAY_DEGREE ( 0 , 0 , 0 , 0 ); - return true; - } - else if ( ddu == "MIN" || ddu == "MINIMAL" || ddu == "MINIMAL_DISPLAY" ) { - set_DISPLAY_DEGREE ( 1 , 1 , 1 , 1 ); - return true; - } - - else if ( ddu == "NORMAL" || ddu == "NORMAL_DISPLAY" ) { - set_DISPLAY_DEGREE ( 2 , 2 , 2 , 2 ); - return true; - } - - else if ( ddu == "FULL" || ddu == "FULL_DISPLAY" ) { - set_DISPLAY_DEGREE ( 3 , 3 , 3 , 3 ); - return true; - } - } - - if ( dd.size() == 1 ) { - int i; - if ( !NOMAD::atoi ( dd[0] , i ) ) - return false; - _out.set_degrees ( NOMAD::Display::int_to_dd(i) ); - return true; - } - - if ( dd.size() != 4 ) - return false; - - // 1. general display: - int gdd; - if ( !NOMAD::atoi ( dd[0] , gdd ) ) - return false; - - // 2. search display: - int sdd; - if ( !NOMAD::atoi ( dd[1] , sdd ) ) - return false; - - // 3. poll display: - int pdd; - if ( !NOMAD::atoi ( dd[2] , pdd ) ) - return false; - - // 4. iterative display: - int idd; - if ( !NOMAD::atoi ( dd[3] , idd ) ) - return false; - - set_DISPLAY_DEGREE ( gdd , sdd , pdd , idd ); - + { + std::string ddu = dd; + NOMAD::toupper ( ddu ); + + if ( ddu == "NO" || ddu == "NO_DISPLAY" ) { + set_DISPLAY_DEGREE ( 0 , 0 , 0 , 0 ); + return true; + } + else if ( ddu == "MIN" || ddu == "MINIMAL" || ddu == "MINIMAL_DISPLAY" ) { + set_DISPLAY_DEGREE ( 1 , 1 , 1 , 1 ); + return true; + } + + else if ( ddu == "NORMAL" || ddu == "NORMAL_DISPLAY" ) { + set_DISPLAY_DEGREE ( 2 , 2 , 2 , 2 ); + return true; + } + + else if ( ddu == "FULL" || ddu == "FULL_DISPLAY" ) { + set_DISPLAY_DEGREE ( 3 , 3 , 3 , 3 ); + return true; + } + } + + if ( dd.size() == 1 ) { + int i; + if ( !NOMAD::atoi ( dd[0] , i ) ) + return false; + _out.set_degrees ( NOMAD::Display::int_to_dd(i) ); + return true; + } + + if ( dd.size() != 4 ) + return false; + + // 1. general display: + int gdd; + if ( !NOMAD::atoi ( dd[0] , gdd ) ) + return false; + + // 2. search display: + int sdd; + if ( !NOMAD::atoi ( dd[1] , sdd ) ) + return false; + + // 3. poll display: + int pdd; + if ( !NOMAD::atoi ( dd[2] , pdd ) ) + return false; + + // 4. iterative display: + int idd; + if ( !NOMAD::atoi ( dd[3] , idd ) ) + return false; + + set_DISPLAY_DEGREE ( gdd , sdd , pdd , idd ); + #endif - return true; + return true; } // set_DISPLAY_DEGREE (3/3): void NOMAD::Parameters::set_DISPLAY_DEGREE ( int gen_dd , - int search_dd , - int poll_dd , - int iter_dd ) + int search_dd , + int poll_dd , + int iter_dd ) { #ifndef DEBUG - _out.set_degrees ( NOMAD::Display::int_to_dd ( gen_dd ) , - NOMAD::Display::int_to_dd ( search_dd ) , - NOMAD::Display::int_to_dd ( poll_dd ) , - NOMAD::Display::int_to_dd ( iter_dd ) ); + _out.set_degrees ( NOMAD::Display::int_to_dd ( gen_dd ) , + NOMAD::Display::int_to_dd ( search_dd ) , + NOMAD::Display::int_to_dd ( poll_dd ) , + NOMAD::Display::int_to_dd ( iter_dd ) ); #endif } // set_OPEN_BRACE: void NOMAD::Parameters::set_OPEN_BRACE ( const std::string & ob ) { - _to_be_checked = true; - _out.set_open_brace ( ob ); + _to_be_checked = true; + _out.set_open_brace ( ob ); } // set_CLOSED_BRACE: void NOMAD::Parameters::set_CLOSED_BRACE ( const std::string & cb ) { - _to_be_checked = true; - _out.set_closed_brace ( cb ); + _to_be_checked = true; + _out.set_closed_brace ( cb ); } // set_SEED: void NOMAD::Parameters::set_SEED ( int t ) { - _to_be_checked = true; - _seed = ( t < 0 ) ? NOMAD::get_pid() : t; + _to_be_checked = true; + _seed = ( t < 0 ) ? NOMAD::get_pid() : t; + + if ( t < 0 && t!=-1 && _out.get_gen_dd()>=NOMAD::NORMAL_DISPLAY && !_warning_has_been_displayed) + _out << NOMAD::open_block("Warning:") + << "Seed should be in the interval [0;INT_MAX] U {-1}. The seed is set to the process id!" << std::endl + << NOMAD::close_block(); + + // The RNG seed is set here when explicit set is required otherwise default RNG seed is used + NOMAD::RNG::set_seed(_seed); + } // set_MAX_EVAL: void NOMAD::Parameters::set_MAX_EVAL ( int e ) { - _to_be_checked = true; - _max_eval = ( e <= 0 ) ? -1 : e; + _to_be_checked = true; + _max_eval = ( e <= 0 ) ? -1 : e; } // set_MAX_BB_EVAL: void NOMAD::Parameters::set_MAX_BB_EVAL ( int bbe ) { - _to_be_checked = true; - _max_bbe_decided = true; - _max_bb_eval = ( bbe < 0 ) ? -1 : bbe; + _to_be_checked = true; + _max_bbe_decided = true; + _max_bb_eval = ( bbe < 0 ) ? -1 : bbe; } // set_MAX_SIM_BB_EVAL: void NOMAD::Parameters::set_MAX_SIM_BB_EVAL ( int bbe ) { - _to_be_checked = true; - _max_sim_bb_eval = ( bbe <= 0 ) ? -1 : bbe; + _to_be_checked = true; + _max_sim_bb_eval = ( bbe <= 0 ) ? -1 : bbe; } // set_MAX_SGTE_EVAL: void NOMAD::Parameters::set_MAX_SGTE_EVAL ( int bbe ) { - _to_be_checked = true; - _sgte_max_eval = ( bbe < 0 ) ? -1 : bbe; + _to_be_checked = true; + _sgte_max_eval = ( bbe < 0 ) ? -1 : bbe; } // set_MAX_TIME: void NOMAD::Parameters::set_MAX_TIME ( int t ) { - _to_be_checked = true; - _max_time = ( t <= 0 ) ? -1 : t; + _to_be_checked = true; + _max_time = ( t <= 0 ) ? -1 : t; } // set_MAX_ITERATIONS: void NOMAD::Parameters::set_MAX_ITERATIONS ( int it ) { - _to_be_checked = true; - _max_iterations = ( it < 0 ) ? -1 : it; + _to_be_checked = true; + _max_iterations = ( it < 0 ) ? -1 : it; } // set_MAX_CONSECUTIVE_FAILED_ITERATIONS: void NOMAD::Parameters::set_MAX_CONSECUTIVE_FAILED_ITERATIONS ( int it ) { - _to_be_checked = true; - _max_cons_failed_it = ( it <= 0 ) ? -1 : it; + _to_be_checked = true; + _max_cons_failed_it = ( it <= 0 ) ? -1 : it; } // set_MAX_CACHE_MEMORY:: void NOMAD::Parameters::set_MAX_CACHE_MEMORY ( float mcm ) { - _to_be_checked = true; - _max_cache_memory = ( mcm < 0.0 ) ? -1 : mcm; + _to_be_checked = true; + _max_cache_memory = ( mcm < 0.0 ) ? -1 : mcm; } // set_CACHE_SAVE_PERIOD: void NOMAD::Parameters::set_CACHE_SAVE_PERIOD ( int csp ) { - _to_be_checked = true; - _cache_save_period = ( csp <= 0 ) ? -1 : csp; + _to_be_checked = true; + _cache_save_period = ( csp <= 0 ) ? -1 : csp; } // set_STOP_IF_FEASIBLE: void NOMAD::Parameters::set_STOP_IF_FEASIBLE ( bool sif ) { - _to_be_checked = true; - _stop_if_feasible = sif; + _to_be_checked = true; + _stop_if_feasible = sif; } // set_F_TARGET (1/2): void NOMAD::Parameters::set_F_TARGET ( const NOMAD::Double & f_target ) { - _to_be_checked = true; - _f_target = NOMAD::Point ( 1 , f_target ); + _to_be_checked = true; + _f_target = NOMAD::Point ( 1 , f_target ); } // set_F_TARGET (2/2): void NOMAD::Parameters::set_F_TARGET ( const NOMAD::Point & f_target ) { - _to_be_checked = true; - _f_target = f_target; + _to_be_checked = true; + _f_target = f_target; } // set_STAT_SUM_TARGET: void NOMAD::Parameters::set_STAT_SUM_TARGET ( const NOMAD::Double & sst ) { - _to_be_checked = true; - _stat_sum_target = sst; + _to_be_checked = true; + _stat_sum_target = sst; } // set_L_CURVE_TARGET: void NOMAD::Parameters::set_L_CURVE_TARGET ( const NOMAD::Double & lct ) { - _to_be_checked = true; - _L_curve_target = lct; + _to_be_checked = true; + _L_curve_target = lct; +} + +// set_ANISOTROPIC_MESH: +void NOMAD::Parameters::set_ANISOTROPIC_MESH ( bool anis ) +{ + _to_be_checked = true; + _anisotropic_mesh = anis; } + +// set_USE_SMESH: +void NOMAD::Parameters::set_USE_SMESH ( bool use_smesh ) +{ + _to_be_checked = true; + _use_smesh = use_smesh; +} + + + // set_MESH_UPDATE_BASIS: void NOMAD::Parameters::set_MESH_UPDATE_BASIS ( const NOMAD::Double & mub ) { - if ( !mub.is_defined() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MESH_UPDATE_BASIS" ); - _to_be_checked = true; - _mesh_update_basis = mub; + if ( !mub.is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MESH_UPDATE_BASIS" ); + _to_be_checked = true; + _mesh_update_basis = mub; +} + +// set_POLL_UPDATE_BASIS: +void NOMAD::Parameters::set_POLL_UPDATE_BASIS ( const NOMAD::Double & pub ) +{ + if ( !pub.is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: POLL_UPDATE_BASIS" ); + _to_be_checked = true; + _poll_update_basis = pub; } + // set_INITIAL_MESH_INDEX: void NOMAD::Parameters::set_INITIAL_MESH_INDEX ( int ell_0 ) { - _to_be_checked = true; - if ( ell_0 > NOMAD::L_LIMITS ) - ell_0 = NOMAD::L_LIMITS; - else if ( ell_0 < - NOMAD::L_LIMITS ) - ell_0 = -NOMAD::L_LIMITS; - _initial_mesh_index = ell_0; + _to_be_checked = true; + if ( ell_0 > NOMAD::L_LIMITS ) + ell_0 = NOMAD::L_LIMITS; + else if ( ell_0 < - NOMAD::L_LIMITS ) + ell_0 = -NOMAD::L_LIMITS; + _initial_mesh_index = ell_0; } // set_MESH_COARSENING_EXPONENT: void NOMAD::Parameters::set_MESH_COARSENING_EXPONENT ( int mce ) { - _to_be_checked = true; - if ( mce < 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MESH_COARSENING_EXPONENT"); - _mesh_coarsening_exponent = mce; + _to_be_checked = true; + if ( mce < 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MESH_COARSENING_EXPONENT"); + _mesh_coarsening_exponent = mce; } // set_MESH_REFINING_EXPONENT: void NOMAD::Parameters::set_MESH_REFINING_EXPONENT ( int mre ) { - _to_be_checked = true; - if ( mre >= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MESH_REFINING_EXPONENT"); - _mesh_refining_exponent = mre; -} - -// set_MAX_MESH_INDEX: -void NOMAD::Parameters::set_MAX_MESH_INDEX ( int lmax ) -{ - _to_be_checked = true; - if ( lmax > NOMAD::L_LIMITS ) - lmax = NOMAD::L_LIMITS; - _max_mesh_index = lmax; + _to_be_checked = true; + if ( mre >= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MESH_REFINING_EXPONENT"); + _mesh_refining_exponent = mre; } // set_INITIAL_MESH_SIZE (1/3): void NOMAD::Parameters::set_INITIAL_MESH_SIZE ( int index , - const NOMAD::Double & d , - bool relative ) -{ - if ( index < 0 || index >= _initial_mesh_size.size() || !d.is_defined() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: INITIAL_MESH_SIZE" ); - _to_be_checked = true; - - if ( relative ) { - - if ( !_lb.is_defined() || !_ub.is_defined() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: INITIAL_MESH_SIZE - bounds not defined" ); - - if ( !_lb[index].is_defined() || !_ub[index].is_defined() || - d <= 0.0 || d > 1.0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: INITIAL_MESH_SIZE - relative value" ); - - NOMAD::Double d2 = d; - d2 *= _ub[index] - _lb[index]; - _initial_mesh_size[index] = d2; - } - else - _initial_mesh_size[index] = d; + const NOMAD::Double & d , + bool relative ) +{ + if ( index < 0 || index >= _initial_mesh_size.size() || !d.is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_MESH_SIZE" ); + _to_be_checked = true; + + if ( relative ) + { + + if ( !_lb.is_defined() || !_ub.is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_MESH_SIZE - bounds not defined" ); + + if ( !_lb[index].is_defined() || !_ub[index].is_defined() || + d <= 0.0 || d > 1.0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_MESH_SIZE - relative value" ); + + NOMAD::Double d2 = d; + d2 *= _ub[index] - _lb[index]; + _initial_mesh_size[index] = d2; + } + else + _initial_mesh_size[index] = d; } // set_INITIAL_MESH_SIZE (2/3): void NOMAD::Parameters::set_INITIAL_MESH_SIZE ( const NOMAD::Point & delta_m_0 , - bool relative ) + bool relative ) { - _to_be_checked = true; - if ( relative ) { - int nd = delta_m_0.size(); - for ( int i = 0 ; i < nd ; ++i ) - set_INITIAL_MESH_SIZE ( i , delta_m_0[i] , true ); - } - else - _initial_mesh_size = delta_m_0; + _to_be_checked = true; + if ( relative ) + { + int nd = delta_m_0.size(); + for ( int i = 0 ; i < nd ; ++i ) + set_INITIAL_MESH_SIZE ( i , delta_m_0[i] , true ); + } + else + _initial_mesh_size = delta_m_0; } // set_INITIAL_MESH_SIZE (3/3): void NOMAD::Parameters::set_INITIAL_MESH_SIZE ( const NOMAD::Double & d , bool relative ) { - if ( _dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: INITIAL_MESH_SIZE - undefined dimension" ); - _to_be_checked = true; - if ( relative ) - for ( int i = 0 ; i < _dimension ; ++i ) - set_INITIAL_MESH_SIZE ( i , d , true ); - else - _initial_mesh_size = NOMAD::Point ( _dimension , d ); + if ( _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_MESH_SIZE - undefined dimension" ); + _to_be_checked = true; + if ( relative ) + for ( int i = 0 ; i < _dimension ; ++i ) + set_INITIAL_MESH_SIZE ( i , d , true ); + else + _initial_mesh_size = NOMAD::Point ( _dimension , d ); +} + +// set_INITIAL_POLL_SIZE (1/3): +void NOMAD::Parameters::set_INITIAL_POLL_SIZE ( int index , + const NOMAD::Double & d , + bool relative ) +{ + if ( index < 0 || index >= _initial_poll_size.size() || !d.is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_POLL_SIZE" ); + _to_be_checked = true; + + if ( relative ) + { + + if ( !_lb.is_defined() || !_ub.is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_POLL_SIZE - bounds not defined" ); + + if ( !_lb[index].is_defined() || !_ub[index].is_defined() || + d <= 0.0 || d > 1.0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_POLL_SIZE - relative value" ); + + NOMAD::Double d2 = d; + d2 *= _ub[index] - _lb[index]; + _initial_poll_size[index] = d2; + } + else + _initial_poll_size[index] = d; +} + +// set_INITIAL_POLL_SIZE (2/3): +void NOMAD::Parameters::set_INITIAL_POLL_SIZE ( const NOMAD::Point & delta_m_0 , + bool relative ) +{ + _to_be_checked = true; + if ( relative ) + { + int nd = delta_m_0.size(); + for ( int i = 0 ; i < nd ; ++i ) + set_INITIAL_POLL_SIZE ( i , delta_m_0[i] , true ); + } + else + _initial_poll_size = delta_m_0; +} + +// set_INITIAL_POLL_SIZE (3/3): +void NOMAD::Parameters::set_INITIAL_POLL_SIZE ( const NOMAD::Double & d , bool relative ) +{ + if ( _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: INITIAL_POLL_SIZE - undefined dimension" ); + _to_be_checked = true; + if ( relative ) + for ( int i = 0 ; i < _dimension ; ++i ) + set_INITIAL_POLL_SIZE ( i , d , true ); + else + _initial_poll_size = NOMAD::Point ( _dimension , d ); } + + // set_MIN_MESH_SIZE (1/3): void NOMAD::Parameters::set_MIN_MESH_SIZE ( int index , - const NOMAD::Double & d , - bool relative ) -{ - if (_dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_MESH_SIZE - undefined dimension" ); - - if ( !_min_mesh_size.is_defined() ) - _min_mesh_size = NOMAD::Point ( _dimension ); - - if ( index < 0 || index >= _min_mesh_size.size() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_MESH_SIZE" ); - _to_be_checked = true; - if ( relative ) { - - if ( !_lb.is_defined() || !_ub.is_defined() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_MESH_SIZE - bounds not defined" ); - - if ( !_lb[index].is_defined() || !_ub[index].is_defined() || - !d.is_defined() || d <= 0.0 || d > 1.0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_MESH_SIZE - relative value" ); - NOMAD::Double d2 = d; - d2 *= _ub[index] - _lb[index]; - _min_mesh_size[index] = d2; - } - else - _min_mesh_size[index] = d; + const NOMAD::Double & d , + bool relative ) +{ + if (_dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_MESH_SIZE - undefined dimension" ); + + if ( !_min_mesh_size.is_defined() ) + _min_mesh_size = NOMAD::Point ( _dimension ); + + if ( index < 0 || index >= _min_mesh_size.size() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_MESH_SIZE" ); + _to_be_checked = true; + if ( relative ) + { + + if ( !_lb.is_defined() || !_ub.is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_MESH_SIZE - bounds not defined" ); + + if ( !_lb[index].is_defined() || !_ub[index].is_defined() || + !d.is_defined() || d <= 0.0 || d > 1.0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_MESH_SIZE - relative value" ); + NOMAD::Double d2 = d; + d2 *= _ub[index] - _lb[index]; + _min_mesh_size[index] = d2; + } + else + _min_mesh_size[index] = d; } // set_MIN_MESH_SIZE (2/3): void NOMAD::Parameters::set_MIN_MESH_SIZE ( const NOMAD::Point & delta_p_min , - bool relative ) + bool relative ) { - _to_be_checked = true; - if ( relative ) { - int nd = delta_p_min.size(); - for ( int i = 0 ; i < nd ; ++i ) - set_MIN_MESH_SIZE ( i , delta_p_min[i] , true ); - } - else - _min_mesh_size = delta_p_min; + _to_be_checked = true; + if ( relative ) + { + int nd = delta_p_min.size(); + for ( int i = 0 ; i < nd ; ++i ) + set_MIN_MESH_SIZE ( i , delta_p_min[i] , true ); + } + else + _min_mesh_size = delta_p_min; } // set_MIN_MESH_SIZE (3/3): void NOMAD::Parameters::set_MIN_MESH_SIZE ( const NOMAD::Double & d , bool relative ) { - if ( _dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_MESH_SIZE - undefined dimension" ); - _to_be_checked = true; - if ( relative ) - for ( int i = 0 ; i < _dimension ; ++i ) - set_MIN_MESH_SIZE ( i , d , true ); - else - _min_mesh_size = NOMAD::Point ( _dimension , d ); + if ( _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_MESH_SIZE - undefined dimension" ); + _to_be_checked = true; + if ( relative ) + for ( int i = 0 ; i < _dimension ; ++i ) + set_MIN_MESH_SIZE ( i , d , true ); + else + _min_mesh_size = NOMAD::Point ( _dimension , d ); } // set_MIN_POLL_SIZE (1/3): void NOMAD::Parameters::set_MIN_POLL_SIZE ( int index , - const NOMAD::Double & d , - bool relative ) -{ - if ( _dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_POLL_SIZE - undefined dimension" ); - - if ( !_min_poll_size.is_defined() ) - _min_poll_size = NOMAD::Point ( _dimension ); - - if ( index < 0 || index >= _min_poll_size.size() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_POLL_SIZE" ); - _to_be_checked = true; - if ( relative ) { - if ( !_lb[index].is_defined() || !_ub[index].is_defined() || - !d.is_defined() || d <= 0.0 || d > 1.0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_POLL_SIZE - relative value" ); - _min_poll_size[index] = d * ( _ub[index] - _lb[index] ); - } - else - _min_poll_size[index] = d; + const NOMAD::Double & d , + bool relative ) +{ + if ( _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_POLL_SIZE - undefined dimension" ); + + if ( !_min_poll_size.is_defined() ) + _min_poll_size = NOMAD::Point ( _dimension ); + + if ( index < 0 || index >= _min_poll_size.size() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_POLL_SIZE" ); + _to_be_checked = true; + if ( relative ) { + if ( !_lb[index].is_defined() || !_ub[index].is_defined() || + !d.is_defined() || d <= 0.0 || d > 1.0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_POLL_SIZE - relative value" ); + _min_poll_size[index] = d * ( _ub[index] - _lb[index] ); + } + else + _min_poll_size[index] = d; } // set_MIN_POLL_SIZE (2/3): void NOMAD::Parameters::set_MIN_POLL_SIZE ( const NOMAD::Point & delta_p_min , - bool relative ) + bool relative ) { - _to_be_checked = true; - if ( relative ) { - int nd = delta_p_min.size(); - for ( int i = 0 ; i < nd ; ++i ) - set_MIN_POLL_SIZE ( i , delta_p_min[i] , true ); - } - else - _min_poll_size = delta_p_min; + _to_be_checked = true; + if ( relative ) { + int nd = delta_p_min.size(); + for ( int i = 0 ; i < nd ; ++i ) + set_MIN_POLL_SIZE ( i , delta_p_min[i] , true ); + } + else + _min_poll_size = delta_p_min; } // set_MIN_POLL_SIZE (3/3): void NOMAD::Parameters::set_MIN_POLL_SIZE ( const NOMAD::Double & d , bool relative ) { - if ( _dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MIN_POLL_SIZE - undefined dimension" ); - _to_be_checked = true; - if ( relative ) - for ( int i = 0 ; i < _dimension ; ++i ) - set_MIN_POLL_SIZE ( i , d , true ); - else - _min_poll_size = NOMAD::Point ( _dimension , d ); + if ( _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MIN_POLL_SIZE - undefined dimension" ); + _to_be_checked = true; + if ( relative ) + for ( int i = 0 ; i < _dimension ; ++i ) + set_MIN_POLL_SIZE ( i , d , true ); + else + _min_poll_size = NOMAD::Point ( _dimension , d ); } // set_NEIGHBORS_EXE: void NOMAD::Parameters::set_NEIGHBORS_EXE ( const std::string & ne ) { - _to_be_checked = true; - _neighbors_exe = ne; + _to_be_checked = true; + _neighbors_exe = ne; } // set_EXTENDED_POLL_TRIGGER: void NOMAD::Parameters::set_EXTENDED_POLL_TRIGGER ( const NOMAD::Double & ept , - bool relative ) + bool relative ) { - _to_be_checked = true; - - if ( !ept.is_defined() ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: EXTENDED_POLL_TRIGGER (undefined)" ); - - if ( ept <= 0.0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: EXTENDED_POLL_TRIGGER: must be strictly positive" ); + _to_be_checked = true; - _extended_poll_trigger = ept; - _relative_ept = relative; + if ( !ept.is_defined() ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: EXTENDED_POLL_TRIGGER (undefined)" ); + + if ( ept <= 0.0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: EXTENDED_POLL_TRIGGER: must be strictly positive" ); + + _extended_poll_trigger = ept; + _relative_ept = relative; } // set_EXTENDED_POLL_ENABLED: void NOMAD::Parameters::set_EXTENDED_POLL_ENABLED ( bool epe ) { - _to_be_checked = true; - _extended_poll_enabled = epe; + _to_be_checked = true; + _extended_poll_enabled = epe; } // set_USER_CALLS_ENABLED: void NOMAD::Parameters::set_USER_CALLS_ENABLED ( bool uce ) { - _to_be_checked = true; - _user_calls_enabled = uce; + _to_be_checked = true; + _user_calls_enabled = uce; } // set_ASYNCHRONOUS: void NOMAD::Parameters::set_ASYNCHRONOUS ( bool a ) { - _to_be_checked = true; - _asynchronous = a; + _to_be_checked = true; + _asynchronous = a; } // set_MULTI_NB_MADS_RUNS: void NOMAD::Parameters::set_MULTI_NB_MADS_RUNS ( int i ) -{ - if ( i == 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_NB_MADS_RUNS - has been set to zero" ); - - _to_be_checked = true; - _multi_nb_mads_runs = ( i < 0 ) ? -1 : i; +{ + if ( i == 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_NB_MADS_RUNS - has been set to zero" ); + + _to_be_checked = true; + _multi_nb_mads_runs = ( i < 0 ) ? -1 : i; } // set_MULTI_OVERALL_BB_EVAL: void NOMAD::Parameters::set_MULTI_OVERALL_BB_EVAL ( int i ) { - _to_be_checked = true; - _multi_overall_bb_eval = ( i < 0 ) ? -1 : i; -} + _to_be_checked = true; + _multi_overall_bb_eval = ( i < 0 ) ? -1 : i; +} // set_MULTI_USE_DELTA_CRIT: void NOMAD::Parameters::set_MULTI_USE_DELTA_CRIT ( bool b ) { - _to_be_checked = true; - _multi_use_delta_crit = b; + _to_be_checked = true; + _multi_use_delta_crit = b; } // set_MULTI_F_BOUNDS: void NOMAD::Parameters::set_MULTI_F_BOUNDS ( const NOMAD::Point & p ) { - _to_be_checked = true; - if ( p.size() != 4 || p[0] >= p[1] || p[2] >= p[3] ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: MULTI_F_BOUNDS" ); - _multi_f_bounds = p; + _to_be_checked = true; + if ( p.size() != 4 || p[0] >= p[1] || p[2] >= p[3] ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: MULTI_F_BOUNDS" ); + _multi_f_bounds = p; } // set_MULTI_FORMULATION: void NOMAD::Parameters::set_MULTI_FORMULATION ( NOMAD::multi_formulation_type mft ) { - _to_be_checked = true; - _multi_formulation = mft; + _to_be_checked = true; + _multi_formulation = mft; +} + +void NOMAD::Parameters::set_BB_MAX_BLOCK_SIZE ( int max_block_size ) +{ + _to_be_checked = true; + _bb_max_block_size = max_block_size; + + if ( _bb_max_block_size > 1 ) + _eval_points_as_block=true; + + } + + // set_OPPORTUNISTIC_LH: void NOMAD::Parameters::set_OPPORTUNISTIC_LH ( bool opp ) { - _to_be_checked = true; - _opportunistic_LH = opp; - _opp_LH_is_defined = true; + _to_be_checked = true; + _opportunistic_LH = opp; + _opp_LH_is_defined = true; } // set_OPPORTUNISTIC_CACHE_SEARCH: void NOMAD::Parameters::set_OPPORTUNISTIC_CACHE_SEARCH ( bool opp ) { - _to_be_checked = true; - _opportunistic_cache_search = opp; - _opp_CS_is_defined = true; + _to_be_checked = true; + _opportunistic_cache_search = opp; + _opp_CS_is_defined = true; } // set_OPPORTUNISTIC_EVAL: void NOMAD::Parameters::set_OPPORTUNISTIC_EVAL ( bool oe ) { - _to_be_checked = true; - _opportunistic_eval = oe; + _to_be_checked = true; + _opportunistic_eval = oe; } // set_OPPORTUNISTIC_MIN_NB_SUCCESS: void NOMAD::Parameters::set_OPPORTUNISTIC_MIN_NB_SUCCESS ( int mns ) { - _to_be_checked = true; - if ( mns <= 0 ) - mns = -1; - _opportunistic_min_nb_success = mns; + _to_be_checked = true; + if ( mns <= 0 ) + mns = -1; + _opportunistic_min_nb_success = mns; } // set_OPPORTUNISTIC_MIN_EVAL: void NOMAD::Parameters::set_OPPORTUNISTIC_MIN_EVAL ( int me ) { - _to_be_checked = true; - if ( me <= 0 ) - me = -1; - _opportunistic_min_eval = me; + _to_be_checked = true; + if ( me <= 0 ) + me = -1; + _opportunistic_min_eval = me; } // set_OPPORTUNISTIC_MIN_F_IMPRVMT: void NOMAD::Parameters::set_OPPORTUNISTIC_MIN_F_IMPRVMT ( const NOMAD::Double & mfi ) { - _to_be_checked = true; - if ( !mfi.is_defined() || mfi <= 0.0 ) - _opportunistic_min_f_imprvmt.clear(); - else - _opportunistic_min_f_imprvmt = mfi; + _to_be_checked = true; + if ( !mfi.is_defined() || mfi <= 0.0 ) + _opportunistic_min_f_imprvmt.clear(); + else + _opportunistic_min_f_imprvmt = mfi; } // set_OPPORTUNISTIC_LUCKY_EVAL: void NOMAD::Parameters::set_OPPORTUNISTIC_LUCKY_EVAL ( bool le ) { - _to_be_checked = true; - _opportunistic_lucky_eval = le; + _to_be_checked = true; + _opportunistic_lucky_eval = le; } // set_PERIODIC_VARIABLE (1/2): void NOMAD::Parameters::set_PERIODIC_VARIABLE ( int index ) { - if ( _dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: PERIODIC_VARIABLE - undefined dimension" ); - - if ( index < 0 || index >= _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: PERIODIC_VARIABLE - bad variable index" ); - - if ( _periodic_variables.empty() ) - for ( int i = 0 ; i < _dimension ; ++i ) - _periodic_variables.push_back ( false ); - - _periodic_variables[index] = true; - _to_be_checked = true; + if ( _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: PERIODIC_VARIABLE - undefined dimension" ); + + if ( index < 0 || index >= _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: PERIODIC_VARIABLE - bad variable index" ); + + if ( _periodic_variables.empty() ) + for ( int i = 0 ; i < _dimension ; ++i ) + _periodic_variables.push_back ( false ); + + _periodic_variables[index] = true; + _to_be_checked = true; } // set_PERIODIC_VARIABLE (2/2): void NOMAD::Parameters::set_PERIODIC_VARIABLE ( const std::vector<bool> & pv ) { - _to_be_checked = true; - _periodic_variables = pv; + _to_be_checked = true; + _periodic_variables = pv; } // set_VARIABLE_GROUP (1/3): -void NOMAD::Parameters::set_VARIABLE_GROUP ( const std::set<int> & var_indexes , - int halton_seed ) -{ - if ( _dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VARIABLE_GROUP - undefined dimension" ); - - if ( _bb_input_type.empty() || - static_cast<int>(_bb_input_type.size()) != _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VARIABLE_GROUP - undefined blackbox input types" ); - - _to_be_checked = true; - - std::set<NOMAD::direction_type> empty; - - _user_var_groups.insert ( new NOMAD::Variable_Group ( var_indexes , - empty , - empty , - halton_seed , - _out ) ); +void NOMAD::Parameters::set_VARIABLE_GROUP ( const std::set<int> & var_indexes ) +{ + if ( _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VARIABLE_GROUP - undefined dimension" ); + + if ( _bb_input_type.empty() || + static_cast<int>(_bb_input_type.size()) != _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VARIABLE_GROUP - undefined blackbox input types" ); + + _to_be_checked = true; + + std::set<NOMAD::direction_type> empty; + + _user_var_groups.insert ( new NOMAD::Variable_Group ( var_indexes , + empty , + empty , + _out ) ); } // set_VARIABLE_GROUP (2/3): void NOMAD::Parameters::set_VARIABLE_GROUP ( const std::set<int> & var_indexes , const std::set<NOMAD::direction_type> & direction_types , - const std::set<NOMAD::direction_type> & sec_poll_dir_types , - int halton_seed ) -{ - if ( _dimension <= 0 ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VARIABLE_GROUP - undefined dimension" ); - - if ( _bb_input_type.empty() || - static_cast<int>(_bb_input_type.size()) != _dimension ) - throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , - "invalid parameter: VARIABLE_GROUP - undefined blackbox input types" ); - - _to_be_checked = true; - - std::set<NOMAD::direction_type> dt = direction_types; - if ( dt.empty() ) - dt.insert ( NOMAD::ORTHO_NP1_QUAD ); - - _user_var_groups.insert ( new NOMAD::Variable_Group ( var_indexes , - dt , - sec_poll_dir_types , - halton_seed , - _out ) ); + const std::set<NOMAD::direction_type> & sec_poll_dir_types ) +{ + if ( _dimension <= 0 ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VARIABLE_GROUP - undefined dimension" ); + + if ( _bb_input_type.empty() || + static_cast<int>(_bb_input_type.size()) != _dimension ) + throw Invalid_Parameter ( "Parameters.cpp" , __LINE__ , + "invalid parameter: VARIABLE_GROUP - undefined blackbox input types" ); + + _to_be_checked = true; + + std::set<NOMAD::direction_type> dt = direction_types; + if ( dt.empty() ) + dt.insert ( NOMAD::ORTHO_NP1_QUAD ); + + _user_var_groups.insert ( new NOMAD::Variable_Group ( var_indexes , + dt , + sec_poll_dir_types , + _out ) ); } // set_VARIABLE_GROUP (3/3): void NOMAD::Parameters::set_VARIABLE_GROUP ( const std::list<NOMAD::Variable_Group*> & vg ) { - - std::list<NOMAD::Variable_Group*>::const_iterator it , end = vg.end(); - for ( it = vg.begin() ; it != end ; ++it ) - set_VARIABLE_GROUP ( (*it)->get_var_indexes () , - (*it)->get_direction_types () , - (*it)->get_sec_poll_dir_types() , - (*it)->get_halton_seed () ); - + + std::list<NOMAD::Variable_Group*>::const_iterator it , end = vg.end(); + for ( it = vg.begin() ; it != end ; ++it ) + set_VARIABLE_GROUP ( (*it)->get_var_indexes () , + (*it)->get_direction_types () , + (*it)->get_sec_poll_dir_types() + ); + } /*-----------------------------------------------*/ @@ -7371,9 +7718,9 @@ void NOMAD::Parameters::set_VARIABLE_GROUP /*-----------------------------------------------*/ void NOMAD::Parameters::help ( const std::string & param_name,bool developer ) const { - std::list<std::string> ls; - ls.push_back ( param_name ); - help ( ls,developer); + std::list<std::string> ls; + ls.push_back ( param_name ); + help ( ls,developer); } /*-----------------------------------------------*/ @@ -7381,13 +7728,13 @@ void NOMAD::Parameters::help ( const std::string & param_name,bool developer ) c /*-----------------------------------------------*/ void NOMAD::Parameters::help ( int argc , char ** argv , bool developer ) const { - std::list<std::string> ls; - if ( argc <= 2 ) - ls.push_back ( "ALL" ); - else - for ( int i = 2 ; i < argc ; ++i ) - ls.push_back ( argv[i] ); - help(ls,developer); + std::list<std::string> ls; + if ( argc <= 2 ) + ls.push_back ( "ALL" ); + else + for ( int i = 2 ; i < argc ; ++i ) + ls.push_back ( argv[i] ); + help(ls,developer); } /*-----------------------------------------------*/ @@ -7396,125 +7743,125 @@ void NOMAD::Parameters::help ( int argc , char ** argv , bool developer ) const void NOMAD::Parameters::help ( const std::list<std::string> & pnames,bool developer ) const { #ifdef USE_MPI - if ( !NOMAD::Slave::is_master() ) - return; + if ( !NOMAD::Slave::is_master() ) + return; #endif - - // initial display: - _out << std::endl - << NOMAD::open_block ( "NOMAD - help on parameters - see more details in " - + NOMAD::USER_GUIDE_FILE ); - - std::list<std::string> param_names = pnames; - NOMAD::toupper ( param_names ); - - bool chk = false; - bool display_all = false; - - // if ( NOMAD::string_find ( "ALL PARAMS PARAMETERS EVERYTHING NOMAD" , param_names ) ) - if ( NOMAD::string_match ( "ALL", param_names) || NOMAD::string_match( "PARAMS", param_names ) || - NOMAD::string_match ( "PARAMETER", param_names) || NOMAD::string_match ( "PARAM", param_names) || - NOMAD::string_match ( "NOMAD" , param_names ) || NOMAD::string_match ( "EVERYTHING", param_names) ) - display_all = true; - - const char registered_key_basic[]="2N ANGLES AVG BARRIER BASIC BASIC BB_EXE BB_INPUT_TYPE BB_OUTPUT_TYPE BI-MADS BI-OBJECTIVES BIMADS \ - BINARY BIOBJECTIVES BLACK-BOXES BLACKBOXES BOUNDS CACHE BBEVAL CACHE_FILE CNT_EVAL CONSTRAINTS CONTINUOUS COUNT DEBUG DELTA_0 DIMENSION \ - DIRECTION_TYPE DIRECTION_TYPES DIRECTIONS DIRECTIONS_TYPES DIRECTORY DISPLAY_ALL_EVAL DISPLAY_DEGREES DISPLAY_STATS EVALUATIONS \ - EXECUTABLE F_TARGET FILES FILTER FORMAT GPS h(x) HISTORY_FILE INITIAL_MESH_SIZE INTEGER LATEX LATIN-HYPERCUBE LB LH_SEARCH LOWER_BOUND \ - LT LT-MADS LTMADS MADS MAX_BB_EVAL MAX_TIME MAXIMUM MINIMIZE MODEL MODELS MULTI-OBJECTIVE MULTIOBJECTIVES N+1 NUMBER OPTIMIZE ORTHO \ - ORTHO-MADS ORTHOMADS OUTPUTS PATH PB PEB POINT POLL PROGRESSIVE-BARRIER RANDOM SAMPLING SCREEN SCREEN SOLUTION_FILE STARTING STATIC \ - STATS STATS_FILE STOPPING SUM TEMPORARY TERMINATES TERMINATION TMP_DIR UB UNIFORM UPPER_BOUNDS VARIABLES X0"; - - const char registered_key_advanced[]="ADD_SEED_TO_FILE_NAMES ADVANCED ASYNCHRONOUS BB_INPUT_INCLUDE_SEED BB_INPUT_INCLUDE_TAG \ - BB_REDIRECTION BBEVAL BI-MADS BI-OBJECTIVES BIMADS BIOBJECTIVES BLACK-BOXES BLACKBOXES BLOCKS BOUNDS CACHE CACHE_FILE CACHE_SAVE_PERIOD \ - CACHE_SEARCH CATEGORICAL CLOSED_BRACES CONSTRAINTS CYCLIC DELTA DELTA^P DETERMINISTIC DIRECTIONS DISABLE DISABLE_MODEL DISABLE_MODELS \ - DISPLAY ELL ELL_0 EVALUATIONS EXECUTABLE EXTENDED_POLL EXTENDED_POLL_DISABLED EXTENDED_POLL_ENABLED EXTENDED_POLL_TRIGGER FEASIBILITY \ - FILES FILTER FIXED_VARIABLE FROBENIUS GLOBAL GROUPS H_MAX_0 H_MIN H_NORM HALTON_SEED HAS_SGTE HMAX HMAX_0 HMIN INDENTATION INF_STR \ - INFINITY INITIAL_MESH_INDEX INTERPOLATION ITERATIONS L_0 L_INF L0 L1 L2 LATIN-HYPERCUBE LB LIBRARY LINF LT-MADS LTMADS MADS \ - MAX_CACHE_MEMORY MAX_CONSECUTIVE_FAILED_ITERATIONS MAX_EVAL MAX_ITERATIONS MAX_MESH_INDEX MAX_SGTE_EVAL MAX_SIM_BB_EVAL MAXIMUM \ - MB MEGA-BYTES MEGABYTES MESH MESH_COARSENING_EXPONENT MESH_REFINING_EXPONENT MESH_UPDATE_BASIS META-HEURISTICS METAHEURISTICS MFN \ - MIN_MESH_SIZE MIN_POLL_SIZE MINIMUM MIXED MODEL MODEL_EVAL_SORT MODEL_ORDERING MODEL_SEARCH MODEL_SEARCH_OPTIMISTIC MODELS MPI \ - MULTI_F_BOUNDS MULTI_NB_MADS_RUNS MULTI_OVERALL_BB_EVAL MULTI-OBJECTIVES MULTIOBJECTIVES MVP N+1 NEIGHBORHOOD NEIGHBORHOODS NEIGHBORS_EXE \ - NEIGHBOURHOODS NEIGHBOURS NUMBER OPEN_BRACES OPPORTUNISTIC_CACHE_SEARCH OPPORTUNISTIC_EVAL OPPORTUNISTIC_LH OPPORTUNISTIC_MIN_EVAL \ - OPTIMISTIC ORTHO ORTHO-MADS ORTHOGONAL ORTHOMADS OUTPUT OUTPUTS PARALLELISM PARETO PB PEB PERIODIC_VARIABLE PMADS POINT_DISPLAY_LIMIT \ - POLL PRECISION PROGRESSIVE-BARRIER PROJECTION PSD-MADS PSDMADS QUAD QUADRATIC RAM RANDOM REALS REGRESSION RHO SAMPLING SCALE SCALING \ - SEARCH SEED SGTE_CACHE_FILE SGTE_COST SGTE_EVAL_SORT SGTE_EXE SGTE_ORDERING SGTES SIMULATED SNAP_TO_BOUNDS SPECULATIVE_SEARCH \ - STAT_SUM_TARGET STATS STOP_IF_FEASIBLE SUCCESSES SURF SURROGATES TABULATIONS TAU TERMINATES TERMINATION TGP TGPMODEL_SEARCH TRIGGER \ - UB UNDEF_STR UNDEFINED USER_CALLS_DISABLED USER_CALLS_ENABLED VARIABLE_GROUP VARIABLES VNS_SEARCH W- W+"; - - const char registered_key_developer[]="BI-MADS BI-OBJECTIVES BIMADS BIOBJECTIVES BLACK-BOXES BLACK-BOXES COMPARISONS DEVELOPER \ - DIRECTIONS EPSILON EVALUATIONS FROBENIUS IMPROVEMENT INTERPOLATION L_CURVE_TARGET MADS MFN MODEL MODEL_EVAL_SORT_CAUTIOUS MODEL_ORDERING \ - MODEL_QUAD_MAX_Y_SIZE MODEL_QUAD_MIN_Y_SIZE MODEL_QUAD_RADIUS_FACTOR MODEL_QUAD_USE_WP MODEL_SEARCH MODEL_SEARCH_MAX_TRIAL_PTS \ - MODEL_SEARCH_PROJ_TO_MESH MODEL_TGP_MODE MODEL_TGP_REUSE_MODEL MODELS MULTI_FORMULATION MULTI_USE_DELTA_CRITERION MULTI-OBJECTIVES \ - MULTIOBJECTIVES N+1 NP1 OBJECTIVE OPPORTUNISTIC_LUCKY_EVAL OPPORTUNISTIC_MIN_F_IMPRVMT OPPORTUNISTIC_MIN_NB_SUCCESSES OPT_ONLY_SGTES \ - ORTHO PARETO PB PEB POLL PRECISION PROGRESSIVE-BARRIER PROJECTION QUAD QUADRATIC REALS REGRESSION SEC_POLL_DIR_TYPES SGTES STOPPING \ - SUCCESSES SURROGATES TERMINATES TERMINATION TGP WELL-POISEDNESS"; - - - if ( display_all || NOMAD::string_find ( registered_key_basic, param_names ) ) - { - _out << "--------------------------------------------------------------" << endl; - _out << "-----------------------BASIC PARAMETERS-----------------------" << endl; - _out << "--------------------------------------------------------------" << endl; - } - - - // BB_EXE: - // ------- - if ( display_all || NOMAD::string_find ( "BB_EXE BASIC BLACK-BOXES BLACKBOXES \ + + // initial display: + _out << std::endl + << NOMAD::open_block ( "NOMAD - help on parameters - see more details in " + + NOMAD::USER_GUIDE_FILE ); + + std::list<std::string> param_names = pnames; + NOMAD::toupper ( param_names ); + + bool chk = false; + bool display_all = false; + + if ( NOMAD::string_match ( "ALL", param_names) || NOMAD::string_match( "PARAMS", param_names ) || + NOMAD::string_match ( "PARAMETER", param_names) || NOMAD::string_match ( "PARAM", param_names) || + NOMAD::string_match ( "NOMAD" , param_names ) || NOMAD::string_match ( "EVERYTHING", param_names) ) + display_all = true; + + + const char registered_key_basic[]="2N ANGLES AVG BARRIER BASIC BASIC BB_EXE BB_INPUT_TYPE BB_OUTPUT_TYPE BI-MADS BI-OBJECTIVES BIMADS \ + BINARY BIOBJECTIVES BLACK-BOXES BLACKBOXES BOUNDS CACHE BBEVAL CACHE_FILE CNT_EVAL CONSTRAINTS CONTINUOUS COUNT DEBUG DELTA_0 DIMENSION \ + DIRECTION_TYPE DIRECTION_TYPES DIRECTIONS DIRECTIONS_TYPES DIRECTORY DISPLAY_ALL_EVAL DISPLAY_DEGREES DISPLAY_STATS EVALUATIONS \ + EXECUTABLE F_TARGET FILES FILTER FORMAT GPS h(x) HISTORY_FILE INITIAL_MESH_SIZE INTEGER LATEX LATIN-HYPERCUBE LB LH_SEARCH LOWER_BOUND \ + LT LT-MADS LTMADS MADS MAX_BB_EVAL MAX_TIME MAXIMUM MINIMIZE MODEL MODELS MULTI-OBJECTIVE MULTIOBJECTIVES N+1 NUMBER OPTIMIZE ORTHO \ + ORTHO-MADS ORTHOMADS OUTPUTS PATH PB PEB POINT POLL PROGRESSIVE-BARRIER RANDOM SAMPLING SCREEN SCREEN SOLUTION_FILE STARTING STATIC \ + STATS STATS_FILE STOPPING SUM TEMPORARY TERMINATES TERMINATION TMP_DIR UB UNIFORM UPPER_BOUNDS VARIABLES X0"; + + const char registered_key_advanced[]="ADD_SEED_TO_FILE_NAMES ADVANCED ANISOTROPIC_MESH ASYNCHRONOUS BB_INPUT_INCLUDE_SEED BB_INPUT_INCLUDE_TAG \ + BB_REDIRECTION BBEVAL BI-MADS BI-OBJECTIVES BIMADS BIOBJECTIVES BLACK-BOXES BLACKBOXES BLOCKS BOUNDS CACHE CACHE_FILE CACHE_SAVE_PERIOD \ + CACHE_SEARCH CATEGORICAL CLOSED_BRACES CONSTRAINTS CYCLIC DELTA DETERMINISTIC DIRECTIONS DISABLE DISABLE_EVAL_SORT DISABLE_MODEL DISABLE_MODELS \ + DISPLAY ELL ELL_0 BB_MAX_BLOCK_SIZE EVALUATIONS EXECUTABLE EXTENDED_POLL EXTENDED_POLL_DISABLED EXTENDED_POLL_ENABLED EXTENDED_POLL_TRIGGER FEASIBILITY \ + FILES FILTER FIXED_VARIABLE FROBENIUS GLOBAL GROUPS H_MAX_0 H_MIN H_NORM HAS_SGTE HMAX HMAX_0 HMIN INDENTATION INF_STR \ + INFINITY INTERPOLATION ITERATIONS L_0 L_INF L0 L1 L2 LATIN-HYPERCUBE LB LIBRARY LINF LT-MADS LTMADS MADS \ + MAX_CACHE_MEMORY MAX_CONSECUTIVE_FAILED_ITERATIONS MAX_EVAL MAX_ITERATIONS MAX_SGTE_EVAL MAX_SIM_BB_EVAL MAXIMUM \ + MB MEGA-BYTES MEGABYTES MESH MESH_COARSENING_EXPONENT MESH_REFINING_EXPONENT MESH_UPDATE_BASIS META-HEURISTICS METAHEURISTICS MFN \ + MIN_MESH_SIZE MIN_POLL_SIZE MINIMUM MIXED MODEL MODEL_EVAL_SORT MODEL_ORDERING MODEL_SEARCH MODEL_SEARCH_OPTIMISTIC MODELS MPI \ + MULTI_F_BOUNDS MULTI_NB_MADS_RUNS MULTI_OVERALL_BB_EVAL MULTI-OBJECTIVES MULTIOBJECTIVES MVP N+1 NEIGHBORHOOD NEIGHBORHOODS NEIGHBORS_EXE \ + NEIGHBOURHOODS NEIGHBOURS NUMBER OPEN_BRACES OPPORTUNISTIC_CACHE_SEARCH OPPORTUNISTIC_EVAL OPPORTUNISTIC_LH OPPORTUNISTIC_MIN_EVAL \ + OPTIMISTIC ORTHO ORTHO-MADS ORTHOGONAL ORTHOMADS OUTPUT OUTPUTS PARALLELISM PARETO PB PEB PERIODIC_VARIABLE PMADS POINT_DISPLAY_LIMIT \ + POLL POLL_UPDATE_BASIS PRECISION PROGRESSIVE-BARRIER PROJECTION PSD-MADS PSDMADS QUAD QUADRATIC RAM RANDOM REALS REGRESSION RHO SAMPLING SCALE SCALING \ + SEARCH SEED SGTE_CACHE_FILE SGTE_COST SGTE_EVAL_SORT SGTE_EXE SGTE_ORDERING SGTES SIMULATED SNAP_TO_BOUNDS SPECULATIVE_SEARCH \ + STAT_SUM_TARGET STATS STOP_IF_FEASIBLE SUCCESSES SURF SURROGATES TABULATIONS TAU TERMINATES TERMINATION TGP TGPMODEL_SEARCH TRIGGER \ + UB UNDEF_STR UNDEFINED USER_CALLS_DISABLED USER_CALLS_ENABLED VARIABLE_GROUP VARIABLES VNS_SEARCH W- W+"; + + const char registered_key_developer[]="BI-MADS BI-OBJECTIVES BIMADS BIOBJECTIVES BLACK-BOXES BLACK-BOXES COMPARISONS DEVELOPER \ + DIRECTIONS EPSILON EVALUATIONS FROBENIUS INITIAL_MESH_INDEX IMPROVEMENT INTERPOLATION L_CURVE_TARGET MADS MFN MODEL MODEL_EVAL_SORT_CAUTIOUS MODEL_ORDERING \ + MODEL_QUAD_MAX_Y_SIZE MODEL_QUAD_MIN_Y_SIZE MODEL_QUAD_RADIUS_FACTOR MODEL_QUAD_USE_WP MODEL_SEARCH MODEL_SEARCH_MAX_TRIAL_PTS \ + MODEL_SEARCH_PROJ_TO_MESH MODEL_TGP_MODE MODEL_TGP_REUSE_MODEL MODELS MULTI_FORMULATION MULTI_USE_DELTA_CRITERION MULTI-OBJECTIVES \ + MULTIOBJECTIVES N+1 NP1 OBJECTIVE OPPORTUNISTIC_LUCKY_EVAL OPPORTUNISTIC_MIN_F_IMPRVMT OPPORTUNISTIC_MIN_NB_SUCCESSES OPT_ONLY_SGTES \ + ORTHO PARETO PB PEB POLL PRECISION PROGRESSIVE-BARRIER PROJECTION QUAD QUADRATIC REALS REGRESSION SEC_POLL_DIR_TYPES SGTES STOPPING \ + SUCCESSES SURROGATES TERMINATES TERMINATION TGP USE_SMESH WELL-POISEDNESS"; + + + if ( display_all || NOMAD::string_find ( registered_key_basic, param_names ) ) + { + _out << "--------------------------------------------------------------" << endl; + _out << "-----------------------BASIC PARAMETERS-----------------------" << endl; + _out << "--------------------------------------------------------------" << endl; + } + + + // BB_EXE: + // ------- + if ( display_all || NOMAD::string_find ( "BB_EXE BASIC BLACK-BOXES BLACKBOXES \ EXECUTABLE FILES BI-OBJECTIVES \ BIOBJECTIVES MULTIOBJECTIVES \ BIMADS BI-MADS \ MULTI-OBJECTIVES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "BB_EXE (basic)" ) << std::endl - << ". blackbox executable names" << std::endl - << ". list of strings" << std::endl - << ". no default, required (except in library mode)" << std::endl - << ". several executables can be used" << std::endl - << ". one executable can give several outputs" << std::endl - << ". use \' or \", and \'$\', to specify names or" << std::endl - << " commands with spaces" << std::endl - << ". when the \'$\' character is put in first" << std::endl - << " position of a string, it is considered" << std::endl - << " as global and no path will be added" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "BB_EXE bb.exe" << std::endl - << "BB_EXE bb1.exe bb2.exe" << std::endl - << "BB_EXE \'$nice bb.exe\'" << std::endl - << "BB_EXE \'$python bb.py\'" << std::endl - << NOMAD::close_block() - << NOMAD::close_block(); - chk = true; - } - - // BB_INPUT_TYPE: - // -------------- - if ( display_all || NOMAD::string_find ( "BB_INPUT_TYPE BLACK-BOXES BLACKBOXES \ + _out << std::endl + << NOMAD::open_block ( "BB_EXE (basic)" ) << std::endl + << ". blackbox executable names" << std::endl + << ". list of strings" << std::endl + << ". no default, required (except in library mode)" << std::endl + << ". several executables can be used" << std::endl + << ". one executable can give several outputs" << std::endl + << ". use \' or \", and \'$\', to specify names or" << std::endl + << " commands with spaces" << std::endl + << ". when the \'$\' character is put in first" << std::endl + << " position of a string, it is considered" << std::endl + << " as global and no path will be added" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "BB_EXE bb.exe" << std::endl + << "BB_EXE bb1.exe bb2.exe" << std::endl + << "BB_EXE \'$nice bb.exe\'" << std::endl + << "BB_EXE \'$python bb.py\'" << std::endl + << NOMAD::close_block() + << NOMAD::close_block(); + chk = true; + } + + // BB_INPUT_TYPE: + // -------------- + if ( display_all || NOMAD::string_find ( "BB_INPUT_TYPE BLACK-BOXES BLACKBOXES \ BASIC VARIABLES CONTINUOUS \ INTEGER BINARY" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "BB_INPUT_TYPE (basic)" ) << std::endl - << ". blackbox input types" << std::endl - << ". list of types for each variable" << std::endl - << ". " << NOMAD::open_block ( "available types" ) - << "B: binary" << std::endl - << "C: categorical" << std::endl - << "I: integer" << std::endl - << "R: continuous" << std::endl - << NOMAD::close_block() - << ". default: * R (all continuous)" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "BB_INPUT_TYPE ( R I B ) # for all 3 variables" << std::endl - << "BB_INPUT_TYPE 1-3 B # variables 1 to 3 are binary" << std::endl - << "BB_INPUT_TYPE 0 I # first variable is integer" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - // BB_OUTPUT_TYPE: - // --------------- - if ( display_all || NOMAD::string_find ( "BB_OUTPUT_TYPE BASIC CONSTRAINTS \ + _out << std::endl + << NOMAD::open_block ( "BB_INPUT_TYPE (basic)" ) << std::endl + << ". blackbox input types" << std::endl + << ". list of types for each variable" << std::endl + << ". " << NOMAD::open_block ( "available types" ) + << "B: binary" << std::endl + << "C: categorical" << std::endl + << "I: integer" << std::endl + << "R: continuous" << std::endl + << NOMAD::close_block() + << ". default: * R (all continuous)" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "BB_INPUT_TYPE ( R I B ) # for all 3 variables" << std::endl + << "BB_INPUT_TYPE 1-3 B # variables 1 to 3 are binary" << std::endl + << "BB_INPUT_TYPE 0 I # first variable is integer" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + // BB_OUTPUT_TYPE: + // --------------- + if ( display_all || NOMAD::string_find ( "BB_OUTPUT_TYPE BASIC CONSTRAINTS \ BLACK-BOXES BLACKBOXES \ BARRIER STATS BI-OBJECTIVES h(x) \ PB PEB FILTER STATS SUM AVG CNT_EVAL \ @@ -7523,1991 +7870,2069 @@ void NOMAD::Parameters::help ( const std::list<std::string> & pnames,bool develo BIOBJECTIVES MULTIOBJECTIVES \ BI-MADS BIMADS \ OPTIMIZE" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "BB_OUTPUT_TYPE (basic)" ) << std::endl - << ". blackbox output types" << std::endl - << ". list of types for each blackbox output" << std::endl - << ". " << NOMAD::open_block ( "available types" ) << std::endl - << "OBJ : objective value to minimize" << std::endl - << " (define twice for bi-objective)" << std::endl - << "CSTR or PB: constraint <= 0 treated with" << std::endl - << " Progressive Barrier (PB)" << std::endl - << "EB : constraint <= 0 treated with" << std::endl - << " Extreme Barrier (EB)" << std::endl - << "PEB : constraint <= 0 treated with" << std::endl - << " hybrid PB/EB" << std::endl - << "F : constraint <= 0 treated with Filter" << std::endl - << "CNT_EVAL : 0 or 1 output: count or not the" << std::endl - << " evaluation" << std::endl - << "STAT_AVG : NOMAD will compute the average" << std::endl - << " value for this output" << std::endl - << "STAT_SUM : the same for the sum" << std::endl - << "NOTHING : the output is ignored" << std::endl - << "- : same as \'NOTHING\'" << std::endl - << NOMAD::close_block() - << ". STAT_SUM and STAT_AVG outputs have to be unique;" << std::endl - << " they are updated at every new blackbox evaluation" << std::endl - << ". no default, required" << std::endl - << ". see user guide for blackbox output formats" << std::endl - << ". equality constraints are not natively supported" << std::endl - << ". see parameters LOWER_BOUND and UPPER_BOUND for" << std::endl - << " bound constraints" << std::endl - << ". " << NOMAD::open_block ( "examples" ) << std::endl - << "BB_EXE bb.exe # these two lines define" << std::endl - << "BB_OUTPUT_TYPE OBJ EB EB # that bb.exe outputs" << std::endl - << " # three values" << std::endl - << std::endl - << "BB_EXE bb1.exe bb2.exe bb2.exe # bb1.exe outputs the" << std::endl - << "BB_OUTPUT_TYPE OBJ EB EB # objective and bb2.exe" << std::endl - << " # two constraints" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - - // CACHE_FILE: - // ----------- - if ( display_all || NOMAD::string_find ( "CACHE_FILE BASIC \ + _out << std::endl + << NOMAD::open_block ( "BB_OUTPUT_TYPE (basic)" ) << std::endl + << ". blackbox output types" << std::endl + << ". list of types for each blackbox output" << std::endl + << ". " << NOMAD::open_block ( "available types" ) << std::endl + << "OBJ : objective value to minimize" << std::endl + << " (define twice for bi-objective)" << std::endl + << "CSTR or PB: constraint <= 0 treated with" << std::endl + << " Progressive Barrier (PB)" << std::endl + << "EB : constraint <= 0 treated with" << std::endl + << " Extreme Barrier (EB)" << std::endl + << "PEB : constraint <= 0 treated with" << std::endl + << " hybrid PB/EB" << std::endl + << "F : constraint <= 0 treated with Filter" << std::endl + << "CNT_EVAL : 0 or 1 output: count or not the" << std::endl + << " evaluation" << std::endl + << "STAT_AVG : NOMAD will compute the average" << std::endl + << " value for this output" << std::endl + << "STAT_SUM : the same for the sum" << std::endl + << "NOTHING : the output is ignored" << std::endl + << "- : same as \'NOTHING\'" << std::endl + << NOMAD::close_block() + << ". STAT_SUM and STAT_AVG outputs have to be unique;" << std::endl + << " they are updated at every new blackbox evaluation" << std::endl + << ". no default, required" << std::endl + << ". see user guide for blackbox output formats" << std::endl + << ". equality constraints are not natively supported" << std::endl + << ". see parameters LOWER_BOUND and UPPER_BOUND for" << std::endl + << " bound constraints" << std::endl + << ". " << NOMAD::open_block ( "examples" ) << std::endl + << "BB_EXE bb.exe # these two lines define" << std::endl + << "BB_OUTPUT_TYPE OBJ EB EB # that bb.exe outputs" << std::endl + << " # three values" << std::endl + << std::endl + << "BB_EXE bb1.exe bb2.exe bb2.exe # bb1.exe outputs the" << std::endl + << "BB_OUTPUT_TYPE OBJ EB EB # objective and bb2.exe" << std::endl + << " # two constraints" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + + // CACHE_FILE: + // ----------- + if ( display_all || NOMAD::string_find ( "CACHE_FILE BASIC \ FILES OUTPUTS" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "CACHE_FILE (basic)" ) << std::endl - << ". cache file; if the specified file" << std::endl - << " does not exist, it will be created" << std::endl - << ". argument: one string" << std::endl - << ". no default" << std::endl - << ". points already in the file will be" << std::endl - << " tagged as true evaluations" << std::endl - << ". example: CACHE_FILE cache.bin" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // DIMENSION: - // ---------- - if ( display_all || NOMAD::string_find ( "DIMENSION BASIC VARIABLES" , - param_names ) ) + _out << std::endl + << NOMAD::open_block ( "CACHE_FILE (basic)" ) << std::endl + << ". cache file; if the specified file" << std::endl + << " does not exist, it will be created" << std::endl + << ". argument: one string" << std::endl + << ". no default" << std::endl + << ". points already in the file will be" << std::endl + << " tagged as true evaluations" << std::endl + << ". example: CACHE_FILE cache.bin" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // DIMENSION: + // ---------- + if ( display_all || NOMAD::string_find ( "DIMENSION BASIC VARIABLES" , + param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "DIMENSION (basic)" ) << std::endl - << ". number of variables" << std::endl - << ". argument: one positive integer" << std::endl - << ". no default, required" << std::endl - << ". example: DIMENSION 3" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // DIRECTION_TYPE: - // --------------- - if ( display_all || NOMAD::string_find ( "DIRECTION_TYPES BASIC DIRECTION_TYPE DIRECTIONS_TYPES \ + _out << std::endl + << NOMAD::open_block ( "DIMENSION (basic)" ) << std::endl + << ". number of variables" << std::endl + << ". argument: one positive integer" << std::endl + << ". no default, required" << std::endl + << ". example: DIMENSION 3" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // DIRECTION_TYPE: + // --------------- + if ( display_all || NOMAD::string_find ( "DIRECTION_TYPES BASIC DIRECTION_TYPE DIRECTIONS_TYPES \ BASIC ORTHO LT GPS \ MADS DIRECTIONS 2N N+1 POLL MODEL MODELS \ ORTHOMADS ORTHO-MADS LTMADS LT-MADS \ RANDOM STATIC UNIFORM ANGLES" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "DIRECTION_TYPE (basic)" ) << std::endl - << ". types of directions used in the poll step" << std::endl - << ". arguments: direction types (see user" << std::endl - << " guide for available types)" << std::endl - << ". default: ORTHO (OrthoMADS n+1 (QUAD model used for " << std::endl - << " (n+1)th dir)." << std::endl - << ". several direction types can be defined" << std::endl - << " at the same time (one direction per line)" << std::endl - << ". " << NOMAD::open_block ( "examples" ) << std::endl - << "DIRECTION_TYPE ORTHO 1 # OrthoMADS, 1" << std::endl - << "DIRECTION_TYPE ORTHO 2 # OrthoMADS, 2" << std::endl - << "DIRECTION_TYPE ORTHO N+1 # OrthoMADS, n+1" << std::endl - << " # (QUAD model used"<< std::endl - << " # for (n+1)th dir)"<< std::endl - << "DIRECTION_TYPE ORTHO N+1 QUAD # OrthoMADS, n+1" << std::endl - << " # (QUAD model used"<< std::endl - << " # for (n+1)th dir)"<< std::endl - << "DIRECTION_TYPE ORTHO N+1 NEG # OrthoMADS, n+1" << std::endl - << " # ((n+1)th dir = " << std::endl - << " # negative sum of" << std::endl - << " # n first dirs)" << std::endl - << "DIRECTION_TYPE ORTHO # OrthoMADS, n+1 QUAD " << std::endl - << "DIRECTION_TYPE ORTHO 2N # OrthoMADS, 2n" << std::endl - << "DIRECTION_TYPE LT 1 # LT-MADS, 1" << std::endl - << "DIRECTION_TYPE LT 2 # LT-MADS, 2" << std::endl - << "DIRECTION_TYPE LT N+1 # LT-MADS, n+1" << std::endl - << "DIRECTION_TYPE LT # LT-MADS, 2n" << std::endl - << "DIRECTION_TYPE LT 2N # LT-MADS, 2n" << std::endl - << "DIRECTION_TYPE GPS BINARY or BIN # GPS, bin var" << std::endl - << "DIRECTION_TYPE GPS N+1 # GPS, n+1," << std::endl - << " # static" << std::endl - << "DIRECTION_TYPE GPS N+1 STATIC # GPS, n+1," << std::endl - << " # static" << std::endl - << "DIRECTION_TYPE GPS N+1 STATIC UNIFORM # GPS, n+1," << std::endl - << " # static, unif" << std::endl - << "DIRECTION_TYPE GPS N+1 RAND # GPS, n+1," << std::endl - << " # rand" << std::endl - << "DIRECTION_TYPE GPS N+1 RAND UNIFORM # GPS, n+1," << std::endl - << " # rand, unif" << std::endl - << "DIRECTION_TYPE GPS # GPS, 2n," << std::endl - << " # static" << std::endl - << "DIRECTION_TYPE GPS 2N # GPS, 2n," << std::endl - << " # static" << std::endl - << "DIRECTION_TYPE GPS 2N STATIC # GPS, 2n," << std::endl - << " # static" << std::endl - << "DIRECTION_TYPE GPS 2N RAND # GPS, 2n," << std::endl - << " # rand" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - // DISPLAY_ALL_EVAL: - // ----------------- - if ( display_all || NOMAD::string_find ( "DISPLAY_ALL_EVAL DISPLAY_STATS \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "DIRECTION_TYPE (basic)" ) << std::endl + << ". types of directions used in the poll step" << std::endl + << ". arguments: direction types (see user" << std::endl + << " guide for available types)" << std::endl + << ". default: ORTHO (OrthoMADS n+1 (QUAD model used for " << std::endl + << " (n+1)th dir)." << std::endl + << ". several direction types can be defined" << std::endl + << " at the same time (one direction per line)" << std::endl + << ". " << NOMAD::open_block ( "examples" ) << std::endl + << "DIRECTION_TYPE ORTHO 1 # OrthoMADS, 1" << std::endl + << "DIRECTION_TYPE ORTHO 2 # OrthoMADS, 2" << std::endl + << "DIRECTION_TYPE ORTHO N+1 # OrthoMADS, n+1" << std::endl + << " # (QUAD model used"<< std::endl + << " # for (n+1)th dir)"<< std::endl + << "DIRECTION_TYPE ORTHO N+1 QUAD # OrthoMADS, n+1" << std::endl + << " # (QUAD model used"<< std::endl + << " # for (n+1)th dir)"<< std::endl + << "DIRECTION_TYPE ORTHO N+1 NEG # OrthoMADS, n+1" << std::endl + << " # ((n+1)th dir = " << std::endl + << " # negative sum of" << std::endl + << " # n first dirs)" << std::endl + << "DIRECTION_TYPE ORTHO # OrthoMADS, n+1 QUAD " << std::endl + << "DIRECTION_TYPE ORTHO 2N # OrthoMADS, 2n" << std::endl + << "DIRECTION_TYPE LT 1 # LT-MADS, 1" << std::endl + << "DIRECTION_TYPE LT 2 # LT-MADS, 2" << std::endl + << "DIRECTION_TYPE LT N+1 # LT-MADS, n+1" << std::endl + << "DIRECTION_TYPE LT # LT-MADS, 2n" << std::endl + << "DIRECTION_TYPE LT 2N # LT-MADS, 2n" << std::endl + << "DIRECTION_TYPE GPS BINARY or BIN # GPS, bin var" << std::endl + << "DIRECTION_TYPE GPS N+1 # GPS, n+1," << std::endl + << " # static" << std::endl + << "DIRECTION_TYPE GPS N+1 STATIC # GPS, n+1," << std::endl + << " # static" << std::endl + << "DIRECTION_TYPE GPS N+1 STATIC UNIFORM # GPS, n+1," << std::endl + << " # static, unif" << std::endl + << "DIRECTION_TYPE GPS N+1 RAND # GPS, n+1," << std::endl + << " # rand" << std::endl + << "DIRECTION_TYPE GPS N+1 RAND UNIFORM # GPS, n+1," << std::endl + << " # rand, unif" << std::endl + << "DIRECTION_TYPE GPS # GPS, 2n," << std::endl + << " # static" << std::endl + << "DIRECTION_TYPE GPS 2N # GPS, 2n," << std::endl + << " # static" << std::endl + << "DIRECTION_TYPE GPS 2N STATIC # GPS, 2n," << std::endl + << " # static" << std::endl + << "DIRECTION_TYPE GPS 2N RAND # GPS, 2n," << std::endl + << " # rand" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + // DISPLAY_ALL_EVAL: + // ----------------- + if ( display_all || NOMAD::string_find ( "DISPLAY_ALL_EVAL DISPLAY_STATS \ STATS_FILE BASIC" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "DISPLAY_ALL_EVAL (basic)" ) << std::endl - << ". if \'yes\', more points are displayed with" << std::endl - << " parameters DISPLAY_STATS and STATS_FILE" << std::endl - << ". points of the phase one with EB constraints" << std::endl - << " are not displayed" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'no\'" << std::endl - << ". example: DISPLAY_ALL_EVAL yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - - // DISPLAY_DEGREE: - // --------------- - if ( display_all || NOMAD::string_find ( "DISPLAY_DEGREES OUTPUTS \ + _out << std::endl + << NOMAD::open_block ( "DISPLAY_ALL_EVAL (basic)" ) << std::endl + << ". if \'yes\', more points are displayed with" << std::endl + << " parameters DISPLAY_STATS and STATS_FILE" << std::endl + << ". points of the phase one with EB constraints" << std::endl + << " are not displayed" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'no\'" << std::endl + << ". example: DISPLAY_ALL_EVAL yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + + // DISPLAY_DEGREE: + // --------------- + if ( display_all || NOMAD::string_find ( "DISPLAY_DEGREES OUTPUTS \ SCREEN DEBUG BASIC" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "DISPLAY_DEGREE (basic)" ) << std::endl - << ". " << NOMAD::open_block ( "display degree" ) - << "0: no display" << std::endl - << "1: minimal display" << std::endl - << "2: normal display" << std::endl - << "3: full display" << std::endl - << NOMAD::close_block() - << ". argument: one integer in {0, 1, 2, 3} (basic)" << std::endl - << " or one string in {\'NO\', \'NO_DISPLAY\', \'MIN\'," << std::endl - << " \'MINIMAL\', \'MINIMAL_DISPLAY\' ,\'NORMAL\'," - << std::endl - << " \'NORMAL_DISPLAY\', \'FULL\'," << std::endl - << " \'FULL_DISPLAY\'}" << std::endl - << " or one string composed of 4 integers each in" << std::endl - << " { 0, 1, 2 ,3} (advanced)" << std::endl - << ". default: 2" << std::endl - << ". " - << NOMAD::open_block("advanced use with 4 digits (see user guide for details)") - << "#1 general display degree (before and after" << std::endl - << " all iterations)" << std::endl - << "#2 search display degree (during searches)" << std::endl - << "#3 poll display degree (during polls)" << std::endl - << "#4 iterative display degree (other displays at" << std::endl - << " each iteration)" << std::endl - << NOMAD::close_block() << ". " << NOMAD::open_block ( "examples" ) - << "DISPLAY_DEGREE 2 # basic : normal display" << std::endl - << "DISPLAY_DEGREE 0030 # advanced: display only" << std::endl - << " # poll info" << std::endl - << NOMAD::close_block() - << NOMAD::close_block(); - chk = true; - } - - // DISPLAY_STATS: - // --------------- - if ( display_all || NOMAD::string_find ( "DISPLAY_STATS OUTPUTS LATEX FORMAT \ + _out << std::endl + << NOMAD::open_block ( "DISPLAY_DEGREE (basic)" ) << std::endl + << ". " << NOMAD::open_block ( "display degree" ) + << "0: no display" << std::endl + << "1: minimal display" << std::endl + << "2: normal display" << std::endl + << "3: full display" << std::endl + << NOMAD::close_block() + << ". argument: one integer in {0, 1, 2, 3} (basic)" << std::endl + << " or one string in {\'NO\', \'NO_DISPLAY\', \'MIN\'," << std::endl + << " \'MINIMAL\', \'MINIMAL_DISPLAY\' ,\'NORMAL\'," + << std::endl + << " \'NORMAL_DISPLAY\', \'FULL\'," << std::endl + << " \'FULL_DISPLAY\'}" << std::endl + << " or one string composed of 4 integers each in" << std::endl + << " { 0, 1, 2 ,3} (advanced)" << std::endl + << ". default: 2" << std::endl + << ". " + << NOMAD::open_block("advanced use with 4 digits (see user guide for details)") + << "#1 general display degree (before and after" << std::endl + << " all iterations)" << std::endl + << "#2 search display degree (during searches)" << std::endl + << "#3 poll display degree (during polls)" << std::endl + << "#4 iterative display degree (other displays at" << std::endl + << " each iteration)" << std::endl + << NOMAD::close_block() << ". " << NOMAD::open_block ( "examples" ) + << "DISPLAY_DEGREE 2 # basic : normal display" << std::endl + << "DISPLAY_DEGREE 0030 # advanced: display only" << std::endl + << " # poll info" << std::endl + << NOMAD::close_block() + << NOMAD::close_block(); + chk = true; + } + + // DISPLAY_STATS: + // --------------- + if ( display_all || NOMAD::string_find ( "DISPLAY_STATS OUTPUTS LATEX FORMAT \ SCREEN DEBUG BASIC" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "DISPLAY_STATS (basic)" ) << std::endl - << ". format of the outputs displayed at each success" << std::endl - << " (single-objective)" << std::endl - << ". format of the final Pareto front" << std::endl - << " (multi-objective)" << std::endl - << ". displays more points with DISPLAY_ALL_EVAL=true" << std::endl - << ". arguments: list of strings possibly including" << std::endl - << " the following keywords:" << std::endl - << " BBE : blackbox evaluations" << std::endl - << " BBO : blackbox outputs" << std::endl - << " EVAL : evaluations (includes cache hits)" << std::endl - << " MESH_INDEX: mesh index" << std::endl - << " MESH_SIZE : mesh size delta_k^m" << std::endl - << " OBJ : objective function value" << std::endl - << " POLL_SIZE : poll size delta_k^p" << std::endl - << " SIM_BBE : simulated blackbox evaluations" << std::endl - << " SGTE : surrogate evaluations" << std::endl - << " SOL : current feasible iterate" << std::endl - << " STAT_SUM : value of stat SUM" << std::endl - << " STAT_AVG : value of stat AVG" << std::endl - << " TIME : real time in seconds" << std::endl - << " VARi : value of variable i" << std::endl - << " (0 for the first variable)" << std::endl - << ". all outputs may be formatted using C style" << std::endl - << " (%f, %e, %E, %g, %G, %i, %d with the possibility" << std::endl - << " to specify the display width and the precision)" << std::endl - << " example: %5.2Ef displays f in 5 columns and 2 decimals" << std::endl - << " in scientific notation" << std::endl - << ". do not use quotes" << std::endl - << ". the \'%\' character may be explicitely indicated with \'\\%\'" - << std::endl - << ". see details in user guide" << std::endl - << ". defaults: BBE OBJ (single-objective)" << std::endl - << " OBJ (multi-objective)" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "DISPLAY_STATS TIME f=OBJ" << std::endl - << "DISPLAY_STATS %5.2obj" << std::endl - << "# for LaTeX tables:" << std::endl - << "DISPLAY_STATS $BBE$ & ( $%12.5SOL, ) & $OBJ$ \\\\" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - // F_TARGET: - // --------- - if ( display_all || NOMAD::string_find ( "F_TARGET BASIC BLACK-BOXES BLACKBOXES \ + _out << std::endl + << NOMAD::open_block ( "DISPLAY_STATS (basic)" ) << std::endl + << ". format of the outputs displayed at each success" << std::endl + << " (single-objective)" << std::endl + << ". format of the final Pareto front" << std::endl + << " (multi-objective)" << std::endl + << ". displays more points with DISPLAY_ALL_EVAL=true" << std::endl + << ". arguments: list of strings possibly including" << std::endl + << " the following keywords:" << std::endl + << " BBE : blackbox evaluations" << std::endl + << " BBO : blackbox outputs" << std::endl + << " BLK_EVA : number of blocks of evaluations" << std::endl + << " EVAL : evaluations (includes cache hits)" << std::endl + << " MESH_INDEX: mesh index" << std::endl + << " MESH_SIZE : mesh size delta_k^m" << std::endl + << " OBJ : objective function value" << std::endl + << " POLL_SIZE : poll size delta_k^p" << std::endl + << " SIM_BBE : simulated blackbox evaluations" << std::endl + << " SGTE : surrogate evaluations" << std::endl + << " SOL : current feasible iterate" << std::endl + << " STAT_SUM : value of stat SUM" << std::endl + << " STAT_AVG : value of stat AVG" << std::endl + << " TIME : real time in seconds" << std::endl + << " VARi : value of variable i" << std::endl + << " (0 for the first variable)" << std::endl + << ". all outputs may be formatted using C style" << std::endl + << " (%f, %e, %E, %g, %G, %i, %d with the possibility" << std::endl + << " to specify the display width and the precision)" << std::endl + << " example: %5.2Ef displays f in 5 columns and 2 decimals" << std::endl + << " in scientific notation" << std::endl + << ". do not use quotes" << std::endl + << ". the \'%\' character may be explicitely indicated with \'\\%\'" + << std::endl + << ". see details in user guide" << std::endl + << ". defaults: BBE OBJ (single-objective)" << std::endl + << " OBJ (multi-objective)" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "DISPLAY_STATS TIME f=OBJ" << std::endl + << "DISPLAY_STATS %5.2obj" << std::endl + << "# for LaTeX tables:" << std::endl + << "DISPLAY_STATS $BBE$ & ( $%12.5SOL, ) & $OBJ$ \\\\" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + // F_TARGET: + // --------- + if ( display_all || NOMAD::string_find ( "F_TARGET BASIC BLACK-BOXES BLACKBOXES \ BI-OBJECTIVES STOPPING \ MULTI-OBJECTIVES \ BIOBJECTIVES MULTIOBJECTIVES \ BI-MADS BIMADS \ TERMINATES TERMINATION" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "F_TARGET (basic)" ) << std::endl - << ". NOMAD terminates if fi <= F_TARGET[i] for" << std::endl - << " all objectives i" << std::endl - << ". arguments: one or two reals (single or bi-obj.)" << std::endl - << ". no default" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "F_TARGET 0.0 # single-objective" << std::endl - << "F_TARGET ( 0.0 0.0 ) # bi-objective" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - - // HISTORY_FILE: - // ------------- - if ( display_all || NOMAD::string_find ( "HISTORY_FILE BASIC \ + _out << std::endl + << NOMAD::open_block ( "F_TARGET (basic)" ) << std::endl + << ". NOMAD terminates if fi <= F_TARGET[i] for" << std::endl + << " all objectives i" << std::endl + << ". arguments: one or two reals (single or bi-obj.)" << std::endl + << ". no default" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "F_TARGET 0.0 # single-objective" << std::endl + << "F_TARGET ( 0.0 0.0 ) # bi-objective" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + + // HISTORY_FILE: + // ------------- + if ( display_all || NOMAD::string_find ( "HISTORY_FILE BASIC \ FILES OUTPUTS" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "HISTORY_FILE (basic)" ) << std::endl - << ". history file: contains all trial points" << std::endl - << ". does not include multiple evaluations" << std::endl - << ". argument: one string" << std::endl - << ". no default" << std::endl - << ". the seed is added to the file name" << std::endl - << " if ADD_SEED_TO_FILE_NAMES=\'yes\'" << std::endl - << ". example: HISTORY_FILE his.txt" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // INITIAL_MESH_SIZE: - // ------------------ - if ( display_all || NOMAD::string_find ( "INITIAL_MESH_SIZE BASIC MADS \ - DELTA_0 " , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "INITIAL_MESH_SIZE (basic)" ) << std::endl - << ". initial mesh size" << std::endl - << ". arguments: one or DIMENSION positive real(s)" << std::endl - << ". defaults: r0.1 if bounds are defined (10% of the range)," << std::endl - << " max{|x0|,1.0} otherwise" << std::endl - << ". NOMAD uses one mesh size per variable to achieve scaling" << std::endl - << ". values can be given with \'r\' to indicate a proportion of" << std::endl - << " the bounds range (bounds have to be defined for the" << std::endl - << " corresponding variables)" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "INITIAL_MESH_SIZE 1.0 # for all variables" << std::endl - << "INITIAL_MESH_SIZE ( 3 - r0.1 ) # for all variables" << std::endl - << " # (default considered" << std::endl - << " # for 2nd variable)" << std::endl - << "INITIAL_MESH_SIZE 1 0.5 # for var. 1 only" << std::endl - << "INITIAL_MESH_SIZE 2-4 r0.25 # for var. 2 to 4" << std::endl - << NOMAD::close_block() - << NOMAD::close_block(); - chk = true; - } - - // LH_SEARCH: - // ---------- - if ( display_all || NOMAD::string_find ( "LH_SEARCH LATIN-HYPERCUBE \ + _out << std::endl + << NOMAD::open_block ( "HISTORY_FILE (basic)" ) << std::endl + << ". history file: contains all trial points" << std::endl + << ". does not include multiple evaluations" << std::endl + << ". argument: one string" << std::endl + << ". no default" << std::endl + << ". the seed is added to the file name" << std::endl + << " if ADD_SEED_TO_FILE_NAMES=\'yes\'" << std::endl + << ". example: HISTORY_FILE his.txt" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // INITIAL_MESH_SIZE: + // ------------------ + if ( display_all || NOMAD::string_find ( "INITIAL_MESH_SIZE BASIC MADS \ + DELTA_0 " , param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "INITIAL_MESH_SIZE (basic)" ) << std::endl + << ". initial mesh size" << std::endl + << ". arguments: one or DIMENSION positive real(s)" << std::endl + << ". no default" << std::endl + << ". NOMAD uses one mesh size per variable." << std::endl + << ". values can be given with \'r\' to indicate a proportion of" << std::endl + << " the bounds range (bounds have to be defined for the" << std::endl + << " corresponding variables)" << std::endl + << ". initial poll size is determined from initial mesh size" << std::endl + << " when provided, but providing both is not allowed. " << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "INITIAL_MESH_SIZE 1.0 # for all variables" << std::endl + << "INITIAL_MESH_SIZE ( 3 - r0.1 ) # for all variables" << std::endl + << " # (default considered" << std::endl + << " # for 2nd variable)" << std::endl + << "INITIAL_MESH_SIZE 1 0.5 # for var. 1 only" << std::endl + << "INITIAL_MESH_SIZE 2-4 r0.25 # for var. 2 to 4" << std::endl + << NOMAD::close_block() + << NOMAD::close_block(); + chk = true; + } + + + // INITIAL_POLL_SIZE: + // ------------------ + if ( display_all || NOMAD::string_find ( "INITIAL_POLL_SIZE BASIC MADS \ + DELTA_0 " , param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "INITIAL_POLL_SIZE (basic)" ) << std::endl + << ". initial poll size" << std::endl + << ". arguments: one or DIMENSION positive real(s)" << std::endl + << ". defaults: r0.1 if bounds are defined (10% of the range)," << std::endl + << " |x0|/10 otherwise (if x0!=0)" << std::endl + << ". NOMAD uses one poll size per variable to achieve scaling" << std::endl + << ". values can be given with \'r\' to indicate a proportion of" << std::endl + << " the bounds range (bounds have to be defined for the" << std::endl + << " corresponding variables)." << std::endl + << ". the initial mesh size is determined from initial poll size" << std::endl + << " when provided, but providing both is not allowed. " << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "INITIAL_POLL_SIZE 1.0 # for all variables" << std::endl + << "INITIAL_POLL_SIZE ( 3 - r0.1 ) # for all variables" << std::endl + << " # (default considered" << std::endl + << " # for 2nd variable)" << std::endl + << "INITIAL_POLL_SIZE 1 0.5 # for var. 1 only" << std::endl + << "INITIAL_POLL_SIZE 2-4 r0.25 # for var. 2 to 4" << std::endl + << NOMAD::close_block() + << NOMAD::close_block(); + chk = true; + } + + + // LH_SEARCH: + // ---------- + if ( display_all || NOMAD::string_find ( "LH_SEARCH LATIN-HYPERCUBE \ SAMPLING BASIC" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "LH_SEARCH (basic)" ) << std::endl - << ". Latin-Hypercube sampling (search)" << std::endl - << ". arguments: two nonnegative integers p0 and pi" << std::endl - << ". defaults: no search for single-objective" << std::endl - << " or one initial search for bi-objective" << std::endl - << " (see user guide)" << std::endl - << ". p0: number of initial LH search points" << std::endl - << " (or in first MADS run for bi-obj.)" << std::endl - << ". pi: LH search points at each iteration" << std::endl - << " (or in 2nd MADS run for bi-obj.)" << std::endl - << ". the search can be opportunistic or not" << std::endl - << " (see parameter OPPORTUNISTIC_LH)" << std::endl - << ". example: LH_SEARCH 100 0" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // LOWER_BOUND: - // ------------ - if ( display_all || NOMAD::string_find ( "LOWER_BOUND BASIC LB BOUNDS FILES" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "LOWER_BOUND (basic)" ) << std::endl - << ". lower bounds for each variable" << std::endl - << ". no default" << std::endl - << ". can be defined by various methods (see user guide)" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "LOWER_BOUND * 0.0 # all variables are nonnegative" << std::endl - << "LOWER_BOUND 0-2 0.0 # the 3 first var. are nonnegative" << std::endl - << "LOWER_BOUND 0 0.0 # the first var. is nonnegative" << std::endl - << "LOWER_BOUND lb.txt # bounds are defined in \'lb.txt\'" << std::endl - << " # containing DIMENSION values" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - // MAX_BB_EVAL: - // ------------ - if ( display_all || NOMAD::string_find ( "MAX_BB_EVAL BASIC BLACK-BOXES BLACKBOXES \ + _out << std::endl + << NOMAD::open_block ( "LH_SEARCH (basic)" ) << std::endl + << ". Latin-Hypercube sampling (search)" << std::endl + << ". arguments: two nonnegative integers p0 and pi" << std::endl + << ". defaults: no search for single-objective" << std::endl + << " or one initial search for bi-objective" << std::endl + << " (see user guide)" << std::endl + << ". p0: number of initial LH search points" << std::endl + << " (or in first MADS run for bi-obj.)" << std::endl + << ". pi: LH search points at each iteration" << std::endl + << " (or in 2nd MADS run for bi-obj.)" << std::endl + << ". the search can be opportunistic or not" << std::endl + << " (see parameter OPPORTUNISTIC_LH)" << std::endl + << ". example: LH_SEARCH 100 0" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // LOWER_BOUND: + // ------------ + if ( display_all || NOMAD::string_find ( "LOWER_BOUND BASIC LB BOUNDS FILES" , + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "LOWER_BOUND (basic)" ) << std::endl + << ". lower bounds for each variable" << std::endl + << ". no default" << std::endl + << ". can be defined by various methods (see user guide)" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "LOWER_BOUND * 0.0 # all variables are nonnegative" << std::endl + << "LOWER_BOUND 0-2 0.0 # the 3 first var. are nonnegative" << std::endl + << "LOWER_BOUND 0 0.0 # the first var. is nonnegative" << std::endl + << "LOWER_BOUND lb.txt # bounds are defined in \'lb.txt\'" << std::endl + << " # containing DIMENSION values" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + // MAX_BB_EVAL: + // ------------ + if ( display_all || NOMAD::string_find ( "MAX_BB_EVAL BASIC BLACK-BOXES BLACKBOXES \ MAXIMUM CACHE BBEVAL \ NUMBER EVALUATIONS STOPPING \ BI-0BJECTIVE MULTI-OBJECTIVE \ BIOBJECTIVES MULTIOBJECTIVES \ BI-MADS BIMADS \ TERMINATES TERMINATION" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MAX_BB_EVAL (basic)" ) << std::endl - << ". maximum number of blackbox evaluations" << std::endl - << ". argument: one positive integer" << std::endl - << ". no default" << std::endl - << ". doesn\'t consider evaluations taken in the" << std::endl - << " cache (cache hits)" << std::endl - << ". in bi-objective mode: max number of blackbox" << std::endl - << " evaluations for each MADS run" << std::endl - << ". example: MAX_BB_EVAL 1000" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MAX_TIME: - // --------- - if ( display_all || NOMAD::string_find ( "MAX_TIME BASIC BLACK-BOXES BLACKBOXES \ + _out << std::endl + << NOMAD::open_block ( "MAX_BB_EVAL (basic)" ) << std::endl + << ". maximum number of blackbox evaluations" << std::endl + << ". argument: one positive integer" << std::endl + << ". no default" << std::endl + << ". doesn\'t consider evaluations taken in the" << std::endl + << " cache (cache hits)" << std::endl + << ". in bi-objective mode: max number of blackbox" << std::endl + << " evaluations for each MADS run" << std::endl + << ". example: MAX_BB_EVAL 1000" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MAX_TIME: + // --------- + if ( display_all || NOMAD::string_find ( "MAX_TIME BASIC BLACK-BOXES BLACKBOXES \ MAXIMUM WALL-CLOCK REAL \ STOPPING TERMINATION \ TERMINATES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MAX_TIME (basic)" ) << std::endl - << ". maximum wall-clock time in seconds" << std::endl - << ". argument: one positive integer" << std::endl - << ". no default" << std::endl - << ". example: MAX_TIME 3600 # one hour max" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // SOLUTION_FILE: - // -------------- - if ( display_all || NOMAD::string_find ( "SOLUTION_FILE BASIC \ + _out << std::endl + << NOMAD::open_block ( "MAX_TIME (basic)" ) << std::endl + << ". maximum wall-clock time in seconds" << std::endl + << ". argument: one positive integer" << std::endl + << ". no default" << std::endl + << ". example: MAX_TIME 3600 # one hour max" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // SOLUTION_FILE: + // -------------- + if ( display_all || NOMAD::string_find ( "SOLUTION_FILE BASIC \ FILES OUTPUTS" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "SOLUTION_FILE (basic)" ) << std::endl - << ". file containing the solution" << std::endl - << ". argument: one string" << std::endl - << ". no default" << std::endl - << ". the seed is added to the file name if" << std::endl - << " ADD_SEED_TO_FILE_NAMES=\'yes\'" << std::endl - << ". example: SOLUTION_FILE sol.txt" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - - // STATS_FILE: - // ----------- - if ( display_all || NOMAD::string_find ( "STATS_FILE BASIC \ + _out << std::endl + << NOMAD::open_block ( "SOLUTION_FILE (basic)" ) << std::endl + << ". file containing the solution" << std::endl + << ". argument: one string" << std::endl + << ". no default" << std::endl + << ". the seed is added to the file name if" << std::endl + << " ADD_SEED_TO_FILE_NAMES=\'yes\'" << std::endl + << ". example: SOLUTION_FILE sol.txt" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + + // STATS_FILE: + // ----------- + if ( display_all || NOMAD::string_find ( "STATS_FILE BASIC \ FILES OUTPUTS DISPLAY_STATS" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "STATS_FILE (basic)" ) << std::endl - << ". file containing all successes with the same format" << std::endl - << " than DISPLAY_STATS" << std::endl - << ". displays more points with DISPLAY_ALL_EVAL=true" << std::endl - << ". arguments: one string (file name) and one" << std::endl - << " list of strings (stats)" << std::endl - << ". no default" << std::endl - << ". the seed is added to the file name if" << std::endl - << " ADD_SEED_TO_FILE_NAMES=\'yes\'" << std::endl - << ". example: STATS_FILE log.txt BBE SOL f=%.2EOBJ" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // TMP_DIR: - // -------- - if ( display_all || NOMAD::string_find ( "TMP_DIR BASIC PATH TEMPORARY \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "STATS_FILE (basic)" ) << std::endl + << ". file containing all successes with the same format" << std::endl + << " than DISPLAY_STATS" << std::endl + << ". displays more points with DISPLAY_ALL_EVAL=true" << std::endl + << ". arguments: one string (file name) and one" << std::endl + << " list of strings (stats)" << std::endl + << ". no default" << std::endl + << ". the seed is added to the file name if" << std::endl + << " ADD_SEED_TO_FILE_NAMES=\'yes\'" << std::endl + << ". example: STATS_FILE log.txt BBE SOL f=%.2EOBJ" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // TMP_DIR: + // -------- + if ( display_all || NOMAD::string_find ( "TMP_DIR BASIC PATH TEMPORARY \ DIRECTORY FILES \ BLACK-BOXES BLACKBOXES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "TMP_DIR (basic)" ) << std::endl - << ". temporary directory for blackbox input/output files" << std::endl - << ". argument: one string indicating a directory" << std::endl - << ". default: problem directory" << std::endl - << ". improved performance with a local temporary directory" << std::endl - << ". example: TMP_DIR /tmp" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - - // UPPER_BOUND: - // ------------ - if ( display_all || NOMAD::string_find ( "UPPER_BOUND BASIC UB BOUNDS" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "UPPER_BOUND (basic)" ) << std::endl - << ". upper bounds for each variable" << std::endl - << ". same logic as parameter LOWER_BOUND" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - - // X0: - // --- - if ( display_all || NOMAD::string_find ( "X0 STARTING POINT BASIC \ + _out << std::endl + << NOMAD::open_block ( "TMP_DIR (basic)" ) << std::endl + << ". temporary directory for blackbox input/output files" << std::endl + << ". argument: one string indicating a directory" << std::endl + << ". default: problem directory" << std::endl + << ". improved performance with a local temporary directory" << std::endl + << ". example: TMP_DIR /tmp" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + + // UPPER_BOUND: + // ------------ + if ( display_all || NOMAD::string_find ( "UPPER_BOUND BASIC UB BOUNDS" , + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "UPPER_BOUND (basic)" ) << std::endl + << ". upper bounds for each variable" << std::endl + << ". same logic as parameter LOWER_BOUND" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + + // X0: + // --- + if ( display_all || NOMAD::string_find ( "X0 STARTING POINT BASIC \ VARIABLES \ LH LATIN-HYPERCUBE \ CACHE FILES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "X0 (basic)" ) << std::endl - << ". starting point(s)" << std::endl - << ". arguments: text file name," << std::endl - << " or cache file name," << std::endl - << " or DIMENSION reals," << std::endl - << " or indexed values" << std::endl - << ". default: best point from a cache file or from" << std::endl - << " an initial LH search" << std::endl - << ". do not use a surrogate cache file" << std::endl - << " (even if OPT_ONLY_SGTE=\'yes\')" << std::endl - << ". more than one starting point can be defined (all points" << std::endl - << " are evaluated: x0 evaluations are not opportunistic)" << std:: endl - << ". a text file can describe more than one point" << std::endl - << ". may be infeasible, but can only violate PB, F, or PEB" << std::endl - << " constraints" << std::endl - << ". cannot be outside bounds" << std::endl - << ". must respect fixed variables (param. FIXED_VARIABLE)" << std::endl - << ". " << NOMAD::open_block ("examples") << std::endl - << "X0 x0.txt # text file with a multiple" << std::endl - << " # of DIMENSION values" << std::endl << std::endl - << "X0 * 0.0 # first starting point" << std::endl - << "X0 1 * 1.0 # second starting point" << std::endl << std::endl - << "X0 ( 0 1 2 ) # if DIMENSION=3" << std::endl << std::endl - << "see other examples in user guide" << std::endl - << NOMAD::close_block() - << NOMAD::close_block(); - chk = true; - } - - - if ( display_all || NOMAD::string_find ( registered_key_advanced , param_names ) ) - { - _out << "--------------------------------------------------------------" << endl; - _out << "---------------------ADVANCED PARAMETERS----------------------" << endl; - _out << "--------------------------------------------------------------" << endl; - } - - // ADD_SEED_TO_FILE_NAMES: - // ----------------------- - if ( display_all || NOMAD::string_find ( "ADD_SEED_TO_FILE_NAMES OUTPUTS \ + _out << std::endl + << NOMAD::open_block ( "X0 (basic)" ) << std::endl + << ". starting point(s)" << std::endl + << ". arguments: text file name," << std::endl + << " or cache file name," << std::endl + << " or DIMENSION reals," << std::endl + << " or indexed values" << std::endl + << ". default: best point from a cache file or from" << std::endl + << " an initial LH search" << std::endl + << ". do not use a surrogate cache file" << std::endl + << " (even if OPT_ONLY_SGTE=\'yes\')" << std::endl + << ". more than one starting point can be defined (all points" << std::endl + << " are evaluated: x0 evaluations are not opportunistic)" << std:: endl + << ". a text file can describe more than one point" << std::endl + << ". may be infeasible, but can only violate PB, F, or PEB" << std::endl + << " constraints" << std::endl + << ". cannot be outside bounds" << std::endl + << ". must respect fixed variables (param. FIXED_VARIABLE)" << std::endl + << ". " << NOMAD::open_block ("examples") << std::endl + << "X0 x0.txt # text file with a multiple" << std::endl + << " # of DIMENSION values" << std::endl << std::endl + << "X0 * 0.0 # first starting point" << std::endl + << "X0 1 * 1.0 # second starting point" << std::endl << std::endl + << "X0 ( 0 1 2 ) # if DIMENSION=3" << std::endl << std::endl + << "see other examples in user guide" << std::endl + << NOMAD::close_block() + << NOMAD::close_block(); + chk = true; + } + + + if ( display_all || NOMAD::string_find ( registered_key_advanced , param_names ) ) + { + _out << "--------------------------------------------------------------" << endl; + _out << "---------------------ADVANCED PARAMETERS----------------------" << endl; + _out << "--------------------------------------------------------------" << endl; + } + + // ADD_SEED_TO_FILE_NAMES: + // ----------------------- + if ( display_all || NOMAD::string_find ( "ADD_SEED_TO_FILE_NAMES OUTPUTS \ ADVANCED FILES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "ADD_SEED_TO_FILE_NAMES (advanced)" ) << std::endl - << ". if \'yes\', the seed is added to the name of" << std::endl - << " output files (HISTORY_FILE, SOLUTION_FILE," << std::endl - << " and STATS_FILE)" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". example: ADD_SEED_TO_FILE_NAMES no" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // ASYNCHRONOUS: - // ------------- - if ( display_all || NOMAD::string_find ( "ASYNCHRONOUS PARALLELISM MPI \ + _out << std::endl + << NOMAD::open_block ( "ADD_SEED_TO_FILE_NAMES (advanced)" ) << std::endl + << ". if \'yes\', the seed is added to the name of" << std::endl + << " output files (HISTORY_FILE, SOLUTION_FILE," << std::endl + << " and STATS_FILE)" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". example: ADD_SEED_TO_FILE_NAMES no" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // ANISOTROPIC_MESH: + // ------------- + if ( display_all || NOMAD::string_find ( "ANISOTROPIC MESH SCALING" , param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "ANISOTROPIC_MESH (advanced)" ) << std::endl + << ". use anisotropic mesh for generating directions" << std::endl + << ". if \'yes\', the mesh size is scaled dynamically" << std::endl + << ". based on direction of success." << std::endl + << ". This option is compatible with Ortho Mads " << std::endl + << ". directions only " << std::endl + << ". default: \'yes\'" << std::endl + << ". example: ANISOTROPIC_MESH no" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // ASYNCHRONOUS: + // ------------- + if ( display_all || NOMAD::string_find ( "ASYNCHRONOUS PARALLELISM MPI \ ADVANCED PMADS" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "ASYNCHRONOUS (advanced)" ) << std::endl - << ". asynchronous strategy for the parallel version" << std::endl - << ". if \'yes\', there can be evaluations in progress" << std::endl - << " after an iteration has ended" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". example: ASYNCHRONOUS no" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // BB_INPUT_INCLUDE_SEED: - // ---------------------- - if ( display_all || NOMAD::string_find ( "BB_INPUT_INCLUDE_SEED BLACK-BOXES \ + _out << std::endl + << NOMAD::open_block ( "ASYNCHRONOUS (advanced)" ) << std::endl + << ". asynchronous strategy for the parallel version" << std::endl + << ". if \'yes\', there can be evaluations in progress" << std::endl + << " after an iteration has ended" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". example: ASYNCHRONOUS no" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // BB_INPUT_INCLUDE_SEED: + // ---------------------- + if ( display_all || NOMAD::string_find ( "BB_INPUT_INCLUDE_SEED BLACK-BOXES \ BLACKBOXES \ ADVANCED FILES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "BB_INPUT_INCLUDE_SEED (advanced)" ) << std::endl - << ". if \'yes\', the seed (\'SEED\') of the current" << std::endl - << " execution is put as the first entry in" << std::endl - << " all blackbox input files" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'no\'" << std::endl - << ". example: BB_INPUT_INCLUDE_SEED yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // BB_INPUT_INCLUDE_TAG: - // --------------------- - if ( display_all || NOMAD::string_find ( "BB_INPUT_INCLUDE_TAG \ + _out << std::endl + << NOMAD::open_block ( "BB_INPUT_INCLUDE_SEED (advanced)" ) << std::endl + << ". if \'yes\', the seed (\'SEED\') of the current" << std::endl + << " execution is put as the first entry in" << std::endl + << " all blackbox input files" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'no\'" << std::endl + << ". example: BB_INPUT_INCLUDE_SEED yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // BB_INPUT_INCLUDE_TAG: + // --------------------- + if ( display_all || NOMAD::string_find ( "BB_INPUT_INCLUDE_TAG \ BLACK-BOXES BLACKBOXES \ ADVANCED FILES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "BB_INPUT_INCLUDE_TAG (advanced)" ) << std::endl - << ". if \'yes\', the tag of a point is put as the first" << std::endl - << " entry in all blackbox input files (second" << std::endl - << " entry if BB_INPUT_INCLUDE_SEED=\'yes\')" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'no\'" << std::endl - << ". example: BB_INPUT_INCLUDE_TAG yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // BB_REDIRECTION: - // --------------- - if ( display_all || NOMAD::string_find ( "BB_REDIRECTION BLACK-BOXES BLACKBOXES \ + _out << std::endl + << NOMAD::open_block ( "BB_INPUT_INCLUDE_TAG (advanced)" ) << std::endl + << ". if \'yes\', the tag of a point is put as the first" << std::endl + << " entry in all blackbox input files (second" << std::endl + << " entry if BB_INPUT_INCLUDE_SEED=\'yes\')" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'no\'" << std::endl + << ". example: BB_INPUT_INCLUDE_TAG yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // BB_REDIRECTION: + // --------------- + if ( display_all || NOMAD::string_find ( "BB_REDIRECTION BLACK-BOXES BLACKBOXES \ ADVANCED OUTPUT FILES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "BB_REDIRECTION (advanced)" ) << std::endl - << ". if NOMAD uses a redirection (\'>\') to" << std::endl - << " create blackbox output files" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". if \'no\', the blackbox has to manage its" << std::endl - << " own output files (see user guide)" << std::endl - << ". example: BB_INPUT_INCLUDE_TAG yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // CACHE_SAVE_PERIOD: - // ------------------ - if ( display_all || NOMAD::string_find ( "CACHE_SAVE_PERIOD OUTPUTS \ + _out << std::endl + << NOMAD::open_block ( "BB_REDIRECTION (advanced)" ) << std::endl + << ". if NOMAD uses a redirection (\'>\') to" << std::endl + << " create blackbox output files" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". if \'no\', the blackbox has to manage its" << std::endl + << " own output files (see user guide)" << std::endl + << ". example: BB_INPUT_INCLUDE_TAG yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // CACHE_SAVE_PERIOD: + // ------------------ + if ( display_all || NOMAD::string_find ( "CACHE_SAVE_PERIOD OUTPUTS \ ITERATIONS ADVANCED FILES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "CACHE_SAVE_PERIOD (advanced)" ) << std::endl - << ". period (iterations) at which the cache file is saved" << std::endl - << " (if CACHE_FILE is defined; disabled for bi-objective)" << std::endl - << ". argument: one nonnegative integer" << std::endl - << ". default: 25" << std::endl - << ". example: CACHE_SAVE_PERIOD 10" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // CACHE_SEARCH: - // ------------- - if ( display_all || NOMAD::string_find ( "CACHE_SEARCH ADVANCED\ + _out << std::endl + << NOMAD::open_block ( "CACHE_SAVE_PERIOD (advanced)" ) << std::endl + << ". period (iterations) at which the cache file is saved" << std::endl + << " (if CACHE_FILE is defined; disabled for bi-objective)" << std::endl + << ". argument: one nonnegative integer" << std::endl + << ". default: 25" << std::endl + << ". example: CACHE_SAVE_PERIOD 10" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // CACHE_SEARCH: + // ------------- + if ( display_all || NOMAD::string_find ( "CACHE_SEARCH ADVANCED\ CACHE_FILE SGTE_CACHE_FILE" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "CACHE_SEARCH (advanced)" ) << std::endl - << ". enable or disable the cache search" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'no\'" << std::endl - << ". the search looks in the cache between iterations" << std::endl - << ". this can be useful when a non-empty initial cache" << std::endl - << " file is provided or with an extern cache that" << std::endl - << " the user updates independently" << std::endl - << ". example: CACHE_SEARCH yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // CLOSED_BRACE: - // ------------- - if ( display_all || NOMAD::string_find ( "CLOSED_BRACES INDENTATION TABULATIONS \ + _out << std::endl + << NOMAD::open_block ( "CACHE_SEARCH (advanced)" ) << std::endl + << ". enable or disable the cache search" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'no\'" << std::endl + << ". the search looks in the cache between iterations" << std::endl + << ". this can be useful when a non-empty initial cache" << std::endl + << " file is provided or with an extern cache that" << std::endl + << " the user updates independently" << std::endl + << ". example: CACHE_SEARCH yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // CLOSED_BRACE: + // ------------- + if ( display_all || NOMAD::string_find ( "CLOSED_BRACES INDENTATION TABULATIONS \ BLOCKS ADVANCED DISPLAY" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "CLOSED_BRACE (advanced)" ) << std::endl - << ". string displayed at the end of indented" << std::endl - << " blocks in full display mode" << std::endl - << ". argument: one string" << std::endl - << ". default: \'}\'" << std::endl - << ". example: CLOSED_BRACE End" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // DISABLE MODELS - //----------- - if ( display_all || NOMAD::string_find ( "MODEL DISABLE MODELS DISABLE_MODELS \ - MODEL_EVAL_SORT ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "CLOSED_BRACE (advanced)" ) << std::endl + << ". string displayed at the end of indented" << std::endl + << " blocks in full display mode" << std::endl + << ". argument: one string" << std::endl + << ". default: \'}\'" << std::endl + << ". example: CLOSED_BRACE End" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // DISABLE MODELS / EVAL_SORT + //----------- + if ( display_all || NOMAD::string_find ( "MODEL DISABLE MODELS DISABLE_MODELS \ + MODEL_EVAL_SORT ADVANCED \ + EVAL_SORT \ ORTHO N+1 QUAD QUADRATIC MODEL_SEARCH TGP " , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "DISABLE (advanced)" ) << std::endl - << ". this parameter is used to forcefully disable a feature." << std::endl - << ". argument: MODELS" << std::endl - << ". # DISABLE MODELS is equivalent to set: " << std::endl - << " MODEL_EVAL_SORT no " << std::endl - << " MODEL_SEARCH no " << std::endl - << " DIRECTION_TYPE ORTHO N+1 NEG " << std::endl - << " # WARNING: extra settings of MODEL_EVAL_SORT," << std::endl - << " MODEL_SEARCH and DIRECTION_TYPE ORTHO N+1 QUAD" << std::endl - << " will be ignored " << std::endl - << ". default: no default" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // EXTENDED_POLL_ENABLED: - // ---------------------- - if ( display_all || NOMAD::string_find ( "EXTENDED_POLL_ENABLED \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "DISABLE (advanced)" ) << std::endl + << ". this parameter is used to forcefully disable a feature." << std::endl + << ". argument: MODELS or EVAL_SORT" << std::endl + << ". # DISABLE MODELS is equivalent to set: " << std::endl + << " MODEL_EVAL_SORT no " << std::endl + << " MODEL_SEARCH no " << std::endl + << " DIRECTION_TYPE ORTHO N+1 NEG " << std::endl + << " # WARNING: extra settings of MODEL_EVAL_SORT," << std::endl + << " MODEL_SEARCH and DIRECTION_TYPE ORTHO N+1 QUAD" << std::endl + << " will be ignored " << std::endl + << ". # DISABLE EVAL_SORT: ordering by lexicographic order only. " << std::endl + << " # WARNING: setting of MODEL_EVAL_SORT," << std::endl + << " SURROGATE_EVAL_SORT and user priority " << std::endl + << " will be ignored" << std::endl + << ". default: no default" << std::endl + + << NOMAD::close_block(); + chk = true; + } + + // BB_MAX_BLOCK_SIZE + //----------- + if ( display_all || NOMAD::string_find ( "EVAL LIST MAX BLOCK SIZE BB BLACKBOX \ + BLACK-BOX OPPORTUNIST OPPORTUNISTIC PARALLEL", + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "BB_MAX_BLOCK_SIZE (advanced)" ) << std::endl + << ". maximum size of a block of evaluations send to the blackbox" << std::endl + << " executable at once. Blackbox executable can manage parallel" << std::endl + << " evaluations on its own. Opportunistic strategies may apply after" << std::endl + << " each block of evaluations." << std::endl + << " Depending on the algorithm phase, the blackbox executable will" << std::endl + << " receive at most BB_MAX_BLOCK_SIZE points to evaluate." << std::endl + << " When this parameter is greater than one, the number of evaluations"<< std::endl + << " may exceed the MAX_BB_EVAL stopping criterion." << std::endl + << ". argument: integer > 0" << std::endl + << ". example: BB_MAX_BLOCK_SIZE 3," << std::endl + << " The blackbox executable receives blocks of" << std::endl + << " at most 3 points for evaluation." << std::endl + << ". default: 1" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // EXTENDED_POLL_ENABLED: + // ---------------------- + if ( display_all || NOMAD::string_find ( "EXTENDED_POLL_ENABLED \ EXTENDED_POLL_DISABLED \ MIXED MVP CATEGORICAL \ ADVANCED" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "EXTENDED_POLL_ENABLED (advanced)" ) << std::endl - << ". if \'no\', the extended poll for categorical" << std::endl - << " variables is disabled" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". the extended poll uses the surrogate" << std::endl - << " if HAS_SGTE or SGTE_EXE is defined" << std::endl - << ". example: EXTENDED_POLL_ENABLED yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // EXTENDED_POLL_TRIGGER: - // ---------------------- - if ( display_all || NOMAD::string_find ( "EXTENDED_POLL_TRIGGER ADVANCED \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "EXTENDED_POLL_ENABLED (advanced)" ) << std::endl + << ". if \'no\', the extended poll for categorical" << std::endl + << " variables is disabled" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". the extended poll uses the surrogate" << std::endl + << " if HAS_SGTE or SGTE_EXE is defined" << std::endl + << ". example: EXTENDED_POLL_ENABLED yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // EXTENDED_POLL_TRIGGER: + // ---------------------- + if ( display_all || NOMAD::string_find ( "EXTENDED_POLL_TRIGGER ADVANCED \ MIXED MVP CATEGORICAL" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "EXTENDED_POLL_TRIGGER (advanced)" ) << std::endl - << ". extended poll trigger for categorical variables" << std::endl - << ". argument: one positive real (can be relative)" << std::endl - << ". an extended poll around the extended poll point y" << std::endl - << " constructed from an iterate xk is performed if" << std::endl - << " f(y) < f(xk)+trigger or f(y) < f(xk)+|f(x_k)|*trigger" << std::endl - << " (relative value)" << std::endl - << ". see details in user guide" << std::endl - << ". default: r0.1" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "EXTENDED_POLL_TRIGGER 10.0 # ext poll trigger of 10" << std::endl - << "EXTENDED_POLL_TRIGGER r0.2 # ext poll trigger of 20%" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - - // FIXED_VARIABLE: - // --------------- - if ( display_all || NOMAD::string_find ( "FIXED_VARIABLE VARIABLES ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "EXTENDED_POLL_TRIGGER (advanced)" ) << std::endl + << ". extended poll trigger for categorical variables" << std::endl + << ". argument: one positive real (can be relative)" << std::endl + << ". an extended poll around the extended poll point y" << std::endl + << " constructed from an iterate xk is performed if" << std::endl + << " f(y) < f(xk)+trigger or f(y) < f(xk)+|f(x_k)|*trigger" << std::endl + << " (relative value)" << std::endl + << ". see details in user guide" << std::endl + << ". default: r0.1" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "EXTENDED_POLL_TRIGGER 10.0 # ext poll trigger of 10" << std::endl + << "EXTENDED_POLL_TRIGGER r0.2 # ext poll trigger of 20%" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + + // FIXED_VARIABLE: + // --------------- + if ( display_all || NOMAD::string_find ( "FIXED_VARIABLE VARIABLES ADVANCED \ FILES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "FIXED_VARIABLE (advanced)" ) << std::endl - << ". fix some variables to some specific values" << std::endl - << ". arguments: variable indexes and values" << std::endl - << ". no default" << std::endl - << ". values are optional if at least one starting point" << std::endl - << " is defined" << std::endl - << ". can be given by a text file containing DIMENSION" << std::endl - << " entrie (use \'-\' for free variables)" << std::endl - << ". variables inside groups defined by VARIABLE_GROUP" << std::endl - << " cannot be fixed" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "FIXED_VARIABLE ( 0.0 - 0.0 ) # variables 0 and 2 are fixed" << std::endl - << "FIXED_VARIABLE fixed.txt # with a file" << std::endl - << "FIXED_VARIABLE 0-1 3.14 # 2 first variables fixed" << std::endl - << " # to 3.14" << std::endl - << "FIXED_VARIABLE 0 # first variable fixed to" << std::endl - << " # its X0 value" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - // HALTON_SEED: - // ------------ - if ( display_all || NOMAD::string_find ( "HALTON_SEED ADVANCED ORTHO-MADS ORTHOMADS \ - RANDOM \ - DETERMINISTIC ORTHOGONAL DIRECTIONS \ - POLL" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "HALTON_SEED (advanced)" ) << std::endl - << ". Halton seed to get different runs with OrthoMADS" << std::endl - << ". argument: one nonnegative integer" << std::endl - << ". default: the DIMENSION^th prime number" << std::endl - << ". choose values greater than or equal to this default" << std::endl - << ". see also parameter SEED for different LT-MADS runs" << std::endl - << ". example: HALTON_SEED 10" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // H_MAX_0: - // -------- - if ( display_all || NOMAD::string_find ( "H_MAX_0 HMAX_0 HMAX ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "FIXED_VARIABLE (advanced)" ) << std::endl + << ". fix some variables to some specific values" << std::endl + << ". arguments: variable indexes and values" << std::endl + << ". no default" << std::endl + << ". values are optional if at least one starting point" << std::endl + << " is defined" << std::endl + << ". can be given by a text file containing DIMENSION" << std::endl + << " entrie (use \'-\' for free variables)" << std::endl + << ". variables inside groups defined by VARIABLE_GROUP" << std::endl + << " cannot be fixed" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "FIXED_VARIABLE ( 0.0 - 0.0 ) # variables 0 and 2 are fixed" << std::endl + << "FIXED_VARIABLE fixed.txt # with a file" << std::endl + << "FIXED_VARIABLE 0-1 3.14 # 2 first variables fixed" << std::endl + << " # to 3.14" << std::endl + << "FIXED_VARIABLE 0 # first variable fixed to" << std::endl + << " # its X0 value" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + // H_MAX_0: + // -------- + if ( display_all || NOMAD::string_find ( "H_MAX_0 HMAX_0 HMAX ADVANCED \ CONSTRAINTS PB FILTER PEB \ L1 L2 LINF L_INF \ FEASIBILITY \ PROGRESSIVE-BARRIER" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "H_MAX_0 (advanced)" ) << std::endl - << ". initial value of h_max (for PB and" << std::endl - << " F constraints handling strategies)" << std::endl - << ". argument: one positive real" << std::endl - << ". default: 1E+20" << std::endl - << ". points x such that h(x) > h_max are" << std::endl - << " rejected (h measures the feasibility)" << std::endl - << ". example: H_MAX_0 100.0" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // H_MIN: - // ------ - if ( display_all || NOMAD::string_find ( "H_MIN HMIN ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "H_MAX_0 (advanced)" ) << std::endl + << ". initial value of h_max (for PB and" << std::endl + << " F constraints handling strategies)" << std::endl + << ". argument: one positive real" << std::endl + << ". default: 1E+20" << std::endl + << ". points x such that h(x) > h_max are" << std::endl + << " rejected (h measures the feasibility)" << std::endl + << ". example: H_MAX_0 100.0" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // H_MIN: + // ------ + if ( display_all || NOMAD::string_find ( "H_MIN HMIN ADVANCED \ CONSTRAINTS PB FILTER PEB \ L1 L2 LINF L_INF \ FEASIBILITY \ PROGRESSIVE-BARRIER" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "H_MIN (advanced)" ) << std::endl - << ". value of h_min; x is feasible if h(x) <= h_min" << std::endl - << " (h measures the feasibility)" << std::endl - << ". argument: one positive real" << std::endl - << ". default: 0.0" << std::endl - << ". example: H_MIN 1E-5" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // H_NORM: - // ------- - if ( display_all || NOMAD::string_find ( "H_NORM ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "H_MIN (advanced)" ) << std::endl + << ". value of h_min; x is feasible if h(x) <= h_min" << std::endl + << " (h measures the feasibility)" << std::endl + << ". argument: one positive real" << std::endl + << ". default: 0.0" << std::endl + << ". example: H_MIN 1E-5" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // H_NORM: + // ------- + if ( display_all || NOMAD::string_find ( "H_NORM ADVANCED \ CONSTRAINTS PB FILTER PEB \ L1 L2 LINF L_INF \ FEASIBILITY \ PROGRESSIVE-BARRIER" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "H_NORM (advanced)" ) << std::endl - << ". norm used by the F and PB constraints handling" << std::endl - << " strategies to compute h(x) (h measures the" << std::endl - << " feasibility)" << std::endl - << ". argument: one string in {\'L1\', \'L2\', \'Linf\'}" << std::endl - << ". default: \'L2\'" << std::endl - << ". example: H_NORM Linf" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // HAS_SGTE: - // --------- - if ( display_all || NOMAD::string_find ( "HAS_SGTE SGTE_EXE ADVANCED SURROGATES \ + _out << std::endl + << NOMAD::open_block ( "H_NORM (advanced)" ) << std::endl + << ". norm used by the F and PB constraints handling" << std::endl + << " strategies to compute h(x) (h measures the" << std::endl + << " feasibility)" << std::endl + << ". argument: one string in {\'L1\', \'L2\', \'Linf\'}" << std::endl + << ". default: \'L2\'" << std::endl + << ". example: H_NORM Linf" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // HAS_SGTE: + // --------- + if ( display_all || NOMAD::string_find ( "HAS_SGTE SGTE_EXE ADVANCED SURROGATES \ BLACK-BOXES BLACKBOXES \ SGTES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "HAS_SGTE (advanced)" ) << std::endl - << ". to indicate that the problem has a surrogate" << std::endl - << ". argument: one boolean (\'yes\' or \'no\') " << std::endl - << ". default: \'no\' if parameter SGTE_EXE is undefined," << std::endl - << " \'yes\' otherwise" << std::endl - << ". this parameter is not necessary in batch" << std::endl - << " mode, but essential in library mode when" << std::endl - << " no surrogate executable is provided" << std::endl - << ". example: HAS_SGTE yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // INF_STR: - // -------- - if ( display_all || NOMAD::string_find ( "INF_STR ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "HAS_SGTE (advanced)" ) << std::endl + << ". to indicate that the problem has a surrogate" << std::endl + << ". argument: one boolean (\'yes\' or \'no\') " << std::endl + << ". default: \'no\' if parameter SGTE_EXE is undefined," << std::endl + << " \'yes\' otherwise" << std::endl + << ". this parameter is not necessary in batch" << std::endl + << " mode, but essential in library mode when" << std::endl + << " no surrogate executable is provided" << std::endl + << ". example: HAS_SGTE yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // INF_STR: + // -------- + if ( display_all || NOMAD::string_find ( "INF_STR ADVANCED \ INFINITY DISPLAY REALS" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "INF_STR (advanced)" ) << std::endl - << ". string used to display infinity" << std::endl - << ". argument: one string" << std::endl - << ". default: \"inf\"" << std::endl - << ". example: INF_STR Infinity" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // INITIAL_MESH_INDEX: - // ------------------- - if ( display_all || NOMAD::string_find ( "INITIAL_MESH_INDEX ADVANCED \\DELTA \ - MADS L0 L_0 \\ELL_0" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "INITIAL_MESH_INDEX (advanced)" ) << std::endl - << ". initial mesh index \\ell_0" << std::endl - << ". argument: one integer (can be negative)" << std::endl - << ". default: 0" << std::endl - << ". example: INITIAL_MESH_INDEX -1" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // MAX_CACHE_MEMORY: - // ----------------- - if ( display_all || NOMAD::string_find ( "MAX_CACHE_MEMORY ADVANCED \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "INF_STR (advanced)" ) << std::endl + << ". string used to display infinity" << std::endl + << ". argument: one string" << std::endl + << ". default: \"inf\"" << std::endl + << ". example: INF_STR Infinity" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MAX_CACHE_MEMORY: + // ----------------- + if ( display_all || NOMAD::string_find ( "MAX_CACHE_MEMORY ADVANCED \ MAXIMUM RAM STOPPING \ MB MEGA-BYTES MEGABYTES \ TERMINATES TERMINATION" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MAX_CACHE_MEMORY (advanced)" ) << std::endl - << ". the program terminates as soon as the cache" << std::endl - << " reaches this memory limit" << std::endl - << ". argument: one positive integer (expressed in MB)" << std::endl - << ". default: 2000" << std::endl - << ". example: MAX_CACHE_MEMORY 1024 # limit of 1GB cache" << std::endl - << " # occupation" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MAX_CONSECUTIVE_FAILED_ITERATIONS: - // ---------------------------------- - if ( display_all || NOMAD::string_find ( "MAX_CONSECUTIVE_FAILED_ITERATIONS ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MAX_CACHE_MEMORY (advanced)" ) << std::endl + << ". the program terminates as soon as the cache" << std::endl + << " reaches this memory limit" << std::endl + << ". argument: one positive integer (expressed in MB)" << std::endl + << ". default: 2000" << std::endl + << ". example: MAX_CACHE_MEMORY 1024 # limit of 1GB cache" << std::endl + << " # occupation" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MAX_CONSECUTIVE_FAILED_ITERATIONS: + // ---------------------------------- + if ( display_all || NOMAD::string_find ( "MAX_CONSECUTIVE_FAILED_ITERATIONS ADVANCED \ TERMINATION STOPPING TERMINATES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MAX_CONSECUTIVE_FAILED_ITERATIONS (advanced)" ) << std::endl - << ". maximum number of consecutive failed iterations" << std::endl - << ". arguments: one positive integer" << std::endl - << ". no default" << std::endl - << ". example: MAX_CONSECUTIVE_FAILED_ITERATIONS 5" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MAX_EVAL: - // --------- - if ( display_all || NOMAD::string_find ( "MAX_EVAL ADVANCED BLACK-BOXES BLACKBOXES \ + _out << std::endl + << NOMAD::open_block ( "MAX_CONSECUTIVE_FAILED_ITERATIONS (advanced)" ) << std::endl + << ". maximum number of consecutive failed iterations" << std::endl + << ". arguments: one positive integer" << std::endl + << ". no default" << std::endl + << ". example: MAX_CONSECUTIVE_FAILED_ITERATIONS 5" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MAX_EVAL: + // --------- + if ( display_all || NOMAD::string_find ( "MAX_EVAL ADVANCED BLACK-BOXES BLACKBOXES \ MAXIMUM CACHE BBEVAL \ NUMBER EVALUATIONS STOPPING \ TERMINATES TERMINATION" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MAX_EVAL (advanced)" ) << std::endl - << ". maximum number of evaluations" << std::endl - << ". argument: one positive integer" << std::endl - << ". no default" << std::endl - << ". includes evaluations taken in" << std::endl - << " the cache (cache hits)" << std::endl - << ". example: MAX_EVAL 1000" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MAX_ITERATIONS: - // --------------- - if ( display_all || NOMAD::string_find ( "MAX_ITERATIONS ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MAX_EVAL (advanced)" ) << std::endl + << ". maximum number of evaluations" << std::endl + << ". argument: one positive integer" << std::endl + << ". no default" << std::endl + << ". includes evaluations taken in" << std::endl + << " the cache (cache hits)" << std::endl + << ". example: MAX_EVAL 1000" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MAX_ITERATIONS: + // --------------- + if ( display_all || NOMAD::string_find ( "MAX_ITERATIONS ADVANCED \ MAXIMUM MADS \ NUMBER STOPPING \ TERMINATES TERMINATION" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MAX_ITERATIONS (advanced)" ) << std::endl - << ". maximum number of MADS iterations" << std::endl - << ". argument: one positive integer" << std::endl - << ". no default" << std::endl - << ". example: MAX_ITERATIONS 20" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MAX_MESH_INDEX: - // --------------- - if ( display_all || NOMAD::string_find ( "MAX_MESH_INDEX ADVANCED MAXIMUM \ - \\DELTA TERMINATION \ - STOPPING TERMINATES \\ELL" , param_names ) ) - { - _out << std::endl - << NOMAD::open_block ( "MAX_MESH_INDEX (advanced)" ) << std::endl - << ". maximum mesh index" << std::endl - << ". argument: one nonnegative integer" << std::endl - << ". no default" << std::endl - << ". example: MAX_MESH_INDEX 5" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MAX_SGTE_EVAL: - // -------------- - if ( display_all || NOMAD::string_find ( "MAX_SGTE_EVAL ADVANCED BLACK-BOXES \ + _out << std::endl + << NOMAD::open_block ( "MAX_ITERATIONS (advanced)" ) << std::endl + << ". maximum number of MADS iterations" << std::endl + << ". argument: one positive integer" << std::endl + << ". no default" << std::endl + << ". example: MAX_ITERATIONS 20" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // MAX_SGTE_EVAL: + // -------------- + if ( display_all || NOMAD::string_find ( "MAX_SGTE_EVAL ADVANCED BLACK-BOXES \ BLACKBOXES \ MAXIMUM SURROGATES BBEVAL SGTES \ NUMBER EVALUATIONS STOPPING \ TERMINATES TERMINATION" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MAX_SGTE_EVAL (advanced)" ) << std::endl - << ". maximum number of surrogate evaluations" << std::endl - << ". argument: one positive integer" << std::endl - << ". no default" << std::endl - << ". example: MAX_SGTE_EVAL 10000" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MAX_SIM_BB_EVAL: - // ---------------- - if ( display_all || NOMAD::string_find ( "MAX_SIM_BB_EVAL ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MAX_SGTE_EVAL (advanced)" ) << std::endl + << ". maximum number of surrogate evaluations" << std::endl + << ". argument: one positive integer" << std::endl + << ". no default" << std::endl + << ". example: MAX_SGTE_EVAL 10000" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MAX_SIM_BB_EVAL: + // ---------------- + if ( display_all || NOMAD::string_find ( "MAX_SIM_BB_EVAL ADVANCED \ BLACK-BOXES BLACKBOXES BBEVAL \ MAXIMUM CACHE SIMULATED \ NUMBER EVALUATIONS STOPPING \ TERMINATES TERMINATION" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MAX_SIM_BB_EVAL (advanced)" ) << std::endl - << ". maximum number of simulated blackbox evaluations" << std::endl - << ". argument: one positive integer" << std::endl - << ". no default" << std::endl - << ". the same as MAX_BB_EVAL except that it considers" << std::endl - << " initial cache hits (cache points that come from" << std::endl - << " a cache file)" << std::endl - << ". simulates the number of blackbox evaluations" << std::endl - << " when no cache file is used" << std::endl - << ". example: MAX_SIM_BB_EVAL 1000" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // MESH_COARSENING_EXPONENT: - // ------------------------- - if ( display_all || NOMAD::string_find ( "MESH_COARSENING_EXPONENT ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MAX_SIM_BB_EVAL (advanced)" ) << std::endl + << ". maximum number of simulated blackbox evaluations" << std::endl + << ". argument: one positive integer" << std::endl + << ". no default" << std::endl + << ". the same as MAX_BB_EVAL except that it considers" << std::endl + << " initial cache hits (cache points that come from" << std::endl + << " a cache file)" << std::endl + << ". simulates the number of blackbox evaluations" << std::endl + << " when no cache file is used" << std::endl + << ". example: MAX_SIM_BB_EVAL 1000" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // MESH_COARSENING_EXPONENT: + // ------------------------- + if ( display_all || NOMAD::string_find ( "MESH_COARSENING_EXPONENT ADVANCED \ MADS W+ \\DELTA" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MESH_COARSENING_EXPONENT (advanced)" ) << std::endl - << ". mesh coarsening exponent w^+ used to update the mesh" << std::endl - << " after successes (\\Delta^m_{k+1}=\\tau^{w^+}\\Delta^m_k)" << std::endl - << ". argument: one nonnegative integer" << std::endl - << ". default: 1" << std::endl - << ". example: MESH_COARSENING_EXPONENT 0 # the mesh size is" << std::endl - << " # not increased" << std::endl - << " # after successes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MESH_REFINING_EXPONENT: - // ----------------------- - if ( display_all || NOMAD::string_find ( "MESH_REFINING_EXPONENT ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MESH_COARSENING_EXPONENT (advanced)" ) << std::endl + << ". mesh coarsening exponent w^+ used to update the mesh" << std::endl + << " after successes (\\Delta^m_{k+1}=\\tau^{w^+}\\Delta^m_k)" << std::endl + << ". argument: one nonnegative integer" << std::endl + << ". default: 1" << std::endl + << ". example: MESH_COARSENING_EXPONENT 0 # the mesh size is" << std::endl + << " # not increased" << std::endl + << " # after successes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MESH_REFINING_EXPONENT: + // ----------------------- + if ( display_all || NOMAD::string_find ( "MESH_REFINING_EXPONENT ADVANCED \ MADS W- \\DELTA" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MESH_REFINING_EXPONENT (advanced)" ) << std::endl - << ". mesh refining exponent w^- used to update the mesh" << std::endl - << " after failures (\\Delta^m_{k+1} = \\tau^{w^-}\\Delta^m_k)" << std::endl - << ". argument: one negative" << std::endl - << ". default: -1" << std::endl - << ". example: MESH_REFINING_EXPONENT -2" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MESH_UPDATE_BASIS: - // ------------------ - if ( display_all || NOMAD::string_find ( "MESH_UPDATE_BASIS ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MESH_REFINING_EXPONENT (advanced)" ) << std::endl + << ". mesh refining exponent w^- used to update the mesh" << std::endl + << " after failures (\\Delta^m_{k+1} = \\tau^{w^-}\\Delta^m_k)" << std::endl + << ". argument: one negative" << std::endl + << ". default: -1" << std::endl + << ". example: MESH_REFINING_EXPONENT -2" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MESH_UPDATE_BASIS: + // ------------------ + if ( display_all || NOMAD::string_find ( "MESH_UPDATE_BASIS ADVANCED \ MADS \\TAU \\DELTA" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MESH_UPDATE_BASIS (advanced)" ) << std::endl - << ". mesh update basis \\tau used to update the" << std::endl - << " mesh (\\Delta^m_{k+1} = \\tau^w\\Delta^m_k)" << std::endl - << ". argument: one positive real" << std::endl - << ". default: 4.0" << std::endl - << ". example: MESH_UPDATE_BASIS 2.0" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MIN_MESH_SIZE: - // -------------- - if ( display_all || NOMAD::string_find ( "MIN_MESH_SIZE ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MESH_UPDATE_BASIS (advanced)" ) << std::endl + << ". mesh update basis \\tau used to update the" << std::endl + << " mesh (\\Delta^m_{k+1} = \\tau^w\\Delta^m_k)" << std::endl + << ". argument: one positive real > 1" << std::endl + << ". default: 4.0" << std::endl + << ". example: MESH_UPDATE_BASIS 2.0" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MIN_MESH_SIZE: + // -------------- + if ( display_all || NOMAD::string_find ( "MIN_MESH_SIZE ADVANCED \ \\DELTA MINIMUM TERMINATION \ STOPPING TERMINATES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MIN_MESH_SIZE (advanced)" ) << std::endl - << ". minimum mesh size" << std::endl - << ". arguments: same logic as INITIAL_MESH_SIZE" << std::endl - << " (\'r\' can be used)" << std::endl - << ". no default" << std::endl - << ". example: MIN_MESH_SIZE r1E-5" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MIN_POLL_SIZE: - // -------------- - if ( display_all || NOMAD::string_find ( "MIN_POLL_SIZE MESH ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MIN_MESH_SIZE (advanced)" ) << std::endl + << ". minimum mesh size" << std::endl + << ". arguments: same logic as INITIAL_MESH_SIZE" << std::endl + << " (\'r\' can be used)" << std::endl + << ". no default" << std::endl + << ". example: MIN_MESH_SIZE r1E-5" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MIN_POLL_SIZE: + // -------------- + if ( display_all || NOMAD::string_find ( "MIN_POLL_SIZE MESH ADVANCED \ \\DELTA^P MINIMUM TERMINATION \ STOPPING TERMINATES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MIN_POLL_SIZE (advanced)" ) << std::endl - << ". minimum poll size" << std::endl - << ". arguments: same logic as INITIAL_MESH_SIZE" << std::endl - << " (\'r\' can be used)" << std::endl - << ". default: 1.0 for integer or binary variables, no default otherwise" - << std::endl - << ". example: MIN_POLL_SIZE r1E-5" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // MODEL_EVAL_SORT: - // ---------------- - if ( display_all || NOMAD::string_find ( "MODEL_ORDERING MODEL_EVAL_SORT ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MIN_POLL_SIZE (advanced)" ) << std::endl + << ". minimum poll size" << std::endl + << ". arguments: same logic as INITIAL_MESH_SIZE" << std::endl + << " (\'r\' can be used)" << std::endl + << ". default: 1.0 for integer or binary variables, no default otherwise" + << std::endl + << ". example: MIN_POLL_SIZE r1E-5" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // MODEL_EVAL_SORT: + // ---------------- + if ( display_all || NOMAD::string_find ( "MODEL_ORDERING MODEL_EVAL_SORT ADVANCED \ MODELS INTERPOLATION REGRESSION \ MFN FROBENIUS QUADRATIC \ TGP" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MODEL_EVAL_SORT (advanced)" ) << std::endl - << ". if models are used to sort the trial points" << std::endl - << ". disabled for more than 50 variables" << std::endl - << ". disabled with categorical variables" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << " or one string in {\'QUADRATIC\', \'TGP\'}" << std::endl - << ". default: \'QUADRATIC\'" << std::endl - << ". examples: MODEL_EVAL_SORT quadratic" << std::endl - << " MODEL_EVAL_SORT yes # quadratic is used" << std::endl - << " MODEL_EVAL_SORT no # no MES" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // MODEL_SEARCH: - // ------------- - if ( display_all || NOMAD::string_find ( "MODEL_SEARCH ADVANCED CATEGORICAL \ + _out << std::endl + << NOMAD::open_block ( "MODEL_EVAL_SORT (advanced)" ) << std::endl + << ". if models are used to sort the trial points" << std::endl + << ". disabled for more than 50 variables" << std::endl + << ". disabled with categorical variables" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << " or one string in {\'QUADRATIC\', \'TGP\'}" << std::endl + << ". default: \'QUADRATIC\'" << std::endl + << ". examples: MODEL_EVAL_SORT quadratic" << std::endl + << " MODEL_EVAL_SORT yes # quadratic is used" << std::endl + << " MODEL_EVAL_SORT no # no MES" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // MODEL_SEARCH: + // ------------- + if ( display_all || NOMAD::string_find ( "MODEL_SEARCH ADVANCED CATEGORICAL \ MODELS INTERPOLATION REGRESSION \ MFN FROBENIUS QUADRATIC PARALLEL \ TGP" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MODEL_SEARCH (advanced)" ) << std::endl - << ". model search (MS)" << std::endl - << ". can be entered twice in order to define two searches" << std::endl - << ". disabled for more than 50 variables" << std::endl - << ". disabled with categorical variables" << std::endl - << ". disabled in parallel mode" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << " or one string in {\'QUADRATIC\', \'TGP\'}" << std::endl - << ". default: \'QUADRATIC\'" << std::endl - << ". example: MODEL_SEARCH QUADRATIC" << std::endl - << " MODEL_SEARCH TGP" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - - // MODEL_SEARCH_OPTIMISTIC: - // ------------------------ - if ( display_all || NOMAD::string_find ( "MODEL_SEARCH_OPTIMISTIC ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MODEL_SEARCH (advanced)" ) << std::endl + << ". model search (MS)" << std::endl + << ". can be entered twice in order to define two searches" << std::endl + << ". disabled for more than 50 variables" << std::endl + << ". disabled with categorical variables" << std::endl + << ". disabled in parallel mode" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << " or one string in {\'QUADRATIC\', \'TGP\'}" << std::endl + << ". default: \'QUADRATIC\'" << std::endl + << ". example: MODEL_SEARCH QUADRATIC" << std::endl + << " MODEL_SEARCH TGP" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + + // MODEL_SEARCH_OPTIMISTIC: + // ------------------------ + if ( display_all || NOMAD::string_find ( "MODEL_SEARCH_OPTIMISTIC ADVANCED \ MODELS INTERPOLATION REGRESSION \ MFN FROBENIUS QUADRATIC \ TGP" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MODEL_SEARCH_OPTIMISTIC (advanced)" ) << std::endl - << ". model search (MS) is optimistic or not" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". example: MODEL_SEARCH_OPTIMISTIC no" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // MULTI_F_BOUNDS: - // --------------- - if ( display_all || NOMAD::string_find ( "MULTI_F_BOUNDS ADVANCED PARETO \ + _out << std::endl + << NOMAD::open_block ( "MODEL_SEARCH_OPTIMISTIC (advanced)" ) << std::endl + << ". model search (MS) is optimistic or not" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". example: MODEL_SEARCH_OPTIMISTIC no" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // MULTI_F_BOUNDS: + // --------------- + if ( display_all || NOMAD::string_find ( "MULTI_F_BOUNDS ADVANCED PARETO \ BI-OBJECTIVES MULTI-OBJECTIVES \ BIOBJECTIVES MULTIOBJECTIVES \ BI-MADS BIMADS SURF" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MULTI_F_BOUNDS (advanced)" ) << std::endl - << ". multi-objective optimization: bounds on the two" << std::endl - << " objective functions" << std::endl - << ". arguments: 4 reals: f1_min f1_max f2_min f2_max" << std::endl - << ". default: none" << std::endl - << ". these values are used to display the \'surf\' statistics" << std::endl - << " on Pareto fronts (useful to compare different Pareto" << std::endl - << " fronts)" << std::endl - << ". \'surf\' will not be displayed with invalid values (for example" - << std::endl - << " if a dominant point has a f2 value greater than f2_max)" << std::endl - << ". example: MULTI_F_BOUNDS 0 10 0 10" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // MULTI_NB_MADS_RUNS: - // ------------------- - if ( display_all || NOMAD::string_find ( "MULTI_NB_MADS_RUNS ADVANCED \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "MULTI_F_BOUNDS (advanced)" ) << std::endl + << ". multi-objective optimization: bounds on the two" << std::endl + << " objective functions" << std::endl + << ". arguments: 4 reals: f1_min f1_max f2_min f2_max" << std::endl + << ". default: none" << std::endl + << ". these values are used to display the \'surf\' statistics" << std::endl + << " on Pareto fronts (useful to compare different Pareto" << std::endl + << " fronts)" << std::endl + << ". \'surf\' will not be displayed with invalid values (for example" + << std::endl + << " if a dominant point has a f2 value greater than f2_max)" << std::endl + << ". example: MULTI_F_BOUNDS 0 10 0 10" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // MULTI_NB_MADS_RUNS: + // ------------------- + if ( display_all || NOMAD::string_find ( "MULTI_NB_MADS_RUNS ADVANCED \ BI-OBJECTIVES MULTI-OBJECTIVES \ BIOBJECTIVES MULTIOBJECTIVES \ BI-MADS BIMADS \ NUMBER" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MULTI_NB_MADS_RUNS (advanced)" ) << std::endl - << ". multi-objective optimization:" << std::endl - << " number of MADS runs" << std::endl - << ". argument: one positive integer" << std::endl - << ". default: see user guide" << std::endl - << ". example: MULTI_NB_MADS_RUNS 30" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MULTI_OVERALL_BB_EVAL: - // --------------------- - if ( display_all || NOMAD::string_find ( "MULTI_OVERALL_BB_EVAL ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "MULTI_NB_MADS_RUNS (advanced)" ) << std::endl + << ". multi-objective optimization:" << std::endl + << " number of MADS runs" << std::endl + << ". argument: one positive integer" << std::endl + << ". default: see user guide" << std::endl + << ". example: MULTI_NB_MADS_RUNS 30" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MULTI_OVERALL_BB_EVAL: + // --------------------- + if ( display_all || NOMAD::string_find ( "MULTI_OVERALL_BB_EVAL ADVANCED \ BI-OBJECTIVES MULTI-OBJECTIVES \ BIOBJECTIVES MULTIOBJECTIVES \ BI-MADS BIMADS \ NUMBER BLACK-BOXES BLACKBOXES BBEVAL \ EVALUATIONS TERMINATION \ STOPPING TERMINATES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "MULTI_OVERALL_BB_EVAL (advanced)" ) << std::endl - << ". multi-objective optimization: maximum" << std::endl - << " number of blackbox evaluations" << std::endl - << ". argument: one positive integer" << std::endl - << ". default: see user guide" << std::endl - << ". example: MULTI_OVERALL_BB_EVAL 1000" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - - // NEIGHBORS_EXE: - // -------------- - if ( display_all || NOMAD::string_find ( "NEIGHBORS_EXE NEIGHBOURS \ + _out << std::endl + << NOMAD::open_block ( "MULTI_OVERALL_BB_EVAL (advanced)" ) << std::endl + << ". multi-objective optimization: maximum" << std::endl + << " number of blackbox evaluations" << std::endl + << ". argument: one positive integer" << std::endl + << ". default: see user guide" << std::endl + << ". example: MULTI_OVERALL_BB_EVAL 1000" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + + // NEIGHBORS_EXE: + // -------------- + if ( display_all || NOMAD::string_find ( "NEIGHBORS_EXE NEIGHBOURS \ NEIGHBORHOODS NEIGHBOURHOODS \ EXTENDED_POLL \ MIXED MVP CATEGORICAL \ ADVANCED" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "NEIGHBORS_EXE (advanced)" ) << std::endl - << ". to indicate a neighborhood executable for categorical" << std::endl - << " variables in batch mode" << std::endl - << ". arguments: one string" << std::endl - << ". no default" << std::endl - << ". the executable must take a file with the coordinates of" << std::endl - << " a point as argument and displays a list of neighbors" << std::endl - << ". the number of variables must be the same" << std::endl - << ". when the \'$\' character is put in first position of a" << std::endl - << " string, it is considered as global and no path is added" << std::endl - << ". see user guide for details" << std::endl - << ". example: NEIGHBORS_EXE neighbors.exe" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // OPEN_BRACE: - // ----------- - if ( display_all || NOMAD::string_find ( "OPEN_BRACES INDENTATION TABULATIONS \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "NEIGHBORS_EXE (advanced)" ) << std::endl + << ". to indicate a neighborhood executable for categorical" << std::endl + << " variables in batch mode" << std::endl + << ". arguments: one string" << std::endl + << ". no default" << std::endl + << ". the executable must take a file with the coordinates of" << std::endl + << " a point as argument and displays a list of neighbors" << std::endl + << ". the number of variables must be the same" << std::endl + << ". when the \'$\' character is put in first position of a" << std::endl + << " string, it is considered as global and no path is added" << std::endl + << ". see user guide for details" << std::endl + << ". example: NEIGHBORS_EXE neighbors.exe" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // OPEN_BRACE: + // ----------- + if ( display_all || NOMAD::string_find ( "OPEN_BRACES INDENTATION TABULATIONS \ BLOCKS ADVANCED DISPLAY" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "OPEN_BRACE (advanced)" ) << std::endl - << ". string displayed at the beginning of indented" << std::endl - << " blocks in full display mode" << std::endl - << ". argument: one string" << std::endl - << ". default: \'{\'" << std::endl - << ". example: OPEN_BRACE Begin" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // OPPORTUNISTIC_CACHE_SEARCH: - // --------------------------- - if ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_CACHE_SEARCH ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "OPEN_BRACE (advanced)" ) << std::endl + << ". string displayed at the beginning of indented" << std::endl + << " blocks in full display mode" << std::endl + << ". argument: one string" << std::endl + << ". default: \'{\'" << std::endl + << ". example: OPEN_BRACE Begin" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // OPPORTUNISTIC_CACHE_SEARCH: + // --------------------------- + if ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_CACHE_SEARCH ADVANCED \ BLACK-BOXES BLACKBOXES EVALUATIONS \ SUCCESSES CACHE SEARCH" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "OPPORTUNISTIC_CACHE_SEARCH (advanced)" ) << std::endl - << ". opportunistic strategy for cache search" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'no\'" << std::endl - << ". example: OPPORTUNISTIC_CACHE_SEARCH yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // OPPORTUNISTIC_EVAL: - // ------------------- - if ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_EVAL ADVANCED \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "OPPORTUNISTIC_CACHE_SEARCH (advanced)" ) << std::endl + << ". opportunistic strategy for cache search" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'no\'" << std::endl + << ". example: OPPORTUNISTIC_CACHE_SEARCH yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // OPPORTUNISTIC_EVAL: + // ------------------- + if ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_EVAL ADVANCED \ BLACK-BOXES BLACKBOXES EVALUATIONS \ SUCCESSES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "OPPORTUNISTIC_EVAL (advanced)" ) << std::endl - << ". opportunistic strategy (terminate a list of" << std::endl - << " evaluations after successes)" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". type \'nomad -h opportunistic\' to see advanced options" << std::endl - << ". example: OPPORTUNISTIC_EVAL no # complete evaluations" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // OPPORTUNISTIC_LH: - // ----------------- - if ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_LH ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "OPPORTUNISTIC_EVAL (advanced)" ) << std::endl + << ". opportunistic strategy (terminate a list of" << std::endl + << " evaluations after successes)" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". type \'nomad -h opportunistic\' to see advanced options" << std::endl + << ". example: OPPORTUNISTIC_EVAL no # complete evaluations" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // OPPORTUNISTIC_LH: + // ----------------- + if ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_LH ADVANCED \ BLACK-BOXES BLACKBOXES EVALUATIONS \ SUCCESSES LATIN-HYPERCUBE SEARCH" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "OPPORTUNISTIC_LH (advanced)" ) << std::endl - << ". opportunistic strategy for Latin-Hypercube search" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: same value as OPPORTUNISTIC_EVAL" << std::endl - << ". example: OPPORTUNISTIC_LH no # complete evaluations" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - - // OPPORTUNISTIC_MIN_EVAL: - // ----------------------- - if ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_MIN_EVAL ADVANCED \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "OPPORTUNISTIC_LH (advanced)" ) << std::endl + << ". opportunistic strategy for Latin-Hypercube search" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: same value as OPPORTUNISTIC_EVAL" << std::endl + << ". example: OPPORTUNISTIC_LH no # complete evaluations" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + + // OPPORTUNISTIC_MIN_EVAL: + // ----------------------- + if ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_MIN_EVAL ADVANCED \ BLACK-BOXES BLACKBOXES EVALUATIONS \ SUCCESSES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "OPPORTUNISTIC_MIN_EVAL (advanced)" ) << std::endl - << ". advanced parameter for the opportunistic" << std::endl - << " strategy (see user guide)" << std::endl - << ". argument: one nonnegative integer" << std::endl - << ". no default" << std::endl - << ". example: OPPORTUNISTIC_MIN_EVAL 3" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // PERIODIC_VARIABLE: - // ------------------ - if ( display_all || NOMAD::string_find ( "PERIODIC_VARIABLE VARIABLES ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "OPPORTUNISTIC_MIN_EVAL (advanced)" ) << std::endl + << ". advanced parameter for the opportunistic" << std::endl + << " strategy (see user guide)" << std::endl + << ". argument: one nonnegative integer" << std::endl + << ". no default" << std::endl + << ". example: OPPORTUNISTIC_MIN_EVAL 3" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // PERIODIC_VARIABLE: + // ------------------ + if ( display_all || NOMAD::string_find ( "PERIODIC_VARIABLE VARIABLES ADVANCED \ BOUNDS LB UB CYCLIC MADS" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "PERIODIC_VARIABLE (advanced)" ) << std::endl - << ". specify that some variables are periodic" << std::endl - << ". arguments: variable indexes" << std::endl - << ". no default" << std::endl - << ". bounds must be defined for these variables" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "PERIODIC_VARIABLE * # all variables are periodic" << std::endl - << "PERIODIC_VARIABLE 0-1 # 2 first var. are periodic" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - // POINT_DISPLAY_LIMIT: - // -------------------- - if ( display_all || NOMAD::string_find ( "POINT_DISPLAY_LIMIT OUTPUTS \ + _out << std::endl + << NOMAD::open_block ( "PERIODIC_VARIABLE (advanced)" ) << std::endl + << ". specify that some variables are periodic" << std::endl + << ". arguments: variable indexes" << std::endl + << ". no default" << std::endl + << ". bounds must be defined for these variables" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "PERIODIC_VARIABLE * # all variables are periodic" << std::endl + << "PERIODIC_VARIABLE 0-1 # 2 first var. are periodic" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + // POINT_DISPLAY_LIMIT: + // -------------------- + if ( display_all || NOMAD::string_find ( "POINT_DISPLAY_LIMIT OUTPUTS \ ADVANCED PRECISION" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "POINT_DISPLAY_LIMIT (advanced)" ) << std::endl - << ". maximum number of point coordinates" << std::endl - << " that are displayed" << std::endl - << ". argument: one positive integer" << std::endl - << ". default: 20" << std::endl - << ". example: POINT_DISPLAY_LIMIT 10" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // RHO: - // ---- - if ( display_all || NOMAD::string_find ( "RHO ADVANCED MADS CONSTRAINTS \ + _out << std::endl + << NOMAD::open_block ( "POINT_DISPLAY_LIMIT (advanced)" ) << std::endl + << ". maximum number of point coordinates" << std::endl + << " that are displayed" << std::endl + << ". argument: one positive integer" << std::endl + << ". default: 20" << std::endl + << ". example: POINT_DISPLAY_LIMIT 10" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // POLL_UPDATE_BASIS: + // ------------------ + if ( display_all || NOMAD::string_find ( "POLL_UPDATE_BASIS ADVANCED \ + MADS ANISOTROPIC MESH \\TAU \\DELTA" , param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "POLL_UPDATE_BASIS (advanced)" ) << std::endl + << ". poll update basis \\tau used to update the" << std::endl + << " poll (\\Delta^{k+1} = \\tau^w\\Delta^k)" << std::endl + << ". argument: one positive real > 1" << std::endl + << ". default: 2.0" << std::endl + << ". example: POLL_UPDATE_BASIS 1.5" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // RHO: + // ---- + if ( display_all || NOMAD::string_find ( "RHO ADVANCED MADS CONSTRAINTS \ PROGRESSIVE-BARRIER PB PEB \ FILTER TRIGGER" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "RHO (advanced)" ) << std::endl - << ". rho parameter of the progressive barrier" << std::endl - << ". argument: one nonnegative real" << std::endl - << ". default: 0.1" << std::endl - << ". example: RHO 0.5" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // SCALING: - // -------- - if ( display_all || NOMAD::string_find ( "SCALING SCALE ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "RHO (advanced)" ) << std::endl + << ". rho parameter of the progressive barrier" << std::endl + << ". argument: one nonnegative real" << std::endl + << ". default: 0.1" << std::endl + << ". example: RHO 0.5" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // SCALING: + // -------- + if ( display_all || NOMAD::string_find ( "SCALING SCALE ADVANCED \ FILES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "SCALING (advanced)" ) << std::endl - << ". variable scaling" << std::endl - << ". arguments: variable indexes and values" << std::endl - << ". no default" << std::endl - << ". variables are multiplied by these values: they are scaled" << std::endl - << " before an evaluation and the call to Evaluator::eval_x()," << std::endl - << " and unscaled after the evaluation" << std::endl - << ". all NOMAD outputs (including files) display unscaled values" << std::endl - << ". all variable-related parameters (bounds, starting points," << std::endl - << " fixed variables) must be specified without scaling" << std::endl - << ". can be given by a text file containing DIMENSION entries" << std::endl - << " (use \'-\' for unscaled variables)" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "SCALING ( 0.1 - 100 ) # variables 0 and 2 are scaled" << std::endl - << "SCALING scaling.txt # with a file" << std::endl - << "SCALING 0-1 10.0 # 2 first variables scaled" << std::endl - << " # by factor 10" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - - // SEED: - // ----- - if ( display_all || NOMAD::string_find ( "SEED ADVANCED \ - RANDOM FILES LT-MADS LTMADS \ + _out << std::endl + << NOMAD::open_block ( "SCALING (advanced)" ) << std::endl + << ". variable scaling" << std::endl + << ". arguments: variable indexes and values" << std::endl + << ". no default" << std::endl + << ". variables are multiplied by these values: they are scaled" << std::endl + << " before an evaluation and the call to Evaluator::eval_x()," << std::endl + << " and unscaled after the evaluation" << std::endl + << ". all NOMAD outputs (including files) display unscaled values" << std::endl + << ". all variable-related parameters (bounds, starting points," << std::endl + << " fixed variables) must be specified without scaling" << std::endl + << ". can be given by a text file containing DIMENSION entries" << std::endl + << " (use \'-\' for unscaled variables)" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "SCALING ( 0.1 - 100 ) # variables 0 and 2 are scaled" << std::endl + << "SCALING scaling.txt # with a file" << std::endl + << "SCALING 0-1 10.0 # 2 first variables scaled" << std::endl + << " # by factor 10" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + + // SEED: + // ----- + if ( display_all || NOMAD::string_find ( "SEED ADVANCED \ + RANDOM FILES ORTHOMADS LT-MADS LTMADS \ LATIN-HYPERCUBE LH TGP \ SAMPLING SEARCH" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "SEED (advanced)" ) << std::endl - << ". random seed" << std::endl - << ". argument: one integer or the string \'NONE\'" << std::endl - << ". default: \'NONE\'" << std::endl - << ". the random seed is different at each run if" << std::endl - << " \'NONE\' or a negative integer is entered" << std::endl - << ". the seed is used in the output file names" << std::endl - << ". randomness is used for LT-MADS directions," << std::endl - << " Latin-Hypercube search, and TGP search." << std::endl - << ". example: SEED 100" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - - // SGTE_CACHE_FILE: - // ---------------- - if ( display_all || NOMAD::string_find ( "SGTE_CACHE_FILE ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "SEED (advanced)" ) << std::endl + << ". random seed" << std::endl + << ". argument: one integer in [0," << UINT32_MAX << "] U {-1} or the string \'DIFF\'" << std::endl + << ". default: \'" << NOMAD::RNG::get_seed() << "\'" << std::endl + << ". the default value is used for each run if" << std::endl + << " the parameter is not provided. " << std::endl + << ". if '-1' or \'DIFF\' is entered " << std::endl + << " the seed is different for each run (PID is used)." << std::endl + << ". the seed is used in the output file names" << std::endl + << ". the seed affects the randomness of " << std::endl + << " Ortho-MADS and LT-MADS directions," << std::endl + << " Latin-Hypercube search, and TGP search." << std::endl + << ". example: SEED 123456" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + + // SGTE_CACHE_FILE: + // ---------------- + if ( display_all || NOMAD::string_find ( "SGTE_CACHE_FILE ADVANCED \ SURROGATES SGTES \ FILES OUTPUTS" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "SGTE_CACHE_FILE (advanced)" ) << std::endl - << ". surrogate cache file; cannot be the same" << std::endl - << " as CACHE_FILE" << std::endl - << ". argument: one string" << std::endl - << ". no default" << std::endl - << ". points already in the file will be tagged" << std::endl - << " as surrogate evaluations" << std::endl - << ". example: SGTE_CACHE_FILE sgte_cache.bin" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // SGTE_COST: - // ---------- - if ( display_all || NOMAD::string_find ( "SGTE_COST SURROGATES SGTES ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "SGTE_CACHE_FILE (advanced)" ) << std::endl + << ". surrogate cache file; cannot be the same" << std::endl + << " as CACHE_FILE" << std::endl + << ". argument: one string" << std::endl + << ". no default" << std::endl + << ". points already in the file will be tagged" << std::endl + << " as surrogate evaluations" << std::endl + << ". example: SGTE_CACHE_FILE sgte_cache.bin" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // SGTE_COST: + // ---------- + if ( display_all || NOMAD::string_find ( "SGTE_COST SURROGATES SGTES ADVANCED \ BLACK-BOXES BLACKBOXES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "SGTE_COST (advanced)" ) << std::endl - << ". cost of the surrogate function relatively" << std::endl - << " to the true function" << std::endl - << ". argument: one nonnegative integer" << std::endl - << ". default: infinity (no surrogate cost)" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "SGTE_COST 3 # three surrogate evaluations" << std::endl - << " # count as one blackbox" << std::endl - << " # evaluation (the surrogate" << std::endl - << " # is three times faster)" << std::endl - << "SGTE_COST -1 # set to infinity" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - // SGTE_EVAL_SORT: - // --------------- - if ( display_all || NOMAD::string_find ( "SGTE_EVAL_SORT ADVANCED SURROGATES \ + _out << std::endl + << NOMAD::open_block ( "SGTE_COST (advanced)" ) << std::endl + << ". cost of the surrogate function relatively" << std::endl + << " to the true function" << std::endl + << ". argument: one nonnegative integer" << std::endl + << ". default: infinity (no surrogate cost)" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "SGTE_COST 3 # three surrogate evaluations" << std::endl + << " # count as one blackbox" << std::endl + << " # evaluation (the surrogate" << std::endl + << " # is three times faster)" << std::endl + << "SGTE_COST -1 # set to infinity" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + // SGTE_EVAL_SORT: + // --------------- + if ( display_all || NOMAD::string_find ( "SGTE_EVAL_SORT ADVANCED SURROGATES \ SGTE_ORDERING SGTES BLACK-BOXES \ BLACKBOXES" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "SGTE_EVAL_SORT (advanced)" ) << std::endl - << ". if surrogate is used to sort the trial points" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". example: SGTE_EVAL_SORT NO" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // SGTE_EXE: - // ---------- - if ( display_all || NOMAD::string_find ( "SGTE_EXE HAS_SGTE ADVANCED SURROGATES \ + _out << std::endl + << NOMAD::open_block ( "SGTE_EVAL_SORT (advanced)" ) << std::endl + << ". if surrogate is used to sort the trial points" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". example: SGTE_EVAL_SORT NO" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // SGTE_EXE: + // ---------- + if ( display_all || NOMAD::string_find ( "SGTE_EXE HAS_SGTE ADVANCED SURROGATES \ SGTES BLACK-BOXES BLACKBOXES \ FILES EXECUTABLE" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "SGTE_EXE (advanced)" ) << std::endl - << ". to indicate a surrogate executable" << std::endl - << ". arguments: one or two strings" << std::endl - << ". no default" << std::endl - << ". surrogate(s) and blackbox(es) must have the same" << std::endl - << " number of outputs" << std::endl - << ". if surrogates are used, every blackbox executable" << std::endl - << " must have a surrogate" - << std::endl - << ". automatically sets HAS_SGTE to \'yes\'" << std::endl - << ". " << NOMAD::open_block ( "examples" ) << std::endl - << "SGTE_EXE b1.exe s1.exe # \'s1.exe\' is a surrogate" << std::endl - << " # for \'b1.exe\'" << std::endl << std::endl - << "SGTE_EXE sgte.exe # only if one blackbox" << std::endl - << " # executable is used" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - // SNAP_TO_BOUNDS: - // --------------- - if ( display_all || NOMAD::string_find ( "SNAP_TO_BOUNDS PROJECTION \ + _out << std::endl + << NOMAD::open_block ( "SGTE_EXE (advanced)" ) << std::endl + << ". to indicate a surrogate executable" << std::endl + << ". arguments: one or two strings" << std::endl + << ". no default" << std::endl + << ". surrogate(s) and blackbox(es) must have the same" << std::endl + << " number of outputs" << std::endl + << ". if surrogates are used, every blackbox executable" << std::endl + << " must have a surrogate" + << std::endl + << ". automatically sets HAS_SGTE to \'yes\'" << std::endl + << ". " << NOMAD::open_block ( "examples" ) << std::endl + << "SGTE_EXE b1.exe s1.exe # \'s1.exe\' is a surrogate" << std::endl + << " # for \'b1.exe\'" << std::endl << std::endl + << "SGTE_EXE sgte.exe # only if one blackbox" << std::endl + << " # executable is used" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + // SNAP_TO_BOUNDS: + // --------------- + if ( display_all || NOMAD::string_find ( "SNAP_TO_BOUNDS PROJECTION \ ADVANCED" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "SNAP_TO_BOUNDS (advanced)" ) << std::endl - << ". if \'yes\', snap to bounds points generated" << std::endl - << " outside boundaries" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". example: SNAP_TO_BOUNDS no" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // SPECULATIVE_SEARCH: - // ------------------- - if ( display_all || NOMAD::string_find ( "SPECULATIVE_SEARCH MADS OPTIMISTIC \ + _out << std::endl + << NOMAD::open_block ( "SNAP_TO_BOUNDS (advanced)" ) << std::endl + << ". if \'yes\', snap to bounds points generated" << std::endl + << " outside boundaries" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". example: SNAP_TO_BOUNDS no" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // SPECULATIVE_SEARCH: + // ------------------- + if ( display_all || NOMAD::string_find ( "SPECULATIVE_SEARCH MADS OPTIMISTIC \ ADVANCED" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "SPECULATIVE_SEARCH (advanced)" ) << std::endl - << ". MADS speculative_search (optimistic strategy)" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". example: SPECULATIVE_SEARCH no" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // STAT_SUM_TARGET: - // ---------------- - if ( display_all || NOMAD::string_find ( "STAT_SUM_TARGET ADVANCED TERMINATION \ + _out << std::endl + << NOMAD::open_block ( "SPECULATIVE_SEARCH (advanced)" ) << std::endl + << ". MADS speculative_search (optimistic strategy)" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". example: SPECULATIVE_SEARCH no" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // STAT_SUM_TARGET: + // ---------------- + if ( display_all || NOMAD::string_find ( "STAT_SUM_TARGET ADVANCED TERMINATION \ STOPPING TERMINATES STATS" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "STAT_SUM_TARGET (advanced)" ) << std::endl - << ". MADS terminates if STAT_SUM reaches the value of this" << std::endl - << " parameter (STAT_SUM is one of the possible outputs" << std::endl - << " defined in BB_OUTPUT_TYPE)" << std::endl - << ". argument: one real" << std::endl - << ". no default" << std::endl - << ". example: STAT_SUM_TARGET 100.0" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // STOP_IF_FEASIBLE: - // ----------------- - if ( display_all || NOMAD::string_find ( "STOP_IF_FEASIBLE ADVANCED \ + _out << std::endl + << NOMAD::open_block ( "STAT_SUM_TARGET (advanced)" ) << std::endl + << ". MADS terminates if STAT_SUM reaches the value of this" << std::endl + << " parameter (STAT_SUM is one of the possible outputs" << std::endl + << " defined in BB_OUTPUT_TYPE)" << std::endl + << ". argument: one real" << std::endl + << ". no default" << std::endl + << ". example: STAT_SUM_TARGET 100.0" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // STOP_IF_FEASIBLE: + // ----------------- + if ( display_all || NOMAD::string_find ( "STOP_IF_FEASIBLE ADVANCED \ TERMINATES TERMINATION STOPPING" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "STOP_IF_FEASIBLE (advanced)" ) << std::endl - << ". the algorithm terminates if it generates" << std::endl - << " a feasible solution" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'no\'" << std::endl - << ". example: STOP_IF_FEASIBLE yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // UNDEF_STR: - // ---------- - if ( display_all || NOMAD::string_find ( "UNDEF_STR ADVANCED \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "STOP_IF_FEASIBLE (advanced)" ) << std::endl + << ". the algorithm terminates if it generates" << std::endl + << " a feasible solution" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'no\'" << std::endl + << ". example: STOP_IF_FEASIBLE yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // UNDEF_STR: + // ---------- + if ( display_all || NOMAD::string_find ( "UNDEF_STR ADVANCED \ UNDEFINED DISPLAY REALS" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "UNDEF_STR (advanced)" ) << std::endl - << ". string used to display undefined real values" << std::endl - << ". argument: one string" << std::endl - << ". default: \"-\"" << std::endl - << ". example: UNDEF_STR Undefined" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // USER_CALLS_ENABLED: - // ------------------- - if ( display_all || NOMAD::string_find ( "USER_CALLS_ENABLED USER_CALLS_DISABLED \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "UNDEF_STR (advanced)" ) << std::endl + << ". string used to display undefined real values" << std::endl + << ". argument: one string" << std::endl + << ". default: \"-\"" << std::endl + << ". example: UNDEF_STR Undefined" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // USER_CALLS_ENABLED: + // ------------------- + if ( display_all || NOMAD::string_find ( "USER_CALLS_ENABLED USER_CALLS_DISABLED \ ADVANCED LIBRARY" , - param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "USER_CALLS_ENABLED (advanced)" ) << std::endl - << ". if \'no\', the automatic calls to user" << std::endl - << " functions are disabled" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". example: USER_CALLS_ENABLED yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // VARIABLE_GROUP: - // -------------- - if ( display_all || NOMAD::string_find ( "VARIABLE_GROUP GROUPS PSD-MADS PSDMADS \ + param_names ) ) { + _out << std::endl + << NOMAD::open_block ( "USER_CALLS_ENABLED (advanced)" ) << std::endl + << ". if \'no\', the automatic calls to user" << std::endl + << " functions are disabled" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". example: USER_CALLS_ENABLED yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // VARIABLE_GROUP: + // -------------- + if ( display_all || NOMAD::string_find ( "VARIABLE_GROUP GROUPS PSD-MADS PSDMADS \ VARIABLES ADVANCED" , param_names ) ) { - _out << std::endl - << NOMAD::open_block ( "VARIABLE_GROUP (advanced)" ) << std::endl - << ". defines groups of variables" << std::endl - << ". MADS directions are applied separately for" << std::endl - << " each group" << std::endl - << ". also used by PSD-MADS (not yet implemented)" << std::endl - << ". groups cannot include fixed variables" << std::endl - << ". arguments: variable indexes" << std::endl - << ". default groups are created for different types" << std::endl - << " of variables" << std::endl - << ". no other default" << std::endl - << ". advanced options only available in library mode" << std::endl - << " (see user guide)" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "VARIABLE_GROUP 2-5" << std::endl - << "VARIABLE_GROUP 0 1 3" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - - // VNS_SEARCH: - // ----------- - if ( display_all || NOMAD::string_find ( "VNS_SEARCH NEIGHBORHOOD \ + _out << std::endl + << NOMAD::open_block ( "VARIABLE_GROUP (advanced)" ) << std::endl + << ". defines groups of variables" << std::endl + << ". MADS directions are applied separately for" << std::endl + << " each group" << std::endl + << ". also used by PSD-MADS (not yet implemented)" << std::endl + << ". groups cannot include fixed variables" << std::endl + << ". arguments: variable indexes" << std::endl + << ". default groups are created for different types" << std::endl + << " of variables" << std::endl + << ". no other default" << std::endl + << ". advanced options only available in library mode" << std::endl + << " (see user guide)" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "VARIABLE_GROUP 2-5" << std::endl + << "VARIABLE_GROUP 0 1 3" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + + // VNS_SEARCH: + // ----------- + if ( display_all || NOMAD::string_find ( "VNS_SEARCH NEIGHBORHOOD \ METAHEURISTICS META-HEURISTICS \ GLOBAL ADVANCED \ TRIGGER" , - param_names ) ) { - - if ( !NOMAD::string_find ( "RHO" , param_names ) ) { - - _out << std::endl - << NOMAD::open_block ( "VNS_SEARCH (advanced)" ) << std::endl - << ". Variable Neighborhood Search (VNS) search" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << " or one real in [0;1] for the VNS trigger" << std::endl - << ". default: \'no\' (same as 0.0)" << std::endl - << ". the VNS trigger is the maximum desired ratio of" << std::endl - << " VNS blackbox evaluations over the total number" << std::endl - << " of blackbox evaluations" << std::endl - << ". the VNS search is never executed with a null trigger" << std::endl - << " while a value of 1 allows the search at every" << std::endl - << " iteration" << std::endl - << ". if VNS_SEARCH=\'yes\', the default value of 0.75 is" << std::endl - << " taken for the trigger" << std::endl - << ". VNS search uses the surrogate if HAS_SGTE or" << std::endl - << " SGTE_EXE is defined" << std::endl - << ". " << NOMAD::open_block ( "examples" ) - << "VNS_SEARCH yes # VNS trigger of 75%" << std::endl - << "VNS_SEARCH 0.5 # VNS trigger of 50%" << std::endl - << NOMAD::close_block() << NOMAD::close_block(); - chk = true; - } - } - - - - // last display: - if ( !chk && !developer) { - - std::string pname = ( pnames.size() == 1 ) ? - ("\'" + *pnames.begin() + "\'") : - "the specified list of parameter names"; - - _out << std::endl << "no help available for " << pname << std::endl - << "help example: \'nomad -h mesh\' displays help on the mesh parameters" - << std::endl; - } - - if (developer && NOMAD::string_find(registered_key_developer,param_names)) - { - _out << "--------------------------------------------------------------" << endl; - _out << "---------------------DEVELOPER PARAMETERS---------------------" << endl; - _out << "--------------------------------------------------------------" << endl; - } - - // EPSILON: - // -------- - if ( developer && (display_all || NOMAD::string_find ( "EPSILON DEVELOPPER \ - PRECISION REALS COMPARISONS" , - param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "EPSILON (developer)" ) << std::endl - << ". precision on reals" << std::endl - << ". argument: one positive real" << std::endl - << ". default: 1E-13" << std::endl - << ". example: EPSILON 1E-8" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // L_CURVE_TARGET: - // --------------- - if ( developer && ( display_all || NOMAD::string_find ( "L_CURVE_TARGET DEVELOPER TERMINATION \ - STOPPING TERMINATES" , param_names ) ) ){ - _out << std::endl - << NOMAD::open_block ( "L_CURVE_TARGET (developer)" ) << std::endl - << ". MADS terminates if it detects that the objective will" << std::endl - << " not reach this value (based on an approximation" << std::endl - << " of the L-shaped curve obj_value v.s. bb_eval)" << std::endl - << ". argument: one real" << std::endl - << ". no default" << std::endl - << ". example: L_CURVE_TARGET 10.0" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // MODEL_EVAL_SORT_CAUTIOUS: - // ------------------------- - if ( developer && ( display_all || NOMAD::string_find ( "MODEL_ORDERING MODEL_EVAL_SORT_CAUTIOUS \ - MODELS INTERPOLATION REGRESSION \ - MFN FROBENIUS DEVELOPER \ - QUADRATIC TGP" , param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "MODEL_EVAL_SORT_CAUTIOUS (developer)" ) << std::endl - << ". if the model ordering strategy is cautious, meaning" << std::endl - << " that models are evaluated only within a trust radius" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". example: MODEL_EVAL_SORT_CAUTIOUS no" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MODEL_QUAD_MAX_Y_SIZE: - // ---------------------- - if ( developer && ( display_all || NOMAD::string_find ( "MODEL_QUAD_MAX_Y_SIZE MODEL_SEARCH DEVELOPER \ - MODELS INTERPOLATION REGRESSION \ - MFN FROBENIUS QUADRATIC" , param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "MODEL_QUAD_MAX_Y_SIZE (developer)" ) << std::endl - << ". Sup. limit on the size of interp. set Y for quadr. models" << std::endl - << ". arguments: one integer greater than the number of variables" << std::endl - << ". default: 500" << std::endl - << ". example: MODEL_QUAD_MAX_Y_SIZE 10" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MODEL_QUAD_MIN_Y_SIZE: - // ---------------------- - if ( developer && (display_all || NOMAD::string_find ( "MODEL_QUAD_MIN_Y_SIZE MODEL_SEARCH DEVELOPER \ - MODELS INTERPOLATION REGRESSION \ - MFN FROBENIUS QUADRATIC" , param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "MODEL_QUAD_MIN_Y_SIZE (developer)" ) << std::endl - << ". Inf. limit on the size of interp. set Y for quadr. models" << std::endl - << ". arguments: one integer > 1 or the string \'N+1\'" << std::endl - << ". default: N+1" << std::endl - << ". examples: MODEL_QUAD_MIN_Y_SIZE N+1" << std::endl - << " MODEL_QUAD_MIN_Y_SIZE -1 # same as N+1" << std::endl - << " MODEL_QUAD_MIN_Y_SIZE 2" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MODEL_QUAD_RADIUS_FACTOR: - // ------------------------- - if ( developer && ( display_all || NOMAD::string_find ( "MODEL_QUAD_RADIUS_FACTOR MODEL_SEARCH \ - DEVELOPER MODELS INTERPOLATION REGRESSION \ - MFN FROBENIUS QUADRATIC" , param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "MODEL_QUAD_RADIUS_FACTOR (developer)" ) << std::endl - << ". quadratic model search radius factor (see user guide)" << std::endl - << ". arguments: one strictly positive real" << std::endl - << ". default: 2.0" << std::endl - << ". example: MODEL_QUAD_RADIUS_FACTOR 1.0" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MODEL_SEARCH_MAX_TRIAL_PTS: - // --------------------------- - if ( developer && ( display_all || NOMAD::string_find ( "MODEL_SEARCH_MAX_TRIAL_PTS \ - DEVELOPER MODELS INTERPOLATION REGRESSION \ - MFN FROBENIUS QUADRATIC \ - TGP" , param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "MODEL_SEARCH_MAX_TRIAL_PTS (developer)" ) << std::endl - << ". limit on the number of trial points for one model search" << std::endl - << ". arguments: one integer greater than or equal to 1" << std::endl - << ". the quadratic model search will not generate more than 4 points" << std::endl - << ". default: 10" << std::endl - << ". example: MODEL_SEARCH_MAX_TRIAL_PTS 1" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MODEL_SEARCH_PROJ_TO_MESH: - // -------------------------- - if ( developer && ( display_all || NOMAD::string_find ( "MODEL_SEARCH_PROJ_TO_MESH DEVELOPER \ - MODELS INTERPOLATION REGRESSION \ - MFN FROBENIUS QUADRATIC PROJECTION \ - TGP" , param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "MODEL_SEARCH_PROJ_TO_MESH (developer)" ) << std::endl - << ". if model search trial points are projected to the mesh" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". example: MODEL_SEARCH_PROJ_TO_MESH no" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MODEL_QUAD_USE_WP: - // ------------------ - if ( developer && ( display_all || NOMAD::string_find ( "MODEL_QUAD_USE_WP DEVELOPER \ - WELL-POISEDNESS \ - MODELS INTERPOLATION REGRESSION \ - MFN FROBENIUS QUADRATIC" , param_names ) ) ){ - _out << std::endl - << NOMAD::open_block ( "MODEL_QUAD_USE_WP (developer)" ) << std::endl - << ". enable the strategy to maintain WP with quadr. models" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'no\'" << std::endl - << ". example: MODEL_QUAD_USE_WP yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // MODEL_NP1_QUAD_EPSILON : - // --------------- - if ( developer && (display_all || NOMAD::string_find ( "MODEL MODELS NP1 QUAD EPSILON \ - ORTHO N+1 QUAD DEVELOPER" , - param_names ) ) ){ - _out << std::endl - << NOMAD::open_block ( "MODEL_NP1_QUAD_EPSILON (developer)" ) << std::endl - << ". with the direction type ORTHO N+1 QUAD selected the" << std::endl - << " (n+1)-th direction is determined within a truncated " << std::endl - << " unit hypercube ]epsilon;1[^n defined by the first " << std::endl - << " n-th directions. The truncation is on lower limit " << std::endl - << " and is defined with a single argument (epsilon)." << std::endl - << ". argument: real in ]0;1[" << std::endl - << ". default: 0.01" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // MODEL_TGP_MODE: - // --------------- - if ( developer && (display_all || NOMAD::string_find ( "MODEL_TGP_MODE MODEL_SEARCH DEVELOPER \ - MODELS INTERPOLATION REGRESSION \ - TGP" , param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "MODEL_TGP_MODE (developer)" ) << std::endl - << ". TGP mode (fast or precise)" << std::endl - << ". arguments: one string in {\'FAST\', \'PRECISE\'}" << std::endl - << ". default: \'FAST\'" << std::endl - << ". example: MODEL_TGP_MODE PRECISE" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MODEL_TGP_REUSE_MODEL: - // ---------------------- - if (developer && ( display_all || NOMAD::string_find ( "MODEL_TGP_REUSE_MODEL DEVELOPER \ - MODELS INTERPOLATION REGRESSION \ - TGP" , param_names ) ) ){ - _out << std::endl - << NOMAD::open_block ( "MODEL_TGP_REUSE_MODEL (developer)" ) << std::endl - << ". enable to use the last model from the TGP search for" << std::endl - << " the TGP model eval sort strategy." << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'yes\'" << std::endl - << ". example: MODEL_TGP_REUSE_MODEL no" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // MULTI_FORMULATION: - // ----------------- - if ( developer && (display_all || NOMAD::string_find ( "MULTI_FORMULATION DEVELOPER PARETO \ - BI-OBJECTIVES MULTI-OBJECTIVES\ - BIOBJECTIVES MULTIOBJECTIVES \ - BI-MADS BIMADS" , - param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "MULTI_FORMULATION (developer)" ) << std::endl - << ". multi-objective optimization: single-objective reformulation" - << std::endl - << ". argument: one string in {\'NORMALIZED\', \'PRODUCT\', \'DIST_L1\'," - << std::endl - << " \'DIST_L2\', \'DIST_LINF\'}" << std::endl - << " (\'NORMALIZED\' and \'DIST_LINF\' are equivalent)" << std::endl - << ". default: \'PRODUCT\' or \'DIST_L2\' if VNS_SEARCH is set to \'yes\'" - << std::endl - << ". example: MULTI_FORMULATION DIST_L1" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - // MULTI_USE_DELTA_CRIT: - // --------------------- - if ( developer && ( display_all || NOMAD::string_find ( "MULTI_USE_DELTA_CRITERION DEVELOPER PARETO \ - BIOBJECTIVES MULTIOBJECTIVES \ - BI-MADS BIMADS \ - BI-OBJECTIVES MULTI-OBJECTIVES" , - param_names ) ) ){ - _out << std::endl - << NOMAD::open_block ( "MULTI_USE_DELTA_CRIT (developer)" ) << std::endl - << ". multi-objective optimization: use the delta criterion" << std::endl - << " (can result in a better distributed Pareto front)" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'no\'" << std::endl - << ". example: MULTI_USE_DELTA_CRIT yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // OPPORTUNISTIC_LUCKY_EVAL: - // ------------------------- - if ( developer && ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_LUCKY_EVAL DEVELOPER \ - BLACK-BOXES BLACKBOXES EVALUATIONS \ - SUCCESSES" , param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "OPPORTUNISTIC_LUCKY_EVAL (developer)" ) << std::endl - << ". developer parameter for the opportunistic" << std::endl - << " strategy" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". default: \'no\'" << std::endl - << ". example: OPPORTUNISTIC_LUCKY_EVAL yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // OPPORTUNISTIC_MIN_F_IMPRVMT: - // ---------------------------- - if ( developer && ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_MIN_F_IMPRVMT DEVELOPER \ - OBJECTIVE \ - BLACK-BOXES BLACKBOXES EVALUATIONS \ - SUCCESSES IMPROVEMENT" , param_names ) ) ) { - _out << std::endl - << NOMAD::open_block ( "OPPORTUNISTIC_MIN_F_IMPRVMT (developer)" ) << std::endl - << ". advanced parameter for the opportunistic" << std::endl - << " strategy (see user guide)" << std::endl - << ". argument: one real" << std::endl - << ". no default" << std::endl - << ". example: OPPORTUNISTIC_MIN_F_IMPRVMT 0.1" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // OPPORTUNISTIC_MIN_NB_SUCCESS: - // ----------------------------- - if ( developer && ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_MIN_NB_SUCCESSES DEVELOPER \ - BLACK-BOXES BLACKBOXES \ - EVALUATIONS" , param_names ) ) ){ - _out << std::endl - << NOMAD::open_block ( "OPPORTUNISTIC_MIN_NB_SUCCESS (developer)" ) << std::endl - << ". advanced parameter for the opportunistic" << std::endl - << " strategy (see user guide)" << std::endl - << ". argument: one nonnegative integer" << std::endl - << ". no default" << std::endl - << ". example: OPPORTUNISTIC_MIN_NB_SUCCESS 2" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // OPT_ONLY_SGTE: - // -------------- - if (developer && ( display_all || NOMAD::string_find ( "OPT_ONLY_SGTES DEVELOPER SURROGATES \ - BLACK-BOXES BLACKBOXES \ - SGTES" , param_names ) ) ){ - _out << std::endl - << NOMAD::open_block ( "OPT_ONLY_SGTE (developer)" ) << std::endl - << ". NOMAD will only minimize the surrogate" << std::endl - << ". argument: one boolean (\'yes\' or \'no\')" << std::endl - << ". SGTE_EXE or HAS_SGTE must be defined" << std::endl - << ". default: \'no\'" << std::endl - << ". example: OPT_ONLY_SGTE yes" << std::endl - << NOMAD::close_block(); - chk = true; - } - - // SEC_POLL_DIR_TYPES: - // ------------------- - if ( developer && ( display_all || NOMAD::string_find ( "SEC_POLL_DIR_TYPES DEVELOPER MADS \ - POLL DIRECTIONS PB PEB \ - PROGRESSIVE-BARRIER" , param_names ) ) ){ - _out << std::endl - << NOMAD::open_block ( "SEC_POLL_DIR_TYPES (developer)" ) << std::endl - << ". types of directions for the secondary poll" << std::endl - << ". arguments: same logic as DIRECTION_TYPE" << std::endl - << ". default: see user guide" << std::endl - << ". example: SEC_POLL_DIR_TYPES ORTHO 1" << std::endl - << NOMAD::close_block(); - chk = true; - } - - - - // last display: - if ( !chk && developer) { - - std::string pname = ( pnames.size() == 1 ) ? - ("\'" + *pnames.begin() + "\'") : - "the specified list of parameter names"; - - _out << std::endl << "no help available for " << pname << std::endl - << "Developer help example: \'nomad -d mesh\' displays developer " << std::endl - << " help on the mesh parameters." << std::endl - << std::endl; - } - - - _out.close_block(); + param_names ) ) { + + if ( !NOMAD::string_find ( "RHO" , param_names ) ) { + + _out << std::endl + << NOMAD::open_block ( "VNS_SEARCH (advanced)" ) << std::endl + << ". Variable Neighborhood Search (VNS) search" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << " or one real in [0;1] for the VNS trigger" << std::endl + << ". default: \'no\' (same as 0.0)" << std::endl + << ". the VNS trigger is the maximum desired ratio of" << std::endl + << " VNS blackbox evaluations over the total number" << std::endl + << " of blackbox evaluations" << std::endl + << ". the VNS search is never executed with a null trigger" << std::endl + << " while a value of 1 allows the search at every" << std::endl + << " iteration" << std::endl + << ". if VNS_SEARCH=\'yes\', the default value of 0.75 is" << std::endl + << " taken for the trigger" << std::endl + << ". VNS search uses the surrogate if HAS_SGTE or" << std::endl + << " SGTE_EXE is defined" << std::endl + << ". " << NOMAD::open_block ( "examples" ) + << "VNS_SEARCH yes # VNS trigger of 75%" << std::endl + << "VNS_SEARCH 0.5 # VNS trigger of 50%" << std::endl + << NOMAD::close_block() << NOMAD::close_block(); + chk = true; + } + } + + + + // last display: + if ( !chk && !developer) { + + std::string pname = ( pnames.size() == 1 ) ? + ("\'" + *pnames.begin() + "\'") : + "the specified list of parameter names"; + + _out << std::endl << "no help available for " << pname << std::endl + << "help example: \'nomad -h mesh\' displays help on the mesh parameters" + << std::endl; + } + + if (developer && NOMAD::string_find(registered_key_developer,param_names)) + { + _out << "--------------------------------------------------------------" << endl; + _out << "---------------------DEVELOPER PARAMETERS---------------------" << endl; + _out << "--------------------------------------------------------------" << endl; + } + + // EPSILON: + // -------- + if ( developer && (display_all || NOMAD::string_find ( "EPSILON DEVELOPPER \ + PRECISION REALS COMPARISONS" , + param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "EPSILON (developer)" ) << std::endl + << ". precision on reals" << std::endl + << ". argument: one positive real" << std::endl + << ". default: 1E-13" << std::endl + << ". example: EPSILON 1E-8" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // INITIAL_MESH_INDEX: + // ------------------- + if ( developer && ( display_all || NOMAD::string_find ( "INITIAL_MESH_INDEX DEVELOPER SMESH \ + \\DELTA MADS L0 L_0 \\ELL_0" , param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "INITIAL_MESH_INDEX (developer)" ) << std::endl + << ". initial mesh index for SMesh \\ell_0" << std::endl + << ". argument: one integer (can be negative)" << std::endl + << ". default: 0" << std::endl + << ". example: INITIAL_MESH_INDEX -1" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + + // L_CURVE_TARGET: + // --------------- + if ( developer && ( display_all || NOMAD::string_find ( "L_CURVE_TARGET DEVELOPER TERMINATION \ + STOPPING TERMINATES" , param_names ) ) ){ + _out << std::endl + << NOMAD::open_block ( "L_CURVE_TARGET (developer)" ) << std::endl + << ". MADS terminates if it detects that the objective will" << std::endl + << " not reach this value (based on an approximation" << std::endl + << " of the L-shaped curve obj_value v.s. bb_eval)" << std::endl + << ". argument: one real" << std::endl + << ". no default" << std::endl + << ". example: L_CURVE_TARGET 10.0" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + + // MODEL_EVAL_SORT_CAUTIOUS: + // ------------------------- + if ( developer && ( display_all || NOMAD::string_find ( "MODEL_ORDERING MODEL_EVAL_SORT_CAUTIOUS \ + MODELS INTERPOLATION REGRESSION \ + MFN FROBENIUS DEVELOPER \ + QUADRATIC TGP" , param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "MODEL_EVAL_SORT_CAUTIOUS (developer)" ) << std::endl + << ". if the model ordering strategy is cautious, meaning" << std::endl + << " that models are evaluated only within a trust radius" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'no\'" << std::endl + << ". example: MODEL_EVAL_SORT_CAUTIOUS no" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MODEL_QUAD_MAX_Y_SIZE: + // ---------------------- + if ( developer && ( display_all || NOMAD::string_find ( "MODEL_QUAD_MAX_Y_SIZE MODEL_SEARCH DEVELOPER \ + MODELS INTERPOLATION REGRESSION \ + MFN FROBENIUS QUADRATIC" , param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "MODEL_QUAD_MAX_Y_SIZE (developer)" ) << std::endl + << ". Sup. limit on the size of interp. set Y for quadr. models" << std::endl + << ". arguments: one integer greater than the number of variables" << std::endl + << ". default: 500" << std::endl + << ". example: MODEL_QUAD_MAX_Y_SIZE 10" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MODEL_QUAD_MIN_Y_SIZE: + // ---------------------- + if ( developer && (display_all || NOMAD::string_find ( "MODEL_QUAD_MIN_Y_SIZE MODEL_SEARCH DEVELOPER \ + MODELS INTERPOLATION REGRESSION \ + MFN FROBENIUS QUADRATIC" , param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "MODEL_QUAD_MIN_Y_SIZE (developer)" ) << std::endl + << ". Inf. limit on the size of interp. set Y for quadr. models" << std::endl + << ". arguments: one integer > 1 or the string \'N+1\'" << std::endl + << ". default: N+1" << std::endl + << ". examples: MODEL_QUAD_MIN_Y_SIZE N+1" << std::endl + << " MODEL_QUAD_MIN_Y_SIZE -1 # same as N+1" << std::endl + << " MODEL_QUAD_MIN_Y_SIZE 2" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MODEL_QUAD_RADIUS_FACTOR: + // ------------------------- + if ( developer && ( display_all || NOMAD::string_find ( "MODEL_QUAD_RADIUS_FACTOR MODEL_SEARCH \ + DEVELOPER MODELS INTERPOLATION REGRESSION \ + MFN FROBENIUS QUADRATIC" , param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "MODEL_QUAD_RADIUS_FACTOR (developer)" ) << std::endl + << ". quadratic model search radius factor (see user guide)" << std::endl + << ". arguments: one strictly positive real" << std::endl + << ". default: 2.0" << std::endl + << ". example: MODEL_QUAD_RADIUS_FACTOR 1.0" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MODEL_SEARCH_MAX_TRIAL_PTS: + // --------------------------- + if ( developer && ( display_all || NOMAD::string_find ( "MODEL_SEARCH_MAX_TRIAL_PTS \ + DEVELOPER MODELS INTERPOLATION REGRESSION \ + MFN FROBENIUS QUADRATIC \ + TGP" , param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "MODEL_SEARCH_MAX_TRIAL_PTS (developer)" ) << std::endl + << ". limit on the number of trial points for one model search" << std::endl + << ". arguments: one integer greater than or equal to 1" << std::endl + << ". the quadratic model search will not generate more than 4 points" << std::endl + << ". default: 10" << std::endl + << ". example: MODEL_SEARCH_MAX_TRIAL_PTS 1" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MODEL_SEARCH_PROJ_TO_MESH: + // -------------------------- + if ( developer && ( display_all || NOMAD::string_find ( "MODEL_SEARCH_PROJ_TO_MESH DEVELOPER \ + MODELS INTERPOLATION REGRESSION \ + MFN FROBENIUS QUADRATIC PROJECTION \ + TGP" , param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "MODEL_SEARCH_PROJ_TO_MESH (developer)" ) << std::endl + << ". if model search trial points are projected to the mesh" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". example: MODEL_SEARCH_PROJ_TO_MESH no" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MODEL_QUAD_USE_WP: + // ------------------ + if ( developer && ( display_all || NOMAD::string_find ( "MODEL_QUAD_USE_WP DEVELOPER \ + WELL-POISEDNESS \ + MODELS INTERPOLATION REGRESSION \ + MFN FROBENIUS QUADRATIC" , param_names ) ) ){ + _out << std::endl + << NOMAD::open_block ( "MODEL_QUAD_USE_WP (developer)" ) << std::endl + << ". enable the strategy to maintain WP with quadr. models" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'no\'" << std::endl + << ". example: MODEL_QUAD_USE_WP yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // MODEL_NP1_QUAD_EPSILON : + // --------------- + if ( developer && (display_all || NOMAD::string_find ( "MODEL MODELS NP1 QUAD EPSILON \ + ORTHO N+1 QUAD DEVELOPER" , + param_names ) ) ){ + _out << std::endl + << NOMAD::open_block ( "MODEL_NP1_QUAD_EPSILON (developer)" ) << std::endl + << ". with the direction type ORTHO N+1 QUAD selected the" << std::endl + << " (n+1)-th direction is determined within a truncated " << std::endl + << " unit hypercube ]epsilon;1[^n defined by the first " << std::endl + << " n-th directions. The truncation is on lower limit " << std::endl + << " and is defined with a single argument (epsilon)." << std::endl + << ". argument: real in ]0;1[" << std::endl + << ". default: 0.01" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // MODEL_TGP_MODE: + // --------------- + if ( developer && (display_all || NOMAD::string_find ( "MODEL_TGP_MODE MODEL_SEARCH DEVELOPER \ + MODELS INTERPOLATION REGRESSION \ + TGP" , param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "MODEL_TGP_MODE (developer)" ) << std::endl + << ". TGP mode (fast or precise)" << std::endl + << ". arguments: one string in {\'FAST\', \'PRECISE\'}" << std::endl + << ". default: \'FAST\'" << std::endl + << ". example: MODEL_TGP_MODE PRECISE" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MODEL_TGP_REUSE_MODEL: + // ---------------------- + if (developer && ( display_all || NOMAD::string_find ( "MODEL_TGP_REUSE_MODEL DEVELOPER \ + MODELS INTERPOLATION REGRESSION \ + TGP" , param_names ) ) ){ + _out << std::endl + << NOMAD::open_block ( "MODEL_TGP_REUSE_MODEL (developer)" ) << std::endl + << ". enable to use the last model from the TGP search for" << std::endl + << " the TGP model eval sort strategy." << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'yes\'" << std::endl + << ". example: MODEL_TGP_REUSE_MODEL no" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // MULTI_FORMULATION: + // ----------------- + if ( developer && (display_all || NOMAD::string_find ( "MULTI_FORMULATION DEVELOPER PARETO \ + BI-OBJECTIVES MULTI-OBJECTIVES\ + BIOBJECTIVES MULTIOBJECTIVES \ + BI-MADS BIMADS" , + param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "MULTI_FORMULATION (developer)" ) << std::endl + << ". multi-objective optimization: single-objective reformulation" + << std::endl + << ". argument: one string in {\'NORMALIZED\', \'PRODUCT\', \'DIST_L1\'," + << std::endl + << " \'DIST_L2\', \'DIST_LINF\'}" << std::endl + << " (\'NORMALIZED\' and \'DIST_LINF\' are equivalent)" << std::endl + << ". default: \'PRODUCT\' or \'DIST_L2\' if VNS_SEARCH is set to \'yes\'" + << std::endl + << ". example: MULTI_FORMULATION DIST_L1" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // MULTI_USE_DELTA_CRIT: + // --------------------- + if ( developer && ( display_all || NOMAD::string_find ( "MULTI_USE_DELTA_CRITERION DEVELOPER PARETO \ + BIOBJECTIVES MULTIOBJECTIVES \ + BI-MADS BIMADS \ + BI-OBJECTIVES MULTI-OBJECTIVES" , + param_names ) ) ){ + _out << std::endl + << NOMAD::open_block ( "MULTI_USE_DELTA_CRIT (developer)" ) << std::endl + << ". multi-objective optimization: use the delta criterion" << std::endl + << " (can result in a better distributed Pareto front)" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'no\'" << std::endl + << ". example: MULTI_USE_DELTA_CRIT yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // OPPORTUNISTIC_LUCKY_EVAL: + // ------------------------- + if ( developer && ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_LUCKY_EVAL DEVELOPER \ + BLACK-BOXES BLACKBOXES EVALUATIONS \ + SUCCESSES" , param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "OPPORTUNISTIC_LUCKY_EVAL (developer)" ) << std::endl + << ". developer parameter for the opportunistic" << std::endl + << " strategy" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". default: \'no\'" << std::endl + << ". example: OPPORTUNISTIC_LUCKY_EVAL yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // OPPORTUNISTIC_MIN_F_IMPRVMT: + // ---------------------------- + if ( developer && ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_MIN_F_IMPRVMT DEVELOPER \ + OBJECTIVE \ + BLACK-BOXES BLACKBOXES EVALUATIONS \ + SUCCESSES IMPROVEMENT" , param_names ) ) ) { + _out << std::endl + << NOMAD::open_block ( "OPPORTUNISTIC_MIN_F_IMPRVMT (developer)" ) << std::endl + << ". advanced parameter for the opportunistic" << std::endl + << " strategy (see user guide)" << std::endl + << ". argument: one real" << std::endl + << ". no default" << std::endl + << ". example: OPPORTUNISTIC_MIN_F_IMPRVMT 0.1" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // OPPORTUNISTIC_MIN_NB_SUCCESS: + // ----------------------------- + if ( developer && ( display_all || NOMAD::string_find ( "OPPORTUNISTIC_MIN_NB_SUCCESSES DEVELOPER \ + BLACK-BOXES BLACKBOXES \ + EVALUATIONS" , param_names ) ) ){ + _out << std::endl + << NOMAD::open_block ( "OPPORTUNISTIC_MIN_NB_SUCCESS (developer)" ) << std::endl + << ". advanced parameter for the opportunistic" << std::endl + << " strategy (see user guide)" << std::endl + << ". argument: one nonnegative integer" << std::endl + << ". no default" << std::endl + << ". example: OPPORTUNISTIC_MIN_NB_SUCCESS 2" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // OPT_ONLY_SGTE: + // -------------- + if (developer && ( display_all || NOMAD::string_find ( "OPT_ONLY_SGTES DEVELOPER SURROGATES \ + BLACK-BOXES BLACKBOXES \ + SGTES" , param_names ) ) ){ + _out << std::endl + << NOMAD::open_block ( "OPT_ONLY_SGTE (developer)" ) << std::endl + << ". NOMAD will only minimize the surrogate" << std::endl + << ". argument: one boolean (\'yes\' or \'no\')" << std::endl + << ". SGTE_EXE or HAS_SGTE must be defined" << std::endl + << ". default: \'no\'" << std::endl + << ". example: OPT_ONLY_SGTE yes" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // SEC_POLL_DIR_TYPES: + // ------------------- + if ( developer && ( display_all || NOMAD::string_find ( "SEC_POLL_DIR_TYPES DEVELOPER MADS \ + POLL DIRECTIONS PB PEB \ + PROGRESSIVE-BARRIER" , param_names ) ) ){ + _out << std::endl + << NOMAD::open_block ( "SEC_POLL_DIR_TYPES (developer)" ) << std::endl + << ". types of directions for the secondary poll" << std::endl + << ". arguments: same logic as DIRECTION_TYPE" << std::endl + << ". default: see user guide" << std::endl + << ". example: SEC_POLL_DIR_TYPES ORTHO 1" << std::endl + << NOMAD::close_block(); + chk = true; + } + + // USE_SMESH: + // ------------------- + if ( developer && ( display_all || NOMAD::string_find ( "USE_SMESH SMESH MESH \ + ANISO" , param_names ) ) ){ + _out << std::endl + << NOMAD::open_block ( "USE_SMESH (developer)" ) << std::endl + << ". forces the use of the standard mesh (older version of mesh)" << std::endl + << ". default: no" << std::endl + << ". example: USE_SMESH 1" << std::endl + << NOMAD::close_block(); + chk = true; + } + + + // last display: + if ( !chk && developer) { + + std::string pname = ( pnames.size() == 1 ) ? + ("\'" + *pnames.begin() + "\'") : + "the specified list of parameter names"; + + _out << std::endl << "no help available for " << pname << std::endl + << "Developer help example: \'nomad -d mesh\' displays developer " << std::endl + << " help on the mesh parameters." << std::endl + << std::endl; + } + + + _out.close_block(); } diff --git a/src/Parameters.hpp b/src/Parameters.hpp index 67f976e..5a8d6c8 100644 --- a/src/Parameters.hpp +++ b/src/Parameters.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Parameters.hpp - \brief NOMAD Parameters (headers) - \author Sebastien Le Digabel - \date 2010-04-21 - \see Parameters.cpp -*/ + \file Parameters.hpp + \brief NOMAD Parameters (headers) + \author Sebastien Le Digabel + \date 2010-04-21 + \see Parameters.cpp + */ #ifndef __PARAMETERS__ #define __PARAMETERS__ @@ -51,2471 +51,2551 @@ #include "Signature.hpp" namespace NOMAD { - - /// Structure to represent the models parameters. - struct model_params_type { - - NOMAD::model_type search1; ///< First model search (MS) type. - NOMAD::model_type search2; ///< Second model search (MS) type. - - NOMAD::model_type eval_sort; ///< Use models to sort trial pts (MES). - - bool search_optimistic; ///< If the MS is optimistic or not. - bool search_proj_to_mesh; ///< Model solution projected or not to mesh. - int search_max_trial_pts; ///< Limit on the number of MS trial pts. - bool eval_sort_cautious; ///< Cautious strategy for MES. - - NOMAD::Double quad_radius_factor; ///< Quadratic model radius factor \c r. - bool quad_use_WP; ///< Use or not a well-poisedness strategy. - int quad_min_Y_size; ///< Limit inf on the size of \c Y. - int quad_max_Y_size; ///< Limit sup on the size of \c Y. - NOMAD::Double model_np1_quad_epsilon;///< Ortho n+1 quadratic model epsilon (scaling used for (n+1)th dynamic direction with Ortho n+1) - - NOMAD::TGP_mode_type tgp_mode; ///< TGP mode (fast or precise). - bool tgp_reuse_model; ///< Use the model from MS for the MES. - }; - - /// Class for the NOMAD parameters. - class Parameters : private NOMAD::Uncopyable { - - private: - - bool _to_be_checked; ///< Access control to the parameters. - static bool _warning_has_been_displayed; - NOMAD::Display _out; ///< Display. - - /*----------------------------------------------------------------------*/ - - /// Initializations. - void init ( void ); - - /// Interpretation of the entries for the starting point. - /** - \param entries Parameter entries -- \b IN. - */ - void interpret_x0 ( const NOMAD::Parameter_Entries & entries ); - - /// Interpretation of the entries for mesh and poll sizes. - /** - \param entries Parameter entries -- \b IN. - \param param_name Parameter name -- \b IN. - */ - void interpret_mesh_sizes ( const NOMAD::Parameter_Entries & entries , - const std::string & param_name ); - - /// Interpretation of the entries for bounds and fixed variables. - /** - \c BFVS stands for "Bounds and Fixed VariableS". - \param entries Parameter entries -- \b IN. - \param param_name Parameter name -- \b IN. - */ - void interpret_BFVS ( const NOMAD::Parameter_Entries & entries , - const std::string & param_name ); - /// Interpretation of the entries for parameter \c BB_INPUT_TYPE. - /** - \param entries Parameter entries -- \b IN. - */ - void interpret_bb_input_type ( const NOMAD::Parameter_Entries & entries ); - - /// Interpretation of the entries for parameter \c PERIODIC_VARIABLE. - /** - \param entries Parameter entries -- \b IN. - */ - void interpret_periodic_var ( const NOMAD::Parameter_Entries & entries ); - - /// Interpretation of the entries for parameter \c VARIABLE_GROUP. - /** - \param entries Parameter entries -- \b IN. - */ - void interpret_var_groups ( const NOMAD::Parameter_Entries & entries ); - - // Interpretation of the entries for parameter \c F_TARGET. - /** - \param entries Parameter entries -- \b IN. - */ - void interpret_f_target ( const NOMAD::Parameter_Entries & entries ); - - /// Delete the list of starting points. - void delete_x0s ( void ); - - /// Check a directory name. - /** - \param dir Directory name -- \b IN. - \return A boolean equal to \c true if the directory is valid. - */ - static bool check_directory ( std::string & dir ); - - /// Add a seed to a file name. - /** - - Transforms \c file_name.ext into \c file_name.seed.ext. - \param n_seed Length of the seed \c s_seed -- \b IN. - \param s_seed A string representating the seed -- \b IN. - \param file_name File name -- \b IN/OUT. - */ - static void add_seed_to_file_name ( int n_seed , - const std::string & s_seed , - std::string & file_name ); - - - - /// Check if a specified direction type is set. - /** - \param dt The specified direction type -- \b IN. - \return true if the specified direction type is used. - */ - bool has_direction_type(NOMAD::direction_type dt) const; - - - /*----------------------------------------------------------------------*/ - - public: - - /// Exception class for an invalid parameter. - class Invalid_Parameter : public NOMAD::Exception { - public: - /// Constructor. - Invalid_Parameter ( const std::string & file , - int line , - const std::string & msg ) - : NOMAD::Exception ( file , line , msg ) {} + /// Structure to represent the models parameters. + struct model_params_type { + + NOMAD::model_type search1; ///< First model search (MS) type. + NOMAD::model_type search2; ///< Second model search (MS) type. + + NOMAD::model_type eval_sort; ///< Use models to sort trial pts (MES). + + bool search_optimistic; ///< If the MS is optimistic or not. + bool search_proj_to_mesh; ///< Model solution projected or not to mesh. + int search_max_trial_pts; ///< Limit on the number of MS trial pts. + bool eval_sort_cautious; ///< Cautious strategy for MES. + + NOMAD::Double quad_radius_factor; ///< Quadratic model radius factor \c r. + bool quad_use_WP; ///< Use or not a well-poisedness strategy. + int quad_min_Y_size; ///< Limit inf on the size of \c Y. + int quad_max_Y_size; ///< Limit sup on the size of \c Y. + NOMAD::Double model_np1_quad_epsilon;///< Ortho n+1 quadratic model epsilon (scaling used for (n+1)th dynamic direction with Ortho n+1) + + NOMAD::TGP_mode_type tgp_mode; ///< TGP mode (fast or precise). + bool tgp_reuse_model; ///< Use the model from MS for the MES. }; - /// Exception class for a bad access. - class Bad_Access : public NOMAD::Exception { + /// Class for the NOMAD parameters. + class Parameters : private NOMAD::Uncopyable { + + private: + + bool _to_be_checked; ///< Access control to the parameters. + static bool _warning_has_been_displayed; + NOMAD::Display _out; ///< Display. + + /*----------------------------------------------------------------------*/ + + /// Initializations. + void init ( void ); + + /// Interpretation of the entries for the starting point. + /** + \param entries Parameter entries -- \b IN. + */ + void interpret_x0 ( const NOMAD::Parameter_Entries & entries ); + + /// Interpretation of the entries for mesh and poll sizes. + /** + \param entries Parameter entries -- \b IN. + \param param_name Parameter name -- \b IN. + */ + void interpret_mesh_sizes ( const NOMAD::Parameter_Entries & entries , + const std::string & param_name ); + + /// Interpretation of the entries for bounds and fixed variables. + /** + \c BFVS stands for "Bounds and Fixed VariableS". + \param entries Parameter entries -- \b IN. + \param param_name Parameter name -- \b IN. + */ + void interpret_BFVS ( const NOMAD::Parameter_Entries & entries , + const std::string & param_name ); + + /// Interpretation of the entries for parameter \c BB_INPUT_TYPE. + /** + \param entries Parameter entries -- \b IN. + */ + void interpret_bb_input_type ( const NOMAD::Parameter_Entries & entries ); + + /// Interpretation of the entries for parameter \c PERIODIC_VARIABLE. + /** + \param entries Parameter entries -- \b IN. + */ + void interpret_periodic_var ( const NOMAD::Parameter_Entries & entries ); + + /// Interpretation of the entries for parameter \c VARIABLE_GROUP. + /** + \param entries Parameter entries -- \b IN. + */ + void interpret_var_groups ( const NOMAD::Parameter_Entries & entries ); + + // Interpretation of the entries for parameter \c F_TARGET. + /** + \param entries Parameter entries -- \b IN. + */ + void interpret_f_target ( const NOMAD::Parameter_Entries & entries ); + + /// Delete the list of starting points. + void delete_x0s ( void ); + + /// Check a directory name. + /** + \param dir Directory name -- \b IN. + \return A boolean equal to \c true if the directory is valid. + */ + static bool check_directory ( std::string & dir ); + + /// Add a seed to a file name. + /** + - Transforms \c file_name.ext into \c file_name.seed.ext. + \param n_seed Length of the seed \c s_seed -- \b IN. + \param s_seed A string representating the seed -- \b IN. + \param file_name File name -- \b IN/OUT. + */ + static void add_seed_to_file_name ( int n_seed , + const std::string & s_seed , + std::string & file_name ); + + + + /// Check if a specified direction type is set. + /** + \param dt The specified direction type -- \b IN. + \return true if the specified direction type is used. + */ + bool has_direction_type(NOMAD::direction_type dt) const; + + + /*----------------------------------------------------------------------*/ + public: - /// Constructor. - Bad_Access ( const std::string & file , - int line , - const std::string & msg ) - : NOMAD::Exception ( file , line , msg ) {} + + /// Exception class for an invalid parameter. + class Invalid_Parameter : public NOMAD::Exception { + public: + /// Constructor. + Invalid_Parameter ( const std::string & file , + int line , + const std::string & msg ) + : NOMAD::Exception ( file , line , msg ) {} + }; + + /// Exception class for a bad access. + class Bad_Access : public NOMAD::Exception { + public: + /// Constructor. + Bad_Access ( const std::string & file , + int line , + const std::string & msg ) + : NOMAD::Exception ( file , line , msg ) {} + }; + + /*----------------------------------------------------------------------*/ + + /// Constructor #1. + /** + \param out Display -- \b IN. + */ + explicit Parameters ( const NOMAD::Display & out ) + : _out ( out ) , + _std_signature ( NULL ) , + _extern_signature ( NULL ) { init(); } + + /// Constructor #2. + /** + From an extern signature. + \param extern_signature A pointer to the extern signature -- \b IN. + \param out Display -- \b IN. + */ + explicit Parameters ( NOMAD::Signature * extern_signature , + const NOMAD::Display & out ) + : _out ( out ) , + _std_signature ( NULL ) , + _extern_signature ( extern_signature ) { init(); } + + /// Destructor. + virtual ~Parameters ( void ); + + /// Display parameter help. + /** + - Help option obtained with command \c nomad \c -h. + - A list of parameters is given as the program arguments. + \param argc Number of command line arguments -- \b IN. + \param argv The command line arguments -- \b IN. + \param developer Bool to request developer help (defaut=false) -- \b IN. + */ + void help ( int argc , char ** argv , bool developer=false) const; + + /// Display parameter help. + /** + For a specific parameter. + \param param_name Name of the parameter -- \b IN. + \param developer Bool to request developer help (defaut=false) -- \b IN. + */ + void help ( const std::string & param_name, bool developer=false ) const; + + /// Display parameter help. + /** + For a list of parameters. + \param param_names_list List of parameter names -- \b IN. + \param developer Bool to request developer help (defaut=false) -- \b IN. + */ + void help ( const std::list<std::string> & param_names_list , bool developer=false) const; + + /// Reset. + void reset ( void ) { init(); } + + /// Read parameters from a file. 1/2 + /** + \param param_file Name of the parameters file -- \b IN. + */ + void read ( const std::string & param_file ); + + /// Read parameters from a Parameter_Entries 2/2 + /** + \param entries -- \b IN. + */ + void read ( const NOMAD::Parameter_Entries & entries ); + + + /// Check the parameters. + /** + \param remove_history_file A boolean equal to \c true if the history file + has to be deleted + -- \b IN -- \b optional (default = \c true). + \param remove_solution_file A boolean equal to \c true if the solution file + has to be deleted + -- \b IN -- \b optional (default = \c true). + \param remove_stats_file A boolean equal to \c true if the stats file + has to be deleted + -- \b IN -- \b optional (default = \c true). + */ + void check ( bool remove_history_file = true , + bool remove_solution_file = true , + bool remove_stats_file = true ); + + /// Force the check flag to be satisfied. + /** + This advanced function should be used with care. + */ + void force_check_flag ( void ) { _to_be_checked = false; } + + /// Display. + /** + \param out The NOMAD::Display object -- \b IN. + */ + void display ( const NOMAD::Display & out ) const; + + /// Display. + /** + Uses \c this->_out as NOMAD::Display object. + */ + void display ( void ) const { display ( _out ); } + + /*--------------------------------------------------------------*/ + /* Attributes and methods listed by categories */ + /*--------------------------------------------------------------*/ + + // Algorithm and miscellaneous parameters: + // --------------------------------------- + private: + std::string _problem_dir; ///< Problem directory. + std::string _tmp_dir; ///< Temporary directory. + int _seed; ///< Seed. + int _max_eval; ///< Maximum number of evaluations. + int _max_bb_eval; ///< Maximum number of blackbox evaluations. + + std::list<std::string> _display_stats; ///< Stats keywords for \c DISPLAY_STATS. + bool _display_all_eval; ///< Parameter \c DISPLAY_ALL_EVAL + + /// Equal to \c true if \c _max_bb_eval has been entered. + bool _max_bbe_decided; + + /// Maximum number of simulated evaluations. + int _max_sim_bb_eval; + + int _max_time; ///< Maximum time. + int _max_iterations; ///< Maximum number of iterations. + int _max_cons_failed_it; ///< Maximum number of consecutive failed iterations. + float _max_cache_memory; ///< Maximum cache memory. + bool _stop_if_feasible; ///< Stop if a feasible solution is found. + NOMAD::Point _f_target; ///< Target for the objective function. + NOMAD::Double _stat_sum_target; ///< Target for the STAT_SUM stat. + NOMAD::Double _L_curve_target; ///< Target for the L_CURVE criterion. + bool _snap_to_bounds; ///< Snap or not the points to the bounds. + bool _user_calls_enabled; ///< Enable calls to user functions. + bool _asynchronous; ///< Asynchronous version for parallelism. + + public: + + /// Test to know if parameters have to be checked. + /** + \return A boolean equal to \c true if parameters have + to be checked with function NOMAD::Parameters::check(). + */ + bool to_be_checked ( void ) const { return _to_be_checked; } + + /// Access to the display degrees. + /** + - Use NOMAD::Parameters::out().get_X_dd() + to access other specific display degrees. + - \see Display.hpp. + \param d The 4 display degrees as a string -- \b OUT. + */ + void get_display_degree ( std::string & d ) const; + + /// Access to the display degree. + /** + \return General display degree. + */ + int get_display_degree ( void ) const; + + /// Access to display. + /** + \return The NOMAD::Display object. + */ + const NOMAD::Display & out ( void ) const; + + /// Access to the \c DISPLAY_STATS parameter. + /** + \return The \c DISPLAY_STATS parameter. + */ + const std::list<std::string> & get_display_stats ( void ) const; + + /// Access to the \c DISPLAY_ALL_EVAL parameter. + /** + \return The \c DISPLAY_ALL_EVAL parameter. + */ + bool get_display_all_eval ( void ) const; + + /// Access to the \c POINT_DISPLAY_LIMIT parameter. + /** + \return The \c POINT_DISPLAY_LIMIT parameter. + */ + int get_point_display_limit ( void ) const; + + /// Access to the seed. + /** + \return The seed. + */ + int get_seed ( void ) const; + + /// Access to the maximum number of evaluations. + /** + \return The maximum number of evaluations. + */ + int get_max_eval ( void ) const; + + /// Access to the \c MAX_SIM_BB_EVAL parameter. + /** + \return The \c MAX_SIM_BB_EVAL parameter. + */ + int get_max_sim_bb_eval ( void ) const; + + /// Access to the \c MAX_BB_EVAL parameter. + /** + \return The \c MAX_BB_EVAL parameter. + */ + int get_max_bb_eval ( void ) const; + + /// Access to the \c MAX_TIME parameter. + /** + \return The \c MAX_TIME parameter. + */ + int get_max_time ( void ) const; + + /// Access to the maximum number of iterations. + /** + \return The maximum number of iterations. + */ + int get_max_iterations ( void ) const; + + /// Access to the maximum number of consecutive failed iterations. + /** + \return The maximum number of consecutive failed iterations. + */ + int get_max_consecutive_failed_iterations ( void ) const; + + /// Access to the maximum cache memory. + /** + \return The maximum cache memory. + */ + float get_max_cache_memory ( void ) const; + + /// Access to the \c STOP_IF_FEASIBLE parameter. + /** + \return The \c STOP_IF_FEASIBLE parameter. + */ + bool get_stop_if_feasible ( void ) const; + + /// Access to the \c F_TARGET parameter. + /** + \return The \c F_TARGET parameter. + */ + const NOMAD::Point & get_f_target ( void ) const; + + /// Access to the \c STAT_SUM_TARGET parameter. + /** + \return The \c STAT_SUM_TARGET parameter. + */ + const NOMAD::Double & get_stat_sum_target ( void ) const; + + /// Access to the \c L_CURVE_TARGET parameter. + /** + \return The \c L_CURVE_TARGET parameter. + */ + const NOMAD::Double & get_L_curve_target ( void ) const; + + /// Access to the problem directory. + /** + \return The problem directory. + */ + const std::string & get_problem_dir ( void ) const; + + /// Access to the temporary directory. + /** + \return The temporary directory. + */ + const std::string & get_tmp_dir ( void ) const; + + /// Access to the \c SNAP_TO_BOUNDS parameter. + /** + \return The \c SNAP_TO_BOUNDS parameter. + */ + bool get_snap_to_bounds ( void ) const; + + /// Access to the \c USER_CALLS_ENABLED parameter. + /** + \return The \c USER_CALLS_ENABLED parameter. + */ + bool get_user_calls_enabled ( void ) const; + + /// Access to the \c ASYNCHRONOUS parameter. + /** + \return The \c ASYNCHRONOUS parameter. + */ + bool get_asynchronous ( void ) const; + + /// Set the \c POINT_DISPLAY_LIMIT parameter. + /** + \param dl The \c POINT_DISPLAY_LIMIT parameter -- \b IN. + */ + void set_POINT_DISPLAY_LIMIT ( int dl ); + + /// Set the \c DISPLAY_STATS parameter. + /** + - From a list of strings. + \param ds The \c DISPLAY_STATS parameter -- \b IN. + */ + void set_DISPLAY_STATS ( const std::list<std::string> & ds ); + + /// Set the \c DISPLAY_STATS parameter. + /** + - From a string. + \param ds The \c DISPLAY_STATS parameter -- \b IN. + */ + void set_DISPLAY_STATS ( const std::string & ds ); + + /// Set the \c DISPLAY_ALL_EVAL parameter. + /** + \param dae The \c DISPLAY_ALL_EVAL parameter -- \b IN. + */ + void set_DISPLAY_ALL_EVAL ( bool dae ); + + /// Set the display degree. + /** + - Accepts also NOMAD::dd_type arguments. + \param dd Display degree -- \b IN. + \return \c true if the operation succeeded. + */ + bool set_DISPLAY_DEGREE ( int dd ); + + /// Set the display degrees. + /** + - From a string with the 4 degrees. + \param dd Display degree -- \b IN. + \return \c true if the operation succeeded. + */ + bool set_DISPLAY_DEGREE ( const std::string & dd ); + + /// Set the display degrees. + /* + \param gen_dd General display degree -- \b IN. + \param search_dd Search display degree -- \b IN. + \param poll_dd Poll display degree -- \b IN. + \param iter_dd Iterative display degree -- \b IN. + */ + void set_DISPLAY_DEGREE ( int gen_dd , + int search_dd , + int poll_dd , + int iter_dd ); + + /// Set the \c OPEN_BRACE parameter. + /** + \param s The \c OPEN_BRACE parameter -- \b IN. + */ + void set_OPEN_BRACE ( const std::string & s ); + + /// Set the \c CLOSED_BRACE parameter. + /** + \param s The \c CLOSED_BRACE parameter -- \b IN. + */ + void set_CLOSED_BRACE ( const std::string & s ); + + /// Set the seed. + /** + \param seed The seed -- \b IN. + */ + void set_SEED ( int seed ); + + /// Set the \c MAX_EVAL parameter. + /** + \param me The \c MAX_EVAL parameter -- \b IN. + */ + void set_MAX_EVAL ( int me ); + + /// Set the \c MAX_SIM_BB_EVAL parameter. + /** + \param msbe The \c MAX_SIM_BB_EVAL parameter -- \b IN. + */ + void set_MAX_SIM_BB_EVAL ( int msbe ); + + /// Set the \c MAX_BB_EVAL parameter. + /** + \param bbe The \c MAX_BB_EVAL parameter -- \b IN. + */ + void set_MAX_BB_EVAL ( int bbe ); + + /// Set the \c MAX_TIME parameter. + /** + \param mt The \c MAX_TIME parameter -- \b IN. + */ + void set_MAX_TIME ( int mt ); + + /// Set the \c MAX_ITERATIONS parameter. + /** + \param mi The \c MAX_ITERATIONS parameter -- \b IN. + */ + void set_MAX_ITERATIONS ( int mi ); + + /// Set the \c MAX_CONSECUTIVE_FAILED_ITERATIONS parameter. + /** + \param mcsi The \c MAX_CONSECUTIVE_FAILED_ITERATIONS parameter -- \b IN. + */ + void set_MAX_CONSECUTIVE_FAILED_ITERATIONS ( int mcsi ); + + /// Set the \c MAX_CACHE_MEMORY parameter. + /** + \param mcm The \c MAX_CACHE_MEMORY parameter -- \b IN. + */ + void set_MAX_CACHE_MEMORY ( float mcm ); + + /// Set the \c STOP_IF_FEASIBLE parameter. + /** + \param sif The \c STOP_IF_FEASIBLE parameter -- \b IN. + */ + void set_STOP_IF_FEASIBLE ( bool sif ); + + /// Set the \c STAT_SUM_TARGET parameter. + /** + \param target The \c STAT_SUM_TARGET parameter -- \b IN. + */ + void set_STAT_SUM_TARGET ( const NOMAD::Double & target ); + + /// Set the \c L_CURVE_TARGET parameter. + /** + \param target The \c L_CURVE_TARGET parameter -- \b IN. + */ + void set_L_CURVE_TARGET ( const NOMAD::Double & target ); + + /// Set the \c PROBLEM_DIR parameter. + /** + \param dir The \c PROBLEM_DIR parameter -- \b IN. + */ + void set_PROBLEM_DIR ( const std::string & dir ); + + /// Set the \c TMP_DIR parameter. + /** + \param dir The \c TMP_DIR parameter -- \b IN. + */ + void set_TMP_DIR ( const std::string & dir ); + + /// Set the \c SNAP_TO_BOUNDS parameter. + /** + \param stb The \c SNAP_TO_BOUNDS parameter -- \b IN. + */ + void set_SNAP_TO_BOUNDS ( bool stb ); + + /// Set the \c USER_CALLS_ENABLED parameter. + /** + \param uce The \c USER_CALLS_ENABLED parameter -- \b IN. + */ + void set_USER_CALLS_ENABLED ( bool uce ); + + /// Set the \c ASYNCHRONOUS parameter. + /** + \param as The \c ASYNCHRONOUS parameter -- \b IN. + */ + void set_ASYNCHRONOUS ( bool as ); + + /// Set the \c F_TARGET parameter. + /** + - Multi-objective version. + \param target The \c F_TARGET parameter -- \b IN. + */ + void set_F_TARGET ( const NOMAD::Point & target ); + + /// Set the F_TARGET \c parameter. + /** + - Single-objective version. + \param target The \c F_TARGET parameter -- \b IN. + */ + void set_F_TARGET ( const NOMAD::Double & target ); + + /// Reset the \c F_TARGET parameter. + void reset_f_target ( void ) { _f_target.clear(); } + + /// Set the \c EPSILON parameter. + /** + \param eps The \c EPSILON parameter -- \b IN. + */ + void set_EPSILON ( const NOMAD::Double & eps ) + { + NOMAD::Double::set_epsilon ( eps.value() ); + } + + /// Set the \c UNDEF_STR parameter. + /** + \param undef_str The \c UNDEF_STR parameter -- \b IN. + */ + void set_UNDEF_STR ( const std::string & undef_str ) + { + NOMAD::Double::set_undef_str ( undef_str ); + } + + /// Set the \c INF_STR parameter. + /** + \param inf_str The \c INF_STR parameter -- \b IN. + */ + void set_INF_STR ( const std::string & inf_str ) + { + NOMAD::Double::set_inf_str ( inf_str ); + } + + /// Access to the \c EPSILON parameter. + /** + \return The \c EPSILON parameter. + */ + const NOMAD::Double get_epsilon ( void ) const + { + return NOMAD::Double::get_epsilon(); + } + + /// Access to the \c UNDEF_STR parameter. + /** + \return The \c UNDEF_STR parameter. + */ + const std::string get_undef_str ( void ) const + { + return NOMAD::Double::get_undef_str(); + } + + /// Access to the \c INF_STR parameter. + /** + \return The \c INF_STR parameter. + */ + const std::string get_inf_str ( void ) const + { + return NOMAD::Double::get_inf_str(); + } + + // Output files: + // ------------- + private: + + /// List of stats for parameter \c STATS_FILE. + std::list<std::string> _stats_file; + + /// Name of the stats file. + std::string _stats_file_name; + + /// Parameter \c ADD_SEED_TO_FILE_NAME. + bool _add_seed_to_file_names; + + std::string _solution_file; ///< Parameter \c SOLUTION_FILE. + std::string _history_file; ///< Parameter \c HISTORY_FILE. + std::string _cache_file; ///< Parameter \c CACHE_FILE. + int _cache_save_period; ///< Parameter \c CACHE_SAVE_PERIOD. + + public: + + /// Access to the list of stats for the \c STATS_FILE parameter. + /** + \return The list of stats. + */ + const std::list<std::string> & get_stats_file ( void ) const; + + /// Access to the name of the stats file. + /** + \return The name of the stats file. + */ + const std::string & get_stats_file_name ( void ) const; + + /// Access to the \c SOLUTION_FILE parameter. + /** + \return The \c SOLUTION_FILE parameter. + */ + const std::string & get_solution_file ( void ) const; + + /// Access to the \c HISTORY_FILE parameter. + /** + \return The \c HISTORY_FILE parameter. + */ + const std::string & get_history_file ( void ) const; + + /// Access to the \c CACHE_FILE parameter. + /** + \return The \c CACHE_FILE parameter. + */ + const std::string & get_cache_file ( void ) const; + + /// Access to the \c CACHE_SAVE_PERIOD parameter. + /** + \return The \c CACHE_SAVE_PERIOD parameter. + */ + int get_cache_save_period ( void ) const; + + /// Access to the \c ADD_SEED_TO_FILE_NAME parameter. + /** + \return The \c ADD_SEED_TO_FILE_NAME parameter. + */ + bool get_add_seed_to_file_names ( void ) const; + + /// Reset the \c STATS_FILE parameter. + void reset_stats_file ( void ); + + /// Set the \c STATS_FILE parameter. + /** + \param file_name Name of the stats file -- \b IN. + \param stats List of stats -- \b IN. + */ + void set_STATS_FILE ( const std::string & file_name , + const std::list<std::string> & stats ); + + /// Set the \c STATS_FILE parameter. + /** + \param file_name Name of the stats file -- \b IN. + \param stats The stats -- \b IN. + */ + void set_STATS_FILE ( const std::string & file_name , + const std::string & stats ); + + /// Set the \c ADD_SEED_TO_FILE_NAME parameter. + /** + \param astfn The \c ADD_SEED_TO_FILE_NAME parameter -- \b IN. + */ + void set_ADD_SEED_TO_FILE_NAMES ( bool astfn ); + + /// Set the \c SOLUTION_FILE parameter. + /** + \param sf The \c SOLUTION_FILE parameter -- \b IN. + */ + void set_SOLUTION_FILE ( const std::string & sf ); + + /// Set the \c HISTORY_FILE parameter. + /** + \param hf The \c HISTORY_FILE parameter -- \b IN. + */ + void set_HISTORY_FILE ( const std::string & hf ); + + /// Set the \c CACHE_FILE parameter. + /** + \param cf The \c CACHE_FILE parameter -- \b IN. + */ + void set_CACHE_FILE ( const std::string & cf ); + + /// Set the \c CACHE_SAVE_PERIOD parameter. + /** + \param csp The \c CACHE_SAVE_PERIOD parameter -- \b IN. + */ + void set_CACHE_SAVE_PERIOD ( int csp ); + + // Searches: + // --------- + private: + + /// Speculative search (MADS search). + bool _speculative_search; + + bool _disable_models; ///< Models disablement + + NOMAD::model_params_type _model_params; ///< Models parameters. + + // VNS search parameters: + bool _VNS_search; ///< Flag for the VNS search. + NOMAD::Double _VNS_trigger; ///< VNS trigger. + + // Latin-Hypercube (LH) search: + int _LH_search_p0; ///< Number of initial LH search points. + int _LH_search_pi; ///< LH search points at each iteration. + bool _opportunistic_LH; ///< Parameter \c OPPORTUNISTIC_LH. + bool _opp_LH_is_defined; ///< A boolean equal to \c true if a LH has been defined. + + bool _cache_search; ///< Cache search. + bool _opportunistic_cache_search; ///< Parameter \c OPPORTUNISTIC_CACHE_SEARCH. + + /// A boolean equal to \c true if \c OPPORTUNISTIC_CACHE_SEARCH has been defined. + bool _opp_CS_is_defined; + + public: + + /// Access to the \c SPECULATIVE_SEARCH parameter. + /** + \return The \c SPECULATIVE_SEARCH parameter. + */ + bool get_speculative_search ( void ) const; + + /// Check if a model search is specified. + /** + \return A boolean equal to \c true if a model search is defined. + */ + bool has_model_search ( void ) const; + + /// Access to the \c MODEL_SEARCH parameter. + /** + \param i Index of the model search (1 or 2) -- \b IN. + \return The \c MODEL_SEARCH parameter. + */ + NOMAD::model_type get_model_search ( int i ) const; + + /// Access to the \c MODEL_SEARCH_OPTIMISTIC parameter. + /** + \return The \c MODEL_SEARCH_OPTIMISTIC parameter. + */ + bool get_model_search_optimistic ( void ) const; + + /// Access to the \c MODEL_SEARCH_PROJ_TO_MESH parameter. + /** + \return The \c MODEL_SEARCH_PROJ_TO_MESH parameter. + */ + bool get_model_search_proj_to_mesh ( void ) const; + + /// Access to the \c MODEL_QUAD_RADIUS_FACTOR parameter. + /** + \return The \c MODEL_QUAD_RADIUS_FACTOR parameter. + */ + const NOMAD::Double & get_model_quad_radius_factor ( void ) const; + + /// Access to the \c MODEL_NP1_QUAD_EPSILON parameter. + /** + \return The \c MODEL_NP1_QUAD_EPSILON parameter. + */ + const NOMAD::Double & get_model_np1_quad_epsilon ( void ) const; + + + /// Access to the \c MODEL_QUAD_USE_WP parameter. + /** + \return The \c MODEL_QUAD_USE_WP parameter. + */ + bool get_model_quad_use_WP ( void ) const; + + /// Access to the \c MODEL_QUAD_MAX_Y_SIZE parameter. + /** + \return The \c MODEL_QUAD_MAX_Y_SIZE parameter. + */ + int get_model_quad_max_Y_size ( void ) const; + + /// Access to the \c MODEL_QUAD_MIN_Y_SIZE parameter. + /** + \return The \c MODEL_QUAD_MIN_Y_SIZE parameter. + */ + int get_model_quad_min_Y_size ( void ) const; + + /// Access to the \c MODEL_TGP_MODE parameter. + /** + \return The \c MODEL_TGP_MODE parameter. + */ + NOMAD::TGP_mode_type get_model_tgp_mode ( void ) const; + + /// Access to the \c MODEL_TGP_REUSE_MODEL parameter. + /** + \return The \c MODEL_TGP_REUSE_MODEL parameter. + */ + bool get_model_tgp_reuse_model ( void ) const; + + /// Access to the \c MODEL_SEARCH_MAX_TRIAL_PTS parameter. + /** + \return The \c MODEL_SEARCH_MAX_TRIAL_PTS parameter. + */ + int get_model_search_max_trial_pts ( void ) const; + + /// Access to the \c MODEL_EVAL_SORT parameter. + /** + \return The \c MODEL_EVAL_SORT parameter. + */ + NOMAD::model_type get_model_eval_sort ( void ) const; + + /// Access to the \c MODEL_EVAL_SORT_CAUTIOUS parameter. + /** + \return The \c MODEL_EVAL_SORT_CAUTIOUS parameter. + */ + bool get_model_eval_sort_cautious ( void ) const; + + + /// Access to all the models parameters. + /** + \param mp The models parameters -- \b OUT. + */ + void get_model_parameters ( NOMAD::model_params_type & mp ) const; + + /// Access to the \c VNS_SEARCH parameter. + /** + \return The \c VNS_SEARCH parameter. + */ + bool get_VNS_search ( void ) const; + + /// Access to the VNS trigger. + /** + \return The VNS trigger. + */ + const NOMAD::Double & get_VNS_trigger ( void ) const; + + /// Access to the number of initial LH search points. + /** + \return The number of initial LH search points. + */ + int get_LH_search_p0 ( void ) const; + + /// Access to the number of LH search points at each iteration. + /** + \return The number of LH search points at each iteration. + */ + int get_LH_search_pi ( void ) const; + + /// Access to the \c OPPORTUNISTIC_LH parameter. + /** + \return The \c OPPORTUNISTIC_LH parameter. + */ + bool get_opportunistic_LH ( void ) const; + + /// Access to the \c CACHE_SEARCH parameter. + /** + \return The \c CACHE_SEARCH parameter. + */ + bool get_cache_search ( void ) const; + + /// Access to the \c OPPORTUNISTIC_CACHE_SEARCH parameter. + /** + \return The \c OPPORTUNISTIC_CACHE_SEARCH parameter. + */ + bool get_opportunistic_cache_search ( void ) const; + + /// Set the \c SPECULATIVE_SEARCH parameter. + /** + \param ss The \c SPECULATIVE_SEARCH parameter -- \b IN. + */ + void set_SPECULATIVE_SEARCH ( bool ss ); + + /// Disable use of models. + /** + */ + void set_DISABLE_MODELS ( void ); + + /// Disable use of sort (lexicographic order used). + /** + */ + void set_DISABLE_EVAL_SORT ( void ); + + /// Set all the models parameters. + /** + \param mp The models parameters -- \b IN. + */ + void set_model_parameters ( const NOMAD::model_params_type & mp ); + + /// Set the \c MODEL_SEARCH parameter (1/3). + /** + \param i Index of the model search (1 or 2) -- \b IN. + \param ms The \c MODEL_SEARCH parameter -- \b IN. + */ + void set_MODEL_SEARCH ( int i , NOMAD::model_type ms ); + + /// Set the \c MODEL_SEARCH parameter (2/3). + /** + \param ms The \c MODEL_SEARCH parameter -- \b IN. + */ + void set_MODEL_SEARCH ( bool ms ); + + /// Set the \c MODEL_SEARCH parameter (3/3). + /** + \param mod_type The \c MODEL_SEARCH parameter -- \b IN. + */ + void set_MODEL_SEARCH ( NOMAD::model_type mod_type ); + + /// Set the \c MODEL_SEARCH_OPTIMISTIC parameter. + /** + \param mso The \c MODEL_SEARCH_OPTIMISTIC parameter -- \b IN. + */ + void set_MODEL_SEARCH_OPTIMISTIC ( bool mso ); + + /// Set the \c MODEL_SEARCH_PROJ_TO_MESH parameter. + /** + \param ptm The \c MODEL_SEARCH_PROJ_TO_MESH parameter -- \b IN. + */ + void set_MODEL_SEARCH_PROJ_TO_MESH ( bool ptm ); + + /// Set the \c MODEL_QUAD_RADIUS_FACTOR parameter. + /** + \param r The \c MODEL_QUAD_RADIUS_FACTOR parameter -- \b IN. + */ + void set_MODEL_QUAD_RADIUS_FACTOR ( const NOMAD::Double & r ); + + /// Set the \c MODEL_QUAD_USE_WP parameter. + /** + \param uwp The \c MODEL_QUAD_USE_WP parameter -- \b IN. + */ + void set_MODEL_QUAD_USE_WP ( bool uwp ); + + /// Set the \c MODEL_QUAD_MAX_Y_SIZE parameter. + /** + \param s The \c MODEL_QUAD_MAX_Y_SIZE parameter -- \b IN. + */ + void set_MODEL_QUAD_MAX_Y_SIZE ( int s ); + + /// Set the \c MODEL_QUAD_MIN_Y_SIZE parameter. + /** + \param s The \c MODEL_QUAD_MIN_Y_SIZE parameter -- \b IN. + */ + void set_MODEL_QUAD_MIN_Y_SIZE ( int s ); + + /// Set the \c MODEL_NP1_QUAD_EPSILON parameter. + /** + \param r The \c MODEL_NP1_QUAD_EPSILON parameter -- \b IN. + */ + void set_MODEL_NP1_QUAD_EPSILON ( const NOMAD::Double & r ); + + /// Set the \c MODEL_TGP_MODE parameter. + /** + \param m The \c MODEL_TGP_MODE parameter -- \b IN. + */ + void set_MODEL_TGP_MODE ( NOMAD::TGP_mode_type m ); + + /// Set the \c MODEL_TGP_REUSE_MODEL parameter. + /** + \param rm The \c MODEL_TGP_REUSE_MODEL parameter -- \b IN. + */ + void set_MODEL_TGP_REUSE_MODEL ( bool rm ); + + /// Set the \c MODEL_SEARCH_MAX_TRIAL_PTS parameter. + /** + \param s The \c MODEL_SEARCH_MAX_TRIAL_PTS parameter -- \b IN. + */ + void set_MODEL_SEARCH_MAX_TRIAL_PTS ( int s ); + + /// Set the \c MODEL_EVAL_SORT parameter (1/2). + /** + \param mes The \c MODEL_EVAL_SORT parameter -- \b IN. + */ + void set_MODEL_EVAL_SORT ( NOMAD::model_type mes ); + + /// Set the \c MODEL_EVAL_SORT parameter (2/2). + /** + \param mes The \c MODEL_EVAL_SORT parameter -- \b IN. + */ + void set_MODEL_EVAL_SORT ( bool mes ); + + + /// Set the \c MODEL_EVAL_SORT_CAUTIOUS parameter. + /** + \param mesc The \c MODEL_EVAL_SORT_CAUTIOUS parameter -- \b IN. + */ + void set_MODEL_EVAL_SORT_CAUTIOUS ( bool mesc ); + + /// Set the \c VNS_SEARCH parameter. + /** + \param vns The \c VNS_SEARCH parameter -- \b IN. + */ + void set_VNS_SEARCH ( bool vns ); + + /// Set the \c VNS_SEARCH parameter. + /** + \param trigger The VNS trigger -- \b IN. + */ + void set_VNS_SEARCH ( const NOMAD::Double & trigger ); + + /// Set the \c LH_SEARCH parameter. + /** + \param p0 Number of initial LH search points -- \b IN. + \param pi LH search points at each iteration -- \b IN. + */ + void set_LH_SEARCH ( int p0 , int pi ); + + /// Set the \c OPPORTUNISTIC_LH parameter. + /** + \param olh The \c OPPORTUNISTIC_LH parameter -- \b IN. + */ + void set_OPPORTUNISTIC_LH ( bool olh ); + + /// Set the \c CACHE_SEARCH parameter. + /** + \param cs The \c CACHE_SEARCH parameter -- \b IN. + */ + void set_CACHE_SEARCH ( bool cs ); + + /// Set the \c OPPORTUNISTIC_CACHE_SEARCH parameter. + /** + \param ocs The \c OPPORTUNISTIC_CACHE_SEARCH parameter -- \b IN. + */ + void set_OPPORTUNISTIC_CACHE_SEARCH ( bool ocs ); + + // Mesh: + // ----- + private: + + bool _use_smesh; ///< Use smesh (default xmesh) + bool _anisotropic_mesh; ///< Anisotropic mesh (xmesh only, i.e. _use_smesh=false) + NOMAD::Double _mesh_update_basis; ///< Mesh update basis (tau). + NOMAD::Double _poll_update_basis; ///< Poll update basis (beta). + int _mesh_coarsening_exponent; ///< Mesh coarsening exponent. + int _mesh_refining_exponent; ///< Mesh refining exponent. + int _initial_mesh_index; ///< Initial mesh index (ell_0). + NOMAD::Point _initial_mesh_size; ///< Initial (absolute) mesh size (delta^0). + NOMAD::Point _min_mesh_size; ///< Minimal (absolute) mesh size (delta_min). + NOMAD::Point _initial_poll_size; ///< Initial (absolute) poll size (delta^0). + NOMAD::Point _min_poll_size; ///< Minimal (absolute) poll size (Delta_min). + + bool _min_poll_size_defined; ///< \c true if _min_poll_size is user-defined. + + public: + + /// Access to the \c ANISOTROPIC_MESH parameter. + /** + \return The \c ANISOTROPIC_MESH parameter -- \b IN. + */ + bool get_anisotropic_mesh ( void ) const; + + /// Access to the \c USE_SMESH parameter. + /** + \return The \c USE_SMESH parameter -- \b IN. + */ + bool get_use_smesh ( void ) const; + + + + /// Access to the \c POLL_UPDATE_BASIS parameter. + /** + \return The \c POLL_UPDATE_BASIS parameter. + */ + const NOMAD::Double & get_poll_update_basis ( void ) const; + + + /// Access to the \c MESH_UPDATE_BASIS parameter. + /** + \return The \c MESH_UPDATE_BASIS parameter. + */ + const NOMAD::Double & get_mesh_update_basis ( void ) const; + + /// Access to the \c MESH_COARSENING_EXPONENT parameter. + /** + \return The \c MESH_COARSENING_EXPONENT parameter. + */ + int get_mesh_coarsening_exponent ( void ) const; + + /// Access to the \c MESH_REFINING_EXPONENT parameter. + /** + \return The \c MESH_REFINING_EXPONENT parameter. + */ + int get_mesh_refining_exponent ( void ) const; + + /// Access to the \c INITIAL_MESH_INDEX parameter. + /** + \return The \c INITIAL_MESH_INDEX parameter. + */ + int get_initial_mesh_index ( void ) const; + + + /// Access to the \c INITIAL_MESH_SIZE parameter. + /** + \return The \c INITIAL_MESH_SIZE parameter. + */ + const NOMAD::Point & get_initial_mesh_size ( void ) const; + + /// Access to the \c INITIAL_POLL_SIZE parameter. + /** + \return The \c INITIAL_POLL_SIZE parameter. + */ + const NOMAD::Point & get_initial_poll_size ( void ) const; + + /// Access to the \c MIN_MESH_SIZE parameter. + /** + \return The \c MIN_MESH_SIZE parameter. + */ + const NOMAD::Point & get_min_mesh_size ( void ) const; + + /// Access to the \c MIN_POLL_SIZE parameter. + /** + \return The \c MIN_POLL_SIZE parameter. + */ + const NOMAD::Point & get_min_poll_size ( void ) const; + + /// Access to \c _min_poll_size_defined. + /** + \return A boolean equal to \c true if the \c MIN_POLL_SIZE parameter + has been user-defined. + */ + bool get_min_poll_size_defined ( void ) const; + + /// Set the \c ANISOTROPIC_MESH parameter. + /** + \param anis The \c ANISOTROPIC_MESH parameter -- \b IN. + */ + void set_ANISOTROPIC_MESH ( bool anis ); + + /// Set the \c USE_SMESH parameter. + /** + \param use_smesh The \c USE_SMESH parameter -- \b IN. + */ + void set_USE_SMESH ( bool use_smesh ); + + + /// Set the \c MESH_UPDATE_BASIS parameter. + /** + \param tau The \c MESH_UPDATE_BASIS parameter -- \b IN. + */ + void set_MESH_UPDATE_BASIS ( const NOMAD::Double & tau ); + + /// Set the \c POLL_UPDATE_BASIS parameter. + /** + \param r The \c POLL_UPDATE_BASIS parameter -- \b IN. + */ + void set_POLL_UPDATE_BASIS ( const NOMAD::Double & r ); + + + /// Set the \c INITIAL_MESH_INDEX parameter. + /** + \param ell_0 The \c INITIAL_MESH_INDEX parameter -- \b IN. + */ + void set_INITIAL_MESH_INDEX ( int ell_0 ); + + /// Set the \c MESH_REFINING_EXPONENT parameter. + /** + \param mre The \c MESH_REFINING_EXPONENT parameter -- \b IN. + */ + void set_MESH_REFINING_EXPONENT ( int mre ); + + /// Set the \c MESH_COARSENING_EXPONENT parameter. + /** + \param mce The \c MESH_COARSENING_EXPONENT parameter -- \b IN. + */ + void set_MESH_COARSENING_EXPONENT ( int mce ); + + /// Set the \c MIN_MESH_SIZE parameter. + /** + \param mms Minimum mesh size -- \b IN. + \param relative Indicated as a relative value + -- \b IN -- \b optional (default = \c false). + */ + void set_MIN_MESH_SIZE ( const NOMAD::Double & mms , bool relative = false ); + + /// Set the \c MIN_MESH_SIZE parameter. + /** + \param index Index of a variable -- \b IN. + \param mms Minimum mesh size -- \b IN. + \param relative Indicated as a relative value + -- \b IN -- \b optional (default = \c false). + */ + void set_MIN_MESH_SIZE ( int index , + const NOMAD::Double & mms , + bool relative = false ); + + /// Set the \c MIN_MESH_SIZE parameter. + /** + \param mms Minimum mesh size -- \b IN. + \param relative Indicated as relative values + -- \b IN -- \b optional (default = \c false). + */ + void set_MIN_MESH_SIZE ( const NOMAD::Point & mms , bool relative = false ); + + /// Set the \c MIN_POLL_SIZE parameter. + /** + \param mps Minimum poll size -- \b IN. + \param relative Indicated as a relative value + -- \b IN -- \b optional (default = \c false). + */ + void set_MIN_POLL_SIZE ( const NOMAD::Double & mps , bool relative = false ); + + /// Set the \c MIN_POLL_SIZE parameter. + /** + \param index Index of a variable -- \b IN. + \param mps Minimum poll size -- \b IN. + \param relative Indicated as a relative value + -- \b IN -- \b optional (default = \c false). + */ + void set_MIN_POLL_SIZE ( int index , + const NOMAD::Double & mps , + bool relative = false ); + + /// Set the \c MIN_POLL_SIZE parameter. + /** + \param mps Minimum poll size -- \b IN. + \param relative Indicated as relative values + -- \b IN -- \b optional (default = \c false). + */ + void set_MIN_POLL_SIZE ( const NOMAD::Point & mps , bool relative = false ); + + /// Set the \c INITIAL_MESH_SIZE parameter. + /** + \param ims Initial mesh size -- \b IN. + \param relative Indicated as a relative value + -- \b IN -- \b optional (default = \c false). + */ + void set_INITIAL_MESH_SIZE ( const NOMAD::Double & ims , bool relative = false ); + + /// Set the \c INITIAL_MESH_SIZE parameter. + /** + \param index Index of a variable -- \b IN. + \param ims Initial mesh size -- \b IN. + \param relative Indicated as a relative value + -- \b IN -- \b optional (default = \c false). + */ + void set_INITIAL_MESH_SIZE ( int index , + const NOMAD::Double & ims , + bool relative = false ); + + /// Set the \c INITIAL_MESH_SIZE parameter. + /** + \param ims Initial mesh size -- \b IN. + \param relative Indicated as relative values + -- \b IN -- \b optional (default = \c false). + */ + void set_INITIAL_MESH_SIZE ( const NOMAD::Point & ims , bool relative = false ); + + + /// Set the \c INITIAL_POLL_SIZE parameter. + /** + \param ims Initial poll size -- \b IN. + \param relative Indicated as a relative value + -- \b IN -- \b optional (default = \c false). + */ + void set_INITIAL_POLL_SIZE ( const NOMAD::Double & ims , bool relative = false ); + + /// Set the \c INITIAL_POLL_SIZE parameter. + /** + \param index Index of a variable -- \b IN. + \param ims Initial poll size -- \b IN. + \param relative Indicated as a relative value + -- \b IN -- \b optional (default = \c false). + */ + void set_INITIAL_POLL_SIZE ( int index , + const NOMAD::Double & ims , + bool relative = false ); + + /// Set the \c INITIAL_POLL_SIZE parameter. + /** + \param ims Initial poll size -- \b IN. + \param relative Indicated as relative values + -- \b IN -- \b optional (default = \c false). + */ + void set_INITIAL_POLL_SIZE ( const NOMAD::Point & ims , bool relative = false ); + + + + // Directions: + // ----------- + private: + + /// Types of poll directions. + std::set<NOMAD::direction_type> _direction_types; + + /// Types of directions for the secondary poll. + std::set<NOMAD::direction_type> _sec_poll_dir_types; + + /// Change direction types to prevent using models for finding the (n+1)th direction + /// Apply if ORTHO N+1 QUAD -> ORTHO N+1 NEG. + void set_DIRECTION_TYPE_NO_MODEL ( void ); + + + public: + + /// Access to the list of poll direction types. + /** + \return The list of poll direction types. + */ + const std::set<NOMAD::direction_type> & get_direction_types ( void ) const; + + /// Access to the list of secondary poll direction types. + /** + \return The list of secondary poll direction types. + */ + const std::set<NOMAD::direction_type> & get_sec_poll_dir_types ( void ) const; + + + /// Check if there are Ortho-MADS directions. + /** + \return A boolean equal to \c true if there is at least one + Ortho-MADS direction in the list of poll directions + or in the list of secondary poll directions. + */ + bool has_orthomads_directions ( void ) const; + + + /// Check if a direction type that required dynamic completion for the (n+1)th direction. + /** + \return true if a dynamic completion is required. + */ + bool has_dynamic_direction(void) const; + + + /// Reset the directions. + void reset_directions ( void ); + + + /// Add a new direction type. + /** + \param dt The new direction type -- \b IN. + */ + void set_DIRECTION_TYPE ( NOMAD::direction_type dt ); + + /// Add a set of new direction types. + /** + \param dt The set of new direction types -- \b IN. + */ + void set_DIRECTION_TYPE ( const std::set<NOMAD::direction_type> & dt ); + + + /// Add a new direction type for the secondary poll. + /** + \param dt The new direction type -- \b IN. + */ + void set_SEC_POLL_DIR_TYPE ( NOMAD::direction_type dt ); + + /// Add a set of new direction types for the secondary poll. + /** + \param dt The set of new direction types -- \b IN. + */ + void set_SEC_POLL_DIR_TYPE ( const std::set<NOMAD::direction_type> & dt ); + + /// Enables use of quad model to determine prospect direction + /// for Ortho n+1 direction type + /** + \param qmpd boolean -- \b IN. + */ + void set_QUAD_MODEL_PROSPECT_DIR ( bool qmpd ) ; + + // Starting point(s): + // ------------------ + private: + + std::vector<NOMAD::Point *> _x0s; ///< List of starting points. + std::string _x0_cache_file; ///< Cache file containing starting points. + + public: + + /// Add a new point in the list of starting points. + /** + \param x0 The new point -- \b IN. + */ + void set_X0 ( const NOMAD::Point & x0 ); + + /// Indicate a cache file containing starting points. + /** + \param file_name Name of the cache file -- \b IN. + */ + void set_X0 ( const std::string & file_name ); + + /// Reset all string points. + void reset_X0 ( void ); + + /// Access to the list of starting points. + /** + \return The list of starting points. + */ + const std::vector<NOMAD::Point *> & get_x0s ( void ) const; + + /// Access to the name of a cache file containing starting points. + /** + \return The file name. + */ + const std::string & get_x0_cache_file ( void ) const; + + // Signature: standard or extern (only one is != NULL): + // ---------------------------------------------------- + private: + + /// Standard signature. + /** + Created and deleted by the Parameters class. + */ + NOMAD::Signature * _std_signature; + + /// Extern signature. + /** + Created and deleted outside the class. + */ + NOMAD::Signature * _extern_signature; + + public: + + /// Access to the signature. + /** + \return The one non-NULL signature. + */ + NOMAD::Signature * get_signature ( void ) const; + + /// Set a new extern signature. + /** + Deletes the standard signature. + \param s A pointer to the extern signature -- \b IN. + */ + void set_EXTERN_SIGNATURE ( NOMAD::Signature * s ); + + // Dimension: + // ---------- + private: + + /// Dimension. + /** + - Number of variables. + - Parameter \c DIMENSION. + */ + int _dimension; + + public: + + /// Access to the dimension. + /** + \return The dimension. + */ + int get_dimension ( void ) const; + + /// Set the dimension. + /** + \param n The dimension -- \b IN. + \return \c true if the operation succeeded. + */ + bool set_DIMENSION ( int n ); + + // Fixed variables: + // ---------------- + private: + + /// Fixed variables. + /** + - This point is of dimension \c n (parameter \c DIMENSION). + - Undefined values correspond to free variables. + */ + NOMAD::Point _fixed_variables; + + /// Number of free variables. + int _nb_free_variables; + + public: + + /// Access to the number of free variables. + /** + \return The number of free variables. + */ + int get_nb_free_variables ( void ) const; + + /// Access to the fixed variables. + /** + \return The fixed variables. + */ + const NOMAD::Point & get_fixed_variable ( void ) const + { + return get_fixed_variables(); + } + + /// Access to the fixed variables. + /** + \return The fixed variables. + */ + const NOMAD::Point & get_fixed_variables ( void ) const; + + /// Test if a variable is fixed. + /** + \param i Index of the variable -- \b IN. + \return A boolean equal to \c true if the variable \c i is fixed. + */ + bool variable_is_fixed ( int i ) const; + + /// Reset the fixed variables. + /** + This frees all the variables. + */ + void reset_fixed_variables ( void ); + + /// Fix one variable. + /** + \param i Index of the variable -- \b IN. + \param value Value of the fixed variable -- \b IN. + */ + void set_FIXED_VARIABLE ( int i , const NOMAD::Double & value ); + + /// Fix one variable. + /** + The value of the variable is based on the starting point. + \param i Index of the variable -- \b IN. + */ + void set_FIXED_VARIABLE ( int i ); + + /// Fix a series of variables. + /** + \param fv The fixed variables; This point is of dimension \c n; + free variables correspond to undefined values -- \b IN. + */ + void set_FIXED_VARIABLE ( const NOMAD::Point & fv ); + + /// Free a variable. + /** + \param i Index of the variable -- \b IN. + */ + void set_FREE_VARIABLE ( int i ) { set_FIXED_VARIABLE ( i , NOMAD::Double() ); } + + // Periodic variables: + // ------------------- + + /// Periodic variables. + /** + - This vector is of size \c n. + - \c _periodic_variables[i] is equal to \c true if + the variable \c i is periodic. + */ + std::vector<bool> _periodic_variables; + + /// Access to the periodic variables. + /** + \return The periodic variables + */ + const std::vector<bool> & get_periodic_variable ( void ) const + { + return get_periodic_variables(); + } + + /// Access to the periodic variables. + /** + \return The periodic variables + */ + const std::vector<bool> & get_periodic_variables ( void ) const; + + /// Check if there is periodic variables. + /** + \return A boolean equal to \c true if there is periodic variables. + */ + bool has_periodic_variables ( void ) const + { + return !_periodic_variables.empty(); + } + + /// Reset periodic variables. + void reset_periodic_variables ( void ); + + /// Set one variable to be periodic. + /** + \param i Index of the variable -- \b IN. + */ + void set_PERIODIC_VARIABLE ( int i ); + + /// Set a series of variables to be periodic. + /** + \param pv Vector of size \c n indicating the + periodic variables -- \b IN. + */ + void set_PERIODIC_VARIABLE ( const std::vector<bool> & pv ); + + // Categorical variables: + // ---------------------- + private: + + /// Extended poll trigger. + /** + - Must be strictly positive. + - May be relative. + */ + NOMAD::Double _extended_poll_trigger; + + /// Equal to \c true if the extended poll trigger is relative. + bool _relative_ept; + + /// Equal to \c true if the extended poll is enabled. + bool _extended_poll_enabled; + + /// Neighborhood executable for using batch mode with categorical variables. + std::string _neighbors_exe; + + public: + + /// Access to the extended poll trigger. + /** + \return The extended poll trigger. + */ + const NOMAD::Double & get_extended_poll_trigger ( void ) const; + + /// Check if the extended poll trigger is relative. + /** + \return A boolean equal to \c true if the extended poll trigger is relative. + */ + bool get_relative_ept ( void ) const; + + /// Check if the extended poll is enabled. + /** + \return A boolean equal to \c true if the extended poll is enabled. + */ + bool get_extended_poll_enabled ( void ) const; + + /// Access to the neighborhood executable. + /** + \return The neighborhood executable. + */ + const std::string & get_neighbors_exe ( void ) const; + + /// Set the extended poll trigger. + /** + \param ept The extended poll trigger -- \b IN. + \param rel A boolean equal to \c true if the extended poll + trigger is relative -- \b IN. + */ + void set_EXTENDED_POLL_TRIGGER ( const NOMAD::Double & ept , bool rel ); + + /// Enable or disable the extended poll. + /** + \param epe A boolean equal to \c true if the extended poll is enabled -- \b IN. + */ + void set_EXTENDED_POLL_ENABLED ( bool epe ); + + /// Set the neighborhood executable. + /** + \param ne The neighborhood executable. + */ + void set_NEIGHBORS_EXE ( const std::string & ne ); + + // Groups of variables: + // -------------------- + private: + + /// Groups of variables. + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> _var_groups; + + /// User groups of variables. + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> _user_var_groups; + + /// Reset a group of variables. + /** + \param g Group to reset; may be \c _var_groups or \c _user_var_groups + -- \b IN/OUT. + */ + void reset_variable_groups + ( std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & g ) const; + + public: + + /// Reset groups of variables. + void reset_variable_groups ( void ); + + /// Access to the groups of variables. + /** + \return The groups of variables. + */ + const std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & + get_variable_groups ( void ) const; + + /// Set one group of variables. + /** + Basic version. + \param var_indexes Indexes of the variables of the group -- \b IN. + */ + void set_VARIABLE_GROUP ( const std::set<int> & var_indexes ); + + /// Set one group of variables. + /** + Advanced version. + \param var_indexes Indexes of the variables of the group -- \b IN. + \param prim_poll_dir_types Types of the poll directions -- \b IN. + \param sec_poll_dir_types Types of the secondary poll directions -- \b IN. + */ + void set_VARIABLE_GROUP + ( const std::set<int> & var_indexes , + const std::set<NOMAD::direction_type> & prim_poll_dir_types , + const std::set<NOMAD::direction_type> & sec_poll_dir_types ); + + /// Set several groups of variables. + /** + \param vg A list of groups of variables -- \b IN. + */ + void set_VARIABLE_GROUP ( const std::list<NOMAD::Variable_Group*> & vg ); + + // Bounds and scaling: + // ------------------- + private: + + NOMAD::Point _lb; ///< Lower bounds. + NOMAD::Point _ub; ///< Upper bounds. + NOMAD::Point _scaling; ///< Scaling. + + public: + + /// Access to the lower bounds. + /** + \return The lower bounds. + */ + const NOMAD::Point & get_lb ( void ) const; + + /// Access to the upper bounds. + /** + \return The upper bounds. + */ + const NOMAD::Point & get_ub ( void ) const; + + /// Access to the lower bounds. + /** + \return The lower bounds. + */ + const NOMAD::Point & get_lower_bound ( void ) const { return get_lb(); } + + /// Access to the upper bounds. + /** + \return The upper bounds. + */ + const NOMAD::Point & get_upper_bound ( void ) const { return get_ub(); } + + /// Access to the scaling. + /** + \return The scaling. + */ + const NOMAD::Point & get_scaling ( void ) const; + + /// Reset the bounds. + void reset_bounds ( void ); + + /// Reset the scaling. + void reset_scaling ( void ); + + /// Set one lower bound. + /** + \param i Index of the variable -- \b IN. + \param lb Lower bound -- \b IN. + */ + void set_LOWER_BOUND ( int i , const NOMAD::Double & lb ); + + /// Set all lower bounds. + /** + Use undefined values for variables without bounds. + \param lb Lower bounds -- \b IN. + */ + void set_LOWER_BOUND ( const NOMAD::Point & lb ); + + /// Set one upper bound. + /** + \param i Index of the variable -- \b IN. + \param ub Upper bound -- \b IN. + */ + void set_UPPER_BOUND ( int i , const NOMAD::Double & ub ); + + /// Set all upper bounds. + /** + Use undefined values for variables without bounds. + \param ub Upper bounds -- \b IN. + */ + void set_UPPER_BOUND ( const NOMAD::Point & ub ); + + /// Set the scaling of one variable. + /** + \param i Index of the variable -- \b IN. + \param s Scaling -- \b IN. + */ + void set_SCALING ( int i , const NOMAD::Double & s ); + + /// Set the scaling for all variables. + /** + Use undefined values for variables scaling. + \param s Scaling -- \b IN. + */ + void set_SCALING ( const NOMAD::Point & s ); + + // Blackboxes (inputs and outputs): + // -------------------------------- + private: + + /// Blackbox input types. + std::vector<NOMAD::bb_input_type> _bb_input_type; + + /// Parameter \c BB_INPUT_INCLUDE_TAG. + bool _bb_input_include_tag; + + /// Parameter \c BB_INPUT_INCLUDE_SEED. + bool _bb_input_include_seed; + + /// Blackbox output types. + /** + May be modified during the algorithm (PEB constraints). + */ + mutable std::vector<NOMAD::bb_output_type> _bb_output_type; + + /// List of blackbox executables. + std::list<std::string> _bb_exe; + + /// List of objective indexes. + std::list<int> _index_obj; + + /// Index for the output \c STAT_SUM. + int _index_stat_sum; + + /// Index for the output \c STAT_AVG. + int _index_stat_avg; + + /// Index for the output \c CNT_EVAL. + /** + - \c 0 or \c 1. + - \c CNT_EVAL indicates if a blackbox evaluation has to be counted. + */ + int _index_cnt_eval; + + /// Parameter \c BB_REDIRECTION. + bool _bb_redirection; + + public: + + /// Access to the number of blackbox outputs. + /** + \return The number of blackbox outputs. + */ + int get_bb_nb_outputs ( void ) const; + + /// Access to the \c BB_INPUT_INCLUDE_TAG parameter. + /** + \return The \c BB_INPUT_INCLUDE_TAG parameter. + */ + bool get_bb_input_include_tag ( void ) const; + + /// Access to the \c BB_INPUT_INCLUDE_SEED parameter. + /** + \return The \c BB_INPUT_INCLUDE_SEED parameter. + */ + bool get_bb_input_include_seed ( void ) const; + + /// Access to the blackbox input types. + /** + \return The blackbox input types. + */ + const std::vector<NOMAD::bb_input_type> & get_bb_input_type ( void ) const; + + /// Access to the blackbox output types. + /** + \return The blackbox output types. + */ + const std::vector<NOMAD::bb_output_type> & get_bb_output_type ( void ) const; + + /// Access to the objective indexes. + /** + \return The list of objective indexes. + */ + const std::list<int> & get_index_obj ( void ) const; + + /// Access to the number of objective functions. + /** + \return The number of objective functions. + */ + int get_nb_obj ( void ) const; + + /// Check the display and file stats. + /** + \param stats The stats -- \b IN. + \return A booleam equal to \c true if the stats are valid. + */ + bool check_display_stats ( const std::list<std::string> & stats ) const; + + /// Check if there is a \c STAT_SUM output. + /** + \return A boolean equal to \c true if there a \c STAT_SUM output. + */ + bool check_stat_sum ( void ) const; + + /// Check if there is a \c STAT_AVG output. + /** + \return A boolean equal to \c true if there is a \c STAT_AVG output. + */ + bool check_stat_avg ( void ) const; + + /// Access the index of output \c CNT_EVAL output. + /** + \return Index of the \c CNT_EVAL output. + \return \c -1 if there is no \c CNT_EVAL output. + */ + int get_index_cnt_eval ( void ) const; + + /// Access the index of output \c STAT_SUM output. + /** + \return Index of the \c STAT_SUM output. + \return \c -1 if there is no \c STAT_SUM output. + */ + int get_index_stat_sum ( void ) const; + + /// Access the index of output \c STAT_AVG output. + /** + \return Index of the \c STAT_AVG output. + \return \c -1 if there is no \c STAT_AVG output. + */ + int get_index_stat_avg ( void ) const; + + /// Access to the list of blackbox executables. + /** + \return The list of blackbox executables. + */ + const std::list<std::string> & get_bb_exe ( void ) const; + + /// Access to the \c BB_REDIRECTION parameter. + /** + \return The \c BB_REDIRECTION parameter. + */ + bool get_bb_redirection ( void ) const; + + /// Set the \c BB_INPUT_INCLUDE_TAG parameter. + /** + \param bbiit The \c BB_INPUT_INCLUDE_TAG parameter -- \b IN. + */ + void set_BB_INPUT_INCLUDE_TAG ( bool bbiit ); + + /// Set the \c BB_INPUT_INCLUDE_SEED parameter. + /** + \param bbiis The \c BB_INPUT_INCLUDE_SEED parameter -- \b IN. + */ + void set_BB_INPUT_INCLUDE_SEED ( bool bbiis ); + + /// Set the blackbox input type of one variable. + /** + \param index Index of the variable -- \b IN. + \param bbit Type of the variable -- \b IN. + */ + void set_BB_INPUT_TYPE ( int index , NOMAD::bb_input_type bbit ); + + /// Set the blackbox input types of all variables. + /** + \param bbit Types of the variables -- \b IN. + */ + void set_BB_INPUT_TYPE ( const std::vector<NOMAD::bb_input_type> & bbit ); + + /// Set the blackbox input types of all variables. + /** + \param bbit Types of the variables -- \b IN. + */ + void set_BB_INPUT_TYPE ( const std::list<NOMAD::bb_input_type> & bbit ); + + /// Set the blackbox output types. + /** + \param bbot Blackbox output types -- \b IN. + */ + void set_BB_OUTPUT_TYPE ( const std::list<NOMAD::bb_output_type> & bbot ); + + /// Set the blackbox output types. + /** + \param bbot Blackbox output types -- \b IN. + */ + void set_BB_OUTPUT_TYPE ( const std::vector<NOMAD::bb_output_type> & bbot ); + + /// Set a list of blackbox executable names. + /** + Must correspond to the blackbox output types. + \param bbexe The list of blackbox executable names -- \b IN. + */ + void set_BB_EXE ( const std::list<std::string> & bbexe ); + + /// Set a list of blackbox executable names. + /** + \param m Number of blackbox outputs and size of \c bbexe -- \b IN. + \param bbexe The list of blackbox executable names -- \b IN. + */ + void set_BB_EXE ( int m , const std::string * bbexe ); + + /// Set a unique blackbox executable name. + /** + \param bbexe The blackbox executable name -- \b IN. + */ + void set_BB_EXE ( const std::string & bbexe ); + + /// Set the \c BB_REDIRECTION parameter. + /** + \param bbr The \c BB_REDIRECTION parameter -- \b IN. + */ + void set_BB_REDIRECTION ( bool bbr ); + + /// Reset the PEB statuses. + /** + Set all outputs at NOMAD::PEB_E (PEB constraint in "extreme" status) + to NOMAD::PEB_P (PEB constraint in "progressive" status). + */ + void reset_PEB_changes ( void ) const; + + /// Change constraints from PEB to PB. + /** + Set all outputs at NOMAD::PEB to NOMAD::PB + */ + void change_PEB_to_PB ( void ); + + /// Change the status of one PEB constraint. + /** + The status is changed from + NOMAD::PEB_P (PEB constraint in "progressive" status) + to NOMAD::PEB_E (PEB constraint in "extreme" status). + \param index Index of the PEB constraint. + */ + void change_PEB_constraint_status ( int index ) const; + + // Surrogates: + // ----------- + private: + + /// Surrogate executables. + /** + \c _sgte_exe[bb_exe] corresponds to the surrogate associated + with the blackbox true executable \c bb_exe. + */ + std::map<std::string,std::string> _sgte_exe; + + bool _disable_eval_sort; ///< Sort disablement + + /// Flag equal to \c true if surrogates are used to sort evaluation points. + bool _sgte_eval_sort; + + /// Flag equal to \c true if the problem has a surrogate. + bool _has_sgte; + + /// Flag equal to \c true if NOMAD considers only surrogates. + bool _opt_only_sgte; + + /// Surrogate cost. + /** + Number of surrogate evaluations counting as one blackbox evaluation. + */ + int _sgte_cost; + + /// Maximum number of surrogate evaluations. + int _sgte_max_eval; + + /// Surrogate cache file. + std::string _sgte_cache_file; + + public: + + /// Access to the surrogate associated with a truth executable. + /** + \param bb_exe The truth executable -- \b IN. + \return The surrogate executable name. + \return An empty string if \c bb_exe has no surrogate. + */ + std::string get_sgte_exe ( const std::string & bb_exe ) const; + + /// Access to the \c SGTE_EVAL_SORT parameter. + /** + \return The \c SGTE_EVAL_SORT parameter. + */ + bool get_sgte_eval_sort ( void ) const; + + /// Access to the \c SGTE_COST parameter. + /** + \return The \c SGTE_COST parameter. + */ + int get_sgte_cost ( void ) const; + + /// Access to the \c MAX_SGTE_EVAL parameter. + /** + \return The \c MAX_SGTE_EVAL parameter. + */ + int get_max_sgte_eval ( void ) const; + + /// Access to the \c SGTE_CACHE_FILE parameter. + /** + \return The \c SGTE_CACHE_FILE parameter. + */ + const std::string & get_sgte_cache_file ( void ) const; + + /// Access to the \c HAS_SGTEparameter. + /** + \return The \c HAS_SGTEparameter. + */ + bool has_sgte ( void ) const; + + /// Access to the \c OPT_ONLY_SGTE parameter. + /** + \return The \c OPT_ONLY_SGTE parameter. + */ + bool get_opt_only_sgte ( void ) const; + + /// Check if a surrogate executable has been defined. + /** + \return A boolean equal to \c true if + a surrogate executable has been defined. + */ + bool has_sgte_exe ( void ) const; + + /// Set the \c SGTE_EXE parameter. + /** + \param bb_exe Truth executable -- \b IN. + \param sgte_exe Associated surrogate executable -- \b IN. + */ + void set_SGTE_EXE ( const std::string & bb_exe , const std::string & sgte_exe ); + + /// Set the \c SGTE_EVAL_SORT parameter. + /** + \param ses The \c SGTE_EVAL_SORT parameter -- \b IN. + */ + void set_SGTE_EVAL_SORT ( bool ses ); + + /// Set the \c HAS_SGTE parameter. + /** + \param hs The \c HAS_SGTE parameter -- \b IN. + */ + void set_HAS_SGTE ( bool hs ); + + /// Set the \c OPT_ONLY_SGTE parameter. + /** + \param oos The \c OPT_ONLY_SGTE parameter -- \b IN. + */ + void set_OPT_ONLY_SGTE ( bool oos ); + + /// Set the \c SGTE_COST parameter. + /** + \param sc The \c SGTE_COST parameter -- \b IN. + */ + void set_SGTE_COST ( int sc ); + + /// Set the \c MAX_SGTE_EVAL parameter. + /** + \param mse The \c MAX_SGTE_EVAL parameter -- \b IN. + */ + void set_MAX_SGTE_EVAL ( int mse ); + + /// Set the \c SGTE_CACHE_FILE parameter. + /** + \param scf The \c SGTE_CACHE_FILE parameter -- \b IN. + */ + void set_SGTE_CACHE_FILE ( const std::string & scf ); + + // Barrier: + // -------- + private: + NOMAD::Double _h_min; ///< Value of \c h_min. + NOMAD::Double _h_max_0; ///< Initial value of \c h_max. + NOMAD::Double _rho; ///< Rho parameter of the progressive barrier. + NOMAD::hnorm_type _h_norm; ///< Norm used to compute the feasibility function \c h. + + /// Flag equal to \c true if there are constraints. + bool _has_constraints; + + /// Flag equal to \c true if there are filter or progressive barrier constraints. + bool _has_filter_constraints; + + /// Flag equal to \c true if there are extreme barrier constraints. + bool _has_EB_constraints; + + /// Type of the barrier. + /** + May be NOMAD::FILTER, NOMAD::PB, NOMAD::PEB_P, or NOMAD::EB. + */ + NOMAD::bb_output_type _barrier_type; + + public: + + /// Access to the \c H_MIN parameter. + /** + \return The \c H_MIN parameter. + */ + const NOMAD::Double & get_h_min ( void ) const; + + /// Access to the \c H_MAX_0 parameter. + /** + \return The \c H_MAX_0 parameter. + */ + const NOMAD::Double & get_h_max_0 ( void ) const; + + /// Access to the \c RHO parameter. + /** + \return The \c RHO parameter. + */ + const NOMAD::Double & get_rho ( void ) const; + + /// Access to the \c H_NORM parameter. + /** + \return The \c H_NORM parameter. + */ + NOMAD::hnorm_type get_h_norm ( void ) const; + + /// Access to the type of barrier. + /** + \return The type of barrier. + */ + NOMAD::bb_output_type get_barrier_type ( void ) const; + + /// Check if there are constraints. + /** + \return A boolean equal to \c true if there are constraints. + */ + bool has_constraints ( void ) const; + + /// Check if there are extreme barrier constraints. + /** + \return A boolean equal to \c true if there are extreme barrier constraints. + */ + bool has_EB_constraints ( void ) const; + + /// Check if the progressive barrier (PB) is used. + /** + \return A boolean equal to \c true if the PB is used. + */ + bool use_sec_poll_center ( void ) const; + + /// Set the \c H_MIN parameter. + /** + \param h_min The \c H_MIN parameter -- \b IN. + */ + void set_H_MIN ( const NOMAD::Double & h_min ); + + /// Set the \c H_MAX_0 parameter. + /** + \param h_max The \c H_MAX_0 parameter -- \b IN. + */ + void set_H_MAX_0 ( const NOMAD::Double & h_max ); + + /// Set the \c RHO parameter. + /** + \param rho The \c RHO parameter -- \b IN. + */ + void set_RHO ( const NOMAD::Double & rho ); + + /// Set the \c H_NORM parameter. + /** + \param h_norm The \c H_NORM parameter -- \b IN. + */ + void set_H_NORM ( NOMAD::hnorm_type h_norm ); + + // MULTI-MADS parameters: + // ---------------------- + private: + + /// Number of MADS runs in Multi-MADS. + int _multi_nb_mads_runs; + + /// Maximum number of blackbox evaluations in Multi-MADS. + int _multi_overall_bb_eval; + + /// Flag equal to \c true if the delta criterion is used in Multi-MADS. + bool _multi_use_delta_crit; + + /// Bounds on the objective necessary for the display of the \c surf stat. + NOMAD::Point _multi_f_bounds; + + /// Multi-MADS reformulation. + /** + May be NOMAD::NORMALIZED, NOMAD::PRODUCT, + NOMAD::DIST_L1, NOMAD::DIST_L2, or NOMAD::DIST_LINF. + */ + NOMAD::multi_formulation_type _multi_formulation; + + public: + + /// Access to the \c MULTI_NB_MADS_RUNS parameter. + /** + \return The \c MULTI_NB_MADS_RUNS parameter. + */ + int get_multi_nb_mads_runs ( void ) const; + + /// Access to the \c MULTI_OVERALL_BB_EVAL parameter. + /** + \return The \c MULTI_OVERALL_BB_EVAL parameter. + */ + int get_multi_overall_bb_eval ( void ) const; + + /// Access to the \c MULTI_USE_DELTA_CRIT parameter. + /** + \return The \c MULTI_USE_DELTA_CRIT parameter. + */ + bool get_multi_use_delta_crit ( void ) const; + + /// Access to the \c MULTI_F_BOUNDS parameter. + /** + \return The \c MULTI_F_BOUNDS parameter. + */ + const NOMAD::Point & get_multi_f_bounds ( void ) const; + + /// Access to the \c MULTI_FORMULATION parameter. + /** + \return The \c MULTI_FORMULATION parameter. + */ + NOMAD::multi_formulation_type get_multi_formulation ( void ) const; + + /// Set the \c MULTI_NB_MADS_RUNS parameter. + /** + \param mads_runs The \c MULTI_NB_MADS_RUNS parameter -- \b IN. + */ + void set_MULTI_NB_MADS_RUNS ( int mads_runs ); + + /// Set the \c MULTI_OVERALL_BB_EVAL parameter. + /** + \param bbe The \c MULTI_OVERALL_BB_EVAL parameter -- \b IN. + */ + void set_MULTI_OVERALL_BB_EVAL ( int bbe ); + + /// Set the \c MULTI_USE_DELTA_CRIT parameter. + /** + \param udc The \c MULTI_USE_DELTA_CRIT parameter -- \b IN. + */ + void set_MULTI_USE_DELTA_CRIT ( bool udc ); + + /// Set the \c MULTI_F_BOUNDS parameter. + /** + \param mfb The \c MULTI_F_BOUNDS parameter -- \b IN. + */ + void set_MULTI_F_BOUNDS ( const NOMAD::Point & mfb ); + + /// Set the \c MULTI_FORMULATION parameter. + /** + \param mf The \c MULTI_FORMULATION parameter -- \b IN. + */ + void set_MULTI_FORMULATION ( NOMAD::multi_formulation_type mf ); + + // Opportunistic strategy parameters: + // ---------------------------------- + private: + + /// Flag equal to \c true if the opportunistic strategy is enabled. + bool _opportunistic_eval; + + /// Minimum number of successes. + /** + Parameter \c OPPORTUNISTIC_MIN_NB_SUCCESS. + */ + int _opportunistic_min_nb_success; + + /// Minimum number of evaluations. + /** + Parameter \c OPPORTUNISTIC_MIN_EVAL. + */ + int _opportunistic_min_eval; + + /// Minimum (relative) percentage of feasible objective improvement. + /** + Parameter \c OPPORTUNISTIC_MIN_F_IMPRVMT. + */ + NOMAD::Double _opportunistic_min_f_imprvmt; + + /// Flag equal to \c true if the lucky evaluation is enabled. + /** + Do one more eval "for luck". + */ + bool _opportunistic_lucky_eval; + + + /// Max block size for list evaluation + /** + Parameter \c BB_MAX_BLOCK_SIZE. + */ + int _bb_max_block_size; + + /// Block of points evaluation + /** + Parameter \c EVAL_POINTS_AS_BLOCK. + */ + bool _eval_points_as_block; + + public: + + /// Access to the \c OPPORTUNISTIC_EVAL parameter. + /** + \return The \c OPPORTUNISTIC_EVAL parameter + */ + bool get_opportunistic_eval ( void ) const; + + /// Access to the \c OPPORTUNISTIC_MIN_NB_SUCCESS parameter. + /** + \return The \c OPPORTUNISTIC_MIN_NB_SUCCESS parameter. + */ + int get_opportunistic_min_nb_success ( void ) const; + + /// Access to the \c OPPORTUNISTIC_MIN_EVAL parameter. + /** + \return The \c OPPORTUNISTIC_MIN_EVAL parameter. + */ + int get_opportunistic_min_eval ( void ) const; + + /// Access to the \c OPPORTUNISTIC_MIN_F_IMPRVMT parameter. + /** + \return The \c OPPORTUNISTIC_MIN_F_IMPRVMT parameter. + */ + const NOMAD::Double & get_opportunistic_min_f_imprvmt ( void ) const; + + /// Access to the \c OPPORTUNISTIC_LUCKY_EVAL parameter. + /** + \return The \c OPPORTUNISTIC_LUCKY_EVAL parameter. + */ + bool get_opportunistic_lucky_eval ( void ) const; + + /// Access to the \c BB_MAX_BLOCK_SIZE parameter + /** + \return the \c BB_MAX_BLOCK_SIZE parameter + */ + int get_bb_max_block_size ( void ) const ; + + /// Set the \c BB_MAX_BLOCK_SIZE parameter. + /** + \param bb_block_size The \c BB_MAX_BLOCK_SIZE parameter -- \b IN. + */ + void set_BB_MAX_BLOCK_SIZE ( int bb_block_size ); + + /// Access to the \c EVAL_POINTS_AS_BLOCK parameter + /** + \return true if points are evaluated as a block (number of elements >=1) + */ + bool eval_points_as_block() const {return _eval_points_as_block;} + + + /// Set the \c OPPORTUNISTIC_EVAL parameter. + /** + \param opp_eval The \c OPPORTUNISTIC_EVAL parameter -- \b IN. + */ + void set_OPPORTUNISTIC_EVAL ( bool opp_eval ); + + /// Set the \c OPPORTUNISTIC_MIN_NB_SUCCESS parameter. + /** + \param opp_min_nb_succ The \c OPPORTUNISTIC_MIN_NB_SUCCESS parameter -- \b IN. + */ + void set_OPPORTUNISTIC_MIN_NB_SUCCESS ( int opp_min_nb_succ ); + + /// Set the \c OPPORTUNISTIC_MIN_EVAL parameter. + /** + \param opp_min_eval The \c OPPORTUNISTIC_MIN_EVAL parameter -- \b IN. + */ + void set_OPPORTUNISTIC_MIN_EVAL ( int opp_min_eval ); + + /// Set the \c OPPORTUNISTIC_MIN_F_IMPRVMT parameter. + /** + \param opp_min_f_imprvt The \c OPPORTUNISTIC_MIN_F_IMPRVMT parameter -- \b IN. + */ + void set_OPPORTUNISTIC_MIN_F_IMPRVMT ( const NOMAD::Double & opp_min_f_imprvt ); + + /// Set the \c OPPORTUNISTIC_LUCKY_EVAL parameter. + /** + \param opp_lucky_eval The \c OPPORTUNISTIC_LUCKY_EVAL parameter -- \b IN. + */ + void set_OPPORTUNISTIC_LUCKY_EVAL ( bool opp_lucky_eval ); + + + + }; /*----------------------------------------------------------------------*/ - /// Constructor #1. - /** - \param out Display -- \b IN. - */ - explicit Parameters ( const NOMAD::Display & out ) - : _out ( out ) , - _std_signature ( NULL ) , - _extern_signature ( NULL ) { init(); } - - /// Constructor #2. - /** - From an extern signature. - \param extern_signature A pointer to the extern signature -- \b IN. - \param out Display -- \b IN. - */ - explicit Parameters ( NOMAD::Signature * extern_signature , - const NOMAD::Display & out ) - : _out ( out ) , - _std_signature ( NULL ) , - _extern_signature ( extern_signature ) { init(); } - - /// Destructor. - virtual ~Parameters ( void ); - - /// Display parameter help. - /** - - Help option obtained with command \c nomad \c -h. - - A list of parameters is given as the program arguments. - \param argc Number of command line arguments -- \b IN. - \param argv The command line arguments -- \b IN. - \param developer Bool to request developer help (defaut=false) -- \b IN. - */ - void help ( int argc , char ** argv , bool developer=false) const; - - /// Display parameter help. - /** - For a specific parameter. - \param param_name Name of the parameter -- \b IN. - \param developer Bool to request developer help (defaut=false) -- \b IN. - */ - void help ( const std::string & param_name, bool developer=false ) const; - - /// Display parameter help. - /** - For a list of parameters. - \param param_names_list List of parameter names -- \b IN. - \param developer Bool to request developer help (defaut=false) -- \b IN. - */ - void help ( const std::list<std::string> & param_names_list , bool developer=false) const; - - /// Reset. - void reset ( void ) { init(); } - - /// Read parameters from a file. 1/2 - /** - \param param_file Name of the parameters file -- \b IN. - */ - void read ( const std::string & param_file ); - - /// Read parameters from a Parameter_Entries 2/2 - /** - \param entries -- \b IN. - */ - void read ( const NOMAD::Parameter_Entries & entries ); - - - /// Check the parameters. - /** - \param remove_history_file A boolean equal to \c true if the history file - has to be deleted - -- \b IN -- \b optional (default = \c true). - \param remove_solution_file A boolean equal to \c true if the solution file - has to be deleted - -- \b IN -- \b optional (default = \c true). - \param remove_stats_file A boolean equal to \c true if the stats file - has to be deleted - -- \b IN -- \b optional (default = \c true). - */ - void check ( bool remove_history_file = true , - bool remove_solution_file = true , - bool remove_stats_file = true ); - - /// Force the check flag to be satisfied. - /** - This advanced function should be used with care. - */ - void force_check_flag ( void ) { _to_be_checked = false; } - - /// Display. - /** - \param out The NOMAD::Display object -- \b IN. - */ - void display ( const NOMAD::Display & out ) const; - - /// Display. - /** - Uses \c this->_out as NOMAD::Display object. - */ - void display ( void ) const { display ( _out ); } - - /*--------------------------------------------------------------*/ - /* Attributes and methods listed by categories */ - /*--------------------------------------------------------------*/ - - // Algorithm and miscellaneous parameters: - // --------------------------------------- - private: - std::string _problem_dir; ///< Problem directory. - std::string _tmp_dir; ///< Temporary directory. - int _seed; ///< Seed. - int _max_eval; ///< Maximum number of evaluations. - int _max_bb_eval; ///< Maximum number of blackbox evaluations. - - std::list<std::string> _display_stats; ///< Stats keywords for \c DISPLAY_STATS. - bool _display_all_eval; ///< Parameter \c DISPLAY_ALL_EVAL - - /// Equal to \c true if \c _max_bb_eval has been entered. - bool _max_bbe_decided; - - /// Maximum number of simulated evaluations. - int _max_sim_bb_eval; - - int _max_time; ///< Maximum time. - int _max_iterations; ///< Maximum number of iterations. - int _max_cons_failed_it; ///< Maximum number of consecutive failed iterations. - float _max_cache_memory; ///< Maximum cache memory. - bool _stop_if_feasible; ///< Stop if a feasible solution is found. - NOMAD::Point _f_target; ///< Target for the objective function. - NOMAD::Double _stat_sum_target; ///< Target for the STAT_SUM stat. - NOMAD::Double _L_curve_target; ///< Target for the L_CURVE criterion. - bool _snap_to_bounds; ///< Snap or not the points to the bounds. - bool _user_calls_enabled; ///< Enable calls to user functions. - bool _asynchronous; ///< Asynchronous version for parallelism. - - public: - - /// Test to know if parameters have to be checked. - /** - \return A boolean equal to \c true if parameters have - to be checked with function NOMAD::Parameters::check(). - */ - bool to_be_checked ( void ) const { return _to_be_checked; } - - /// Access to the display degrees. - /** - - Use NOMAD::Parameters::out().get_X_dd() - to access other specific display degrees. - - \see Display.hpp. - \param d The 4 display degrees as a string -- \b OUT. - */ - void get_display_degree ( std::string & d ) const; - - /// Access to the display degree. - /** - \return General display degree. - */ - int get_display_degree ( void ) const; - - /// Access to display. - /** - \return The NOMAD::Display object. - */ - const NOMAD::Display & out ( void ) const; - - /// Access to the \c DISPLAY_STATS parameter. - /** - \return The \c DISPLAY_STATS parameter. - */ - const std::list<std::string> & get_display_stats ( void ) const; - - /// Access to the \c DISPLAY_ALL_EVAL parameter. - /** - \return The \c DISPLAY_ALL_EVAL parameter. - */ - bool get_display_all_eval ( void ) const; - - /// Access to the \c POINT_DISPLAY_LIMIT parameter. - /** - \return The \c POINT_DISPLAY_LIMIT parameter. - */ - int get_point_display_limit ( void ) const; - - /// Access to the seed. - /** - \return The seed. - */ - int get_seed ( void ) const; - - /// Access to the maximum number of evaluations. - /** - \return The maximum number of evaluations. - */ - int get_max_eval ( void ) const; - - /// Access to the \c MAX_SIM_BB_EVAL parameter. - /** - \return The \c MAX_SIM_BB_EVAL parameter. - */ - int get_max_sim_bb_eval ( void ) const; - - /// Access to the \c MAX_BB_EVAL parameter. - /** - \return The \c MAX_BB_EVAL parameter. - */ - int get_max_bb_eval ( void ) const; - - /// Access to the \c MAX_TIME parameter. - /** - \return The \c MAX_TIME parameter. - */ - int get_max_time ( void ) const; - - /// Access to the maximum number of iterations. - /** - \return The maximum number of iterations. - */ - int get_max_iterations ( void ) const; - - /// Access to the maximum number of consecutive failed iterations. - /** - \return The maximum number of consecutive failed iterations. - */ - int get_max_consecutive_failed_iterations ( void ) const; - - /// Access to the maximum cache memory. - /** - \return The maximum cache memory. - */ - float get_max_cache_memory ( void ) const; - - /// Access to the \c STOP_IF_FEASIBLE parameter. - /** - \return The \c STOP_IF_FEASIBLE parameter. - */ - bool get_stop_if_feasible ( void ) const; - - /// Access to the \c F_TARGET parameter. - /** - \return The \c F_TARGET parameter. - */ - const NOMAD::Point & get_f_target ( void ) const; - - /// Access to the \c STAT_SUM_TARGET parameter. - /** - \return The \c STAT_SUM_TARGET parameter. - */ - const NOMAD::Double & get_stat_sum_target ( void ) const; - - /// Access to the \c L_CURVE_TARGET parameter. - /** - \return The \c L_CURVE_TARGET parameter. - */ - const NOMAD::Double & get_L_curve_target ( void ) const; - - /// Access to the problem directory. - /** - \return The problem directory. - */ - const std::string & get_problem_dir ( void ) const; - - /// Access to the temporary directory. - /** - \return The temporary directory. - */ - const std::string & get_tmp_dir ( void ) const; - - /// Access to the \c SNAP_TO_BOUNDS parameter. - /** - \return The \c SNAP_TO_BOUNDS parameter. - */ - bool get_snap_to_bounds ( void ) const; - - /// Access to the \c USER_CALLS_ENABLED parameter. - /** - \return The \c USER_CALLS_ENABLED parameter. - */ - bool get_user_calls_enabled ( void ) const; - - /// Access to the \c ASYNCHRONOUS parameter. - /** - \return The \c ASYNCHRONOUS parameter. - */ - bool get_asynchronous ( void ) const; - - /// Set the \c POINT_DISPLAY_LIMIT parameter. - /** - \param dl The \c POINT_DISPLAY_LIMIT parameter -- \b IN. - */ - void set_POINT_DISPLAY_LIMIT ( int dl ); - - /// Set the \c DISPLAY_STATS parameter. - /** - - From a list of strings. - \param ds The \c DISPLAY_STATS parameter -- \b IN. - */ - void set_DISPLAY_STATS ( const std::list<std::string> & ds ); - - /// Set the \c DISPLAY_STATS parameter. - /** - - From a string. - \param ds The \c DISPLAY_STATS parameter -- \b IN. - */ - void set_DISPLAY_STATS ( const std::string & ds ); - - /// Set the \c DISPLAY_ALL_EVAL parameter. - /** - \param dae The \c DISPLAY_ALL_EVAL parameter -- \b IN. - */ - void set_DISPLAY_ALL_EVAL ( bool dae ); - - /// Set the display degree. - /** - - Accepts also NOMAD::dd_type arguments. - \param dd Display degree -- \b IN. - \return \c true if the operation succeeded. - */ - bool set_DISPLAY_DEGREE ( int dd ); - - /// Set the display degrees. - /** - - From a string with the 4 degrees. - \param dd Display degree -- \b IN. - \return \c true if the operation succeeded. - */ - bool set_DISPLAY_DEGREE ( const std::string & dd ); - - /// Set the display degrees. - /* - \param gen_dd General display degree -- \b IN. - \param search_dd Search display degree -- \b IN. - \param poll_dd Poll display degree -- \b IN. - \param iter_dd Iterative display degree -- \b IN. - */ - void set_DISPLAY_DEGREE ( int gen_dd , - int search_dd , - int poll_dd , - int iter_dd ); - - /// Set the \c OPEN_BRACE parameter. - /** - \param s The \c OPEN_BRACE parameter -- \b IN. - */ - void set_OPEN_BRACE ( const std::string & s ); - - /// Set the \c CLOSED_BRACE parameter. - /** - \param s The \c CLOSED_BRACE parameter -- \b IN. - */ - void set_CLOSED_BRACE ( const std::string & s ); - - /// Set the seed. - /** - \param seed The seed -- \b IN. - */ - void set_SEED ( int seed ); - - /// Set the \c MAX_EVAL parameter. - /** - \param me The \c MAX_EVAL parameter -- \b IN. - */ - void set_MAX_EVAL ( int me ); - - /// Set the \c MAX_SIM_BB_EVAL parameter. - /** - \param msbe The \c MAX_SIM_BB_EVAL parameter -- \b IN. - */ - void set_MAX_SIM_BB_EVAL ( int msbe ); - - /// Set the \c MAX_BB_EVAL parameter. - /** - \param bbe The \c MAX_BB_EVAL parameter -- \b IN. - */ - void set_MAX_BB_EVAL ( int bbe ); - - /// Set the \c MAX_TIME parameter. - /** - \param mt The \c MAX_TIME parameter -- \b IN. - */ - void set_MAX_TIME ( int mt ); - - /// Set the \c MAX_ITERATIONS parameter. - /** - \param mi The \c MAX_ITERATIONS parameter -- \b IN. - */ - void set_MAX_ITERATIONS ( int mi ); - - /// Set the \c MAX_CONSECUTIVE_FAILED_ITERATIONS parameter. - /** - \param mcsi The \c MAX_CONSECUTIVE_FAILED_ITERATIONS parameter -- \b IN. - */ - void set_MAX_CONSECUTIVE_FAILED_ITERATIONS ( int mcsi ); - - /// Set the \c MAX_CACHE_MEMORY parameter. - /** - \param mcm The \c MAX_CACHE_MEMORY parameter -- \b IN. - */ - void set_MAX_CACHE_MEMORY ( float mcm ); - - /// Set the \c STOP_IF_FEASIBLE parameter. - /** - \param sif The \c STOP_IF_FEASIBLE parameter -- \b IN. - */ - void set_STOP_IF_FEASIBLE ( bool sif ); - - /// Set the \c STAT_SUM_TARGET parameter. - /** - \param target The \c STAT_SUM_TARGET parameter -- \b IN. - */ - void set_STAT_SUM_TARGET ( const NOMAD::Double & target ); - - /// Set the \c L_CURVE_TARGET parameter. - /** - \param target The \c L_CURVE_TARGET parameter -- \b IN. - */ - void set_L_CURVE_TARGET ( const NOMAD::Double & target ); - - /// Set the \c PROBLEM_DIR parameter. - /** - \param dir The \c PROBLEM_DIR parameter -- \b IN. - */ - void set_PROBLEM_DIR ( const std::string & dir ); - - /// Set the \c TMP_DIR parameter. - /** - \param dir The \c TMP_DIR parameter -- \b IN. - */ - void set_TMP_DIR ( const std::string & dir ); - - /// Set the \c SNAP_TO_BOUNDS parameter. - /** - \param stb The \c SNAP_TO_BOUNDS parameter -- \b IN. - */ - void set_SNAP_TO_BOUNDS ( bool stb ); - - /// Set the \c USER_CALLS_ENABLED parameter. - /** - \param uce The \c USER_CALLS_ENABLED parameter -- \b IN. - */ - void set_USER_CALLS_ENABLED ( bool uce ); - - /// Set the \c ASYNCHRONOUS parameter. - /** - \param as The \c ASYNCHRONOUS parameter -- \b IN. - */ - void set_ASYNCHRONOUS ( bool as ); - - /// Set the \c F_TARGET parameter. - /** - - Multi-objective version. - \param target The \c F_TARGET parameter -- \b IN. - */ - void set_F_TARGET ( const NOMAD::Point & target ); - - /// Set the F_TARGET \c parameter. - /** - - Single-objective version. - \param target The \c F_TARGET parameter -- \b IN. - */ - void set_F_TARGET ( const NOMAD::Double & target ); - - /// Reset the \c F_TARGET parameter. - void reset_f_target ( void ) { _f_target.clear(); } - - /// Set the \c EPSILON parameter. - /** - \param eps The \c EPSILON parameter -- \b IN. - */ - void set_EPSILON ( const NOMAD::Double & eps ) - { - NOMAD::Double::set_epsilon ( eps.value() ); - } - - /// Set the \c UNDEF_STR parameter. - /** - \param undef_str The \c UNDEF_STR parameter -- \b IN. - */ - void set_UNDEF_STR ( const std::string & undef_str ) - { - NOMAD::Double::set_undef_str ( undef_str ); - } - - /// Set the \c INF_STR parameter. + /// Display a NOMAD::Parameters object. /** - \param inf_str The \c INF_STR parameter -- \b IN. - */ - void set_INF_STR ( const std::string & inf_str ) - { - NOMAD::Double::set_inf_str ( inf_str ); - } - - /// Access to the \c EPSILON parameter. - /** - \return The \c EPSILON parameter. - */ - const NOMAD::Double get_epsilon ( void ) const - { - return NOMAD::Double::get_epsilon(); - } - - /// Access to the \c UNDEF_STR parameter. - /** - \return The \c UNDEF_STR parameter. - */ - const std::string get_undef_str ( void ) const - { - return NOMAD::Double::get_undef_str(); - } - - /// Access to the \c INF_STR parameter. - /** - \return The \c INF_STR parameter. - */ - const std::string get_inf_str ( void ) const + \param out The NOMAD::Display object -- \b IN. + \param p The NOMAD::Parameters object to be displayed -- \b IN. + \return The NOMAD::Display object. + */ + inline const NOMAD::Display & operator << ( const NOMAD::Display & out , + const NOMAD::Parameters & p ) { - return NOMAD::Double::get_inf_str(); + p.display ( out ); + return out; } - - // Output files: - // ------------- - private: - - /// List of stats for parameter \c STATS_FILE. - std::list<std::string> _stats_file; - - /// Name of the stats file. - std::string _stats_file_name; - - /// Parameter \c ADD_SEED_TO_FILE_NAME. - bool _add_seed_to_file_names; - - std::string _solution_file; ///< Parameter \c SOLUTION_FILE. - std::string _history_file; ///< Parameter \c HISTORY_FILE. - std::string _cache_file; ///< Parameter \c CACHE_FILE. - int _cache_save_period; ///< Parameter \c CACHE_SAVE_PERIOD. - - public: - - /// Access to the list of stats for the \c STATS_FILE parameter. - /** - \return The list of stats. - */ - const std::list<std::string> & get_stats_file ( void ) const; - - /// Access to the name of the stats file. - /** - \return The name of the stats file. - */ - const std::string & get_stats_file_name ( void ) const; - - /// Access to the \c SOLUTION_FILE parameter. - /** - \return The \c SOLUTION_FILE parameter. - */ - const std::string & get_solution_file ( void ) const; - - /// Access to the \c HISTORY_FILE parameter. - /** - \return The \c HISTORY_FILE parameter. - */ - const std::string & get_history_file ( void ) const; - - /// Access to the \c CACHE_FILE parameter. - /** - \return The \c CACHE_FILE parameter. - */ - const std::string & get_cache_file ( void ) const; - - /// Access to the \c CACHE_SAVE_PERIOD parameter. - /** - \return The \c CACHE_SAVE_PERIOD parameter. - */ - int get_cache_save_period ( void ) const; - - /// Access to the \c ADD_SEED_TO_FILE_NAME parameter. - /** - \return The \c ADD_SEED_TO_FILE_NAME parameter. - */ - bool get_add_seed_to_file_names ( void ) const; - - /// Reset the \c STATS_FILE parameter. - void reset_stats_file ( void ); - - /// Set the \c STATS_FILE parameter. - /** - \param file_name Name of the stats file -- \b IN. - \param stats List of stats -- \b IN. - */ - void set_STATS_FILE ( const std::string & file_name , - const std::list<std::string> & stats ); - - /// Set the \c STATS_FILE parameter. - /** - \param file_name Name of the stats file -- \b IN. - \param stats The stats -- \b IN. - */ - void set_STATS_FILE ( const std::string & file_name , - const std::string & stats ); - - /// Set the \c ADD_SEED_TO_FILE_NAME parameter. - /** - \param astfn The \c ADD_SEED_TO_FILE_NAME parameter -- \b IN. - */ - void set_ADD_SEED_TO_FILE_NAMES ( bool astfn ); - - /// Set the \c SOLUTION_FILE parameter. - /** - \param sf The \c SOLUTION_FILE parameter -- \b IN. - */ - void set_SOLUTION_FILE ( const std::string & sf ); - - /// Set the \c HISTORY_FILE parameter. - /** - \param hf The \c HISTORY_FILE parameter -- \b IN. - */ - void set_HISTORY_FILE ( const std::string & hf ); - - /// Set the \c CACHE_FILE parameter. - /** - \param cf The \c CACHE_FILE parameter -- \b IN. - */ - void set_CACHE_FILE ( const std::string & cf ); - - /// Set the \c CACHE_SAVE_PERIOD parameter. - /** - \param csp The \c CACHE_SAVE_PERIOD parameter -- \b IN. - */ - void set_CACHE_SAVE_PERIOD ( int csp ); - - // Searches: - // --------- - private: - - /// Speculative search (MADS search). - bool _speculative_search; - - bool _disable_models; ///< Models disablement - - NOMAD::model_params_type _model_params; ///< Models parameters. - - // VNS search parameters: - bool _VNS_search; ///< Flag for the VNS search. - NOMAD::Double _VNS_trigger; ///< VNS trigger. - - // Latin-Hypercube (LH) search: - int _LH_search_p0; ///< Number of initial LH search points. - int _LH_search_pi; ///< LH search points at each iteration. - bool _opportunistic_LH; ///< Parameter \c OPPORTUNISTIC_LH. - bool _opp_LH_is_defined; ///< A boolean equal to \c true if a LH has been defined. - - bool _cache_search; ///< Cache search. - bool _opportunistic_cache_search; ///< Parameter \c OPPORTUNISTIC_CACHE_SEARCH. - - /// A boolean equal to \c true if \c OPPORTUNISTIC_CACHE_SEARCH has been defined. - bool _opp_CS_is_defined; - - public: - - /// Access to the \c SPECULATIVE_SEARCH parameter. - /** - \return The \c SPECULATIVE_SEARCH parameter. - */ - bool get_speculative_search ( void ) const; - - /// Check if a model search is specified. - /** - \return A boolean equal to \c true if a model search is defined. - */ - bool has_model_search ( void ) const; - - /// Access to the \c MODEL_SEARCH parameter. - /** - \param i Index of the model search (1 or 2) -- \b IN. - \return The \c MODEL_SEARCH parameter. - */ - NOMAD::model_type get_model_search ( int i ) const; - - /// Access to the \c MODEL_SEARCH_OPTIMISTIC parameter. - /** - \return The \c MODEL_SEARCH_OPTIMISTIC parameter. - */ - bool get_model_search_optimistic ( void ) const; - - /// Access to the \c MODEL_SEARCH_PROJ_TO_MESH parameter. - /** - \return The \c MODEL_SEARCH_PROJ_TO_MESH parameter. - */ - bool get_model_search_proj_to_mesh ( void ) const; - - /// Access to the \c MODEL_QUAD_RADIUS_FACTOR parameter. - /** - \return The \c MODEL_QUAD_RADIUS_FACTOR parameter. - */ - const NOMAD::Double & get_model_quad_radius_factor ( void ) const; - - /// Access to the \c MODEL_NP1_QUAD_EPSILON parameter. - /** - \return The \c MODEL_NP1_QUAD_EPSILON parameter. - */ - const NOMAD::Double & get_model_np1_quad_epsilon ( void ) const; - - - /// Access to the \c MODEL_QUAD_USE_WP parameter. - /** - \return The \c MODEL_QUAD_USE_WP parameter. - */ - bool get_model_quad_use_WP ( void ) const; - - /// Access to the \c MODEL_QUAD_MAX_Y_SIZE parameter. - /** - \return The \c MODEL_QUAD_MAX_Y_SIZE parameter. - */ - int get_model_quad_max_Y_size ( void ) const; - - /// Access to the \c MODEL_QUAD_MIN_Y_SIZE parameter. - /** - \return The \c MODEL_QUAD_MIN_Y_SIZE parameter. - */ - int get_model_quad_min_Y_size ( void ) const; - - /// Access to the \c MODEL_TGP_MODE parameter. - /** - \return The \c MODEL_TGP_MODE parameter. - */ - NOMAD::TGP_mode_type get_model_tgp_mode ( void ) const; - - /// Access to the \c MODEL_TGP_REUSE_MODEL parameter. - /** - \return The \c MODEL_TGP_REUSE_MODEL parameter. - */ - bool get_model_tgp_reuse_model ( void ) const; - - /// Access to the \c MODEL_SEARCH_MAX_TRIAL_PTS parameter. - /** - \return The \c MODEL_SEARCH_MAX_TRIAL_PTS parameter. - */ - int get_model_search_max_trial_pts ( void ) const; - - /// Access to the \c MODEL_EVAL_SORT parameter. - /** - \return The \c MODEL_EVAL_SORT parameter. - */ - NOMAD::model_type get_model_eval_sort ( void ) const; - - /// Access to the \c MODEL_EVAL_SORT_CAUTIOUS parameter. - /** - \return The \c MODEL_EVAL_SORT_CAUTIOUS parameter. - */ - bool get_model_eval_sort_cautious ( void ) const; - - - /// Access to all the models parameters. - /** - \param mp The models parameters -- \b OUT. - */ - void get_model_parameters ( NOMAD::model_params_type & mp ) const; - - /// Access to the \c VNS_SEARCH parameter. - /** - \return The \c VNS_SEARCH parameter. - */ - bool get_VNS_search ( void ) const; - - /// Access to the VNS trigger. - /** - \return The VNS trigger. - */ - const NOMAD::Double & get_VNS_trigger ( void ) const; - - /// Access to the number of initial LH search points. - /** - \return The number of initial LH search points. - */ - int get_LH_search_p0 ( void ) const; - - /// Access to the number of LH search points at each iteration. - /** - \return The number of LH search points at each iteration. - */ - int get_LH_search_pi ( void ) const; - - /// Access to the \c OPPORTUNISTIC_LH parameter. - /** - \return The \c OPPORTUNISTIC_LH parameter. - */ - bool get_opportunistic_LH ( void ) const; - - /// Access to the \c CACHE_SEARCH parameter. - /** - \return The \c CACHE_SEARCH parameter. - */ - bool get_cache_search ( void ) const; - - /// Access to the \c OPPORTUNISTIC_CACHE_SEARCH parameter. - /** - \return The \c OPPORTUNISTIC_CACHE_SEARCH parameter. - */ - bool get_opportunistic_cache_search ( void ) const; - - /// Set the \c SPECULATIVE_SEARCH parameter. - /** - \param ss The \c SPECULATIVE_SEARCH parameter -- \b IN. - */ - void set_SPECULATIVE_SEARCH ( bool ss ); - - - /// Disable use of models. - /** - */ - void set_DISABLE_MODELS ( void ); - - - /// Set all the models parameters. - /** - \param mp The models parameters -- \b IN. - */ - void set_model_parameters ( const NOMAD::model_params_type & mp ); - - /// Set the \c MODEL_SEARCH parameter (1/3). - /** - \param i Index of the model search (1 or 2) -- \b IN. - \param ms The \c MODEL_SEARCH parameter -- \b IN. - */ - void set_MODEL_SEARCH ( int i , NOMAD::model_type ms ); - - /// Set the \c MODEL_SEARCH parameter (2/3). - /** - \param ms The \c MODEL_SEARCH parameter -- \b IN. - */ - void set_MODEL_SEARCH ( bool ms ); - - /// Set the \c MODEL_SEARCH parameter (3/3). - /** - \param mod_type The \c MODEL_SEARCH parameter -- \b IN. - */ - void set_MODEL_SEARCH ( NOMAD::model_type mod_type ); - - /// Set the \c MODEL_SEARCH_OPTIMISTIC parameter. - /** - \param mso The \c MODEL_SEARCH_OPTIMISTIC parameter -- \b IN. - */ - void set_MODEL_SEARCH_OPTIMISTIC ( bool mso ); - - /// Set the \c MODEL_SEARCH_PROJ_TO_MESH parameter. - /** - \param ptm The \c MODEL_SEARCH_PROJ_TO_MESH parameter -- \b IN. - */ - void set_MODEL_SEARCH_PROJ_TO_MESH ( bool ptm ); - - /// Set the \c MODEL_QUAD_RADIUS_FACTOR parameter. - /** - \param r The \c MODEL_QUAD_RADIUS_FACTOR parameter -- \b IN. - */ - void set_MODEL_QUAD_RADIUS_FACTOR ( const NOMAD::Double & r ); - - /// Set the \c MODEL_QUAD_USE_WP parameter. - /** - \param uwp The \c MODEL_QUAD_USE_WP parameter -- \b IN. - */ - void set_MODEL_QUAD_USE_WP ( bool uwp ); - - /// Set the \c MODEL_QUAD_MAX_Y_SIZE parameter. - /** - \param s The \c MODEL_QUAD_MAX_Y_SIZE parameter -- \b IN. - */ - void set_MODEL_QUAD_MAX_Y_SIZE ( int s ); - - /// Set the \c MODEL_QUAD_MIN_Y_SIZE parameter. - /** - \param s The \c MODEL_QUAD_MIN_Y_SIZE parameter -- \b IN. - */ - void set_MODEL_QUAD_MIN_Y_SIZE ( int s ); - - /// Set the \c MODEL_NP1_QUAD_EPSILON parameter. - /** - \param r The \c MODEL_NP1_QUAD_EPSILON parameter -- \b IN. - */ - void set_MODEL_NP1_QUAD_EPSILON ( const NOMAD::Double & r ); - - /// Set the \c MODEL_TGP_MODE parameter. - /** - \param m The \c MODEL_TGP_MODE parameter -- \b IN. - */ - void set_MODEL_TGP_MODE ( NOMAD::TGP_mode_type m ); - - /// Set the \c MODEL_TGP_REUSE_MODEL parameter. - /** - \param rm The \c MODEL_TGP_REUSE_MODEL parameter -- \b IN. - */ - void set_MODEL_TGP_REUSE_MODEL ( bool rm ); - - /// Set the \c MODEL_SEARCH_MAX_TRIAL_PTS parameter. - /** - \param s The \c MODEL_SEARCH_MAX_TRIAL_PTS parameter -- \b IN. - */ - void set_MODEL_SEARCH_MAX_TRIAL_PTS ( int s ); - - /// Set the \c MODEL_EVAL_SORT parameter (1/2). - /** - \param mes The \c MODEL_EVAL_SORT parameter -- \b IN. - */ - void set_MODEL_EVAL_SORT ( NOMAD::model_type mes ); - - /// Set the \c MODEL_EVAL_SORT parameter (2/2). - /** - \param mes The \c MODEL_EVAL_SORT parameter -- \b IN. - */ - void set_MODEL_EVAL_SORT ( bool mes ); - - - /// Set the \c MODEL_EVAL_SORT_CAUTIOUS parameter. - /** - \param mesc The \c MODEL_EVAL_SORT_CAUTIOUS parameter -- \b IN. - */ - void set_MODEL_EVAL_SORT_CAUTIOUS ( bool mesc ); - - /// Set the \c VNS_SEARCH parameter. - /** - \param vns The \c VNS_SEARCH parameter -- \b IN. - */ - void set_VNS_SEARCH ( bool vns ); - - /// Set the \c VNS_SEARCH parameter. - /** - \param trigger The VNS trigger -- \b IN. - */ - void set_VNS_SEARCH ( const NOMAD::Double & trigger ); - - /// Set the \c LH_SEARCH parameter. - /** - \param p0 Number of initial LH search points -- \b IN. - \param pi LH search points at each iteration -- \b IN. - */ - void set_LH_SEARCH ( int p0 , int pi ); - - /// Set the \c OPPORTUNISTIC_LH parameter. - /** - \param olh The \c OPPORTUNISTIC_LH parameter -- \b IN. - */ - void set_OPPORTUNISTIC_LH ( bool olh ); - - /// Set the \c CACHE_SEARCH parameter. - /** - \param cs The \c CACHE_SEARCH parameter -- \b IN. - */ - void set_CACHE_SEARCH ( bool cs ); - - /// Set the \c OPPORTUNISTIC_CACHE_SEARCH parameter. - /** - \param ocs The \c OPPORTUNISTIC_CACHE_SEARCH parameter -- \b IN. - */ - void set_OPPORTUNISTIC_CACHE_SEARCH ( bool ocs ); - - // Mesh: - // ----- - private: - - NOMAD::Double _mesh_update_basis; ///< Mesh update basis (tau). - int _mesh_coarsening_exponent; ///< Mesh coarsening exponent. - int _mesh_refining_exponent; ///< Mesh refining exponent. - int _initial_mesh_index; ///< Initial mesh index (ell_0). - int _max_mesh_index; ///< Final mesh index (ell_max). - - NOMAD::Point _initial_mesh_size; ///< Initial (absolute) mesh size (Delta^m_0). - NOMAD::Point _min_mesh_size; ///< Minimal (absolute) mesh size (Delta^m_min). - NOMAD::Point _min_poll_size; ///< Minimal (absolute) poll size (Delta^p_min). - - bool _min_poll_size_defined; ///< \c true if _min_poll_size is user-defined. - - public: - - /// Access to the \c MESH_UPDATE_BASIS parameter. - /** - \return The \c MESH_UPDATE_BASIS parameter. - */ - const NOMAD::Double & get_mesh_update_basis ( void ) const; - - /// Access to the \c MESH_COARSENING_EXPONENT parameter. - /** - \return The \c MESH_COARSENING_EXPONENT parameter. - */ - int get_mesh_coarsening_exponent ( void ) const; - - /// Access to the \c MESH_REFINING_EXPONENT parameter. - /** - \return The \c MESH_REFINING_EXPONENT parameter. - */ - int get_mesh_refining_exponent ( void ) const; - - /// Access to the \c INITIAL_MESH_INDEX parameter. - /** - \return The \c INITIAL_MESH_INDEX parameter. - */ - int get_initial_mesh_index ( void ) const; - - /// Access to the \c MAX_MESH_INDEX parameter. - /** - \return The \c MAX_MESH_INDEX parameter. - */ - int get_max_mesh_index ( void ) const; - - /// Access to the \c INITIAL_MESH_SIZE parameter. - /** - \return The \c INITIAL_MESH_SIZE parameter. - */ - const NOMAD::Point & get_initial_mesh_size ( void ) const; - - /// Access to the \c MIN_MESH_SIZE parameter. - /** - \return The \c MIN_MESH_SIZE parameter. - */ - const NOMAD::Point & get_min_mesh_size ( void ) const; - - /// Access to the \c MIN_POLL_SIZE parameter. - /** - \return The \c MIN_POLL_SIZE parameter. - */ - const NOMAD::Point & get_min_poll_size ( void ) const; - - /// Access to \c _min_poll_size_defined. - /** - \return A boolean equal to \c true if the \c MIN_POLL_SIZE parameter - has been user-defined. - */ - bool get_min_poll_size_defined ( void ) const; - - /// Set the \c MAX_MESH_INDEX parameter. - /** - \param lmax The \c MAX_MESH_INDEX parameter -- \b IN. - */ - void set_MAX_MESH_INDEX ( int lmax ); - - /// Set the \c MESH_UPDATE_BASIS parameter. - /** - \param tau The \c MESH_UPDATE_BASIS parameter -- \b IN. - */ - void set_MESH_UPDATE_BASIS ( const NOMAD::Double & tau ); - - /// Set the \c INITIAL_MESH_INDEX parameter. - /** - \param ell_0 The \c INITIAL_MESH_INDEX parameter -- \b IN. - */ - void set_INITIAL_MESH_INDEX ( int ell_0 ); - - /// Set the \c MESH_REFINING_EXPONENT parameter. - /** - \param mre The \c MESH_REFINING_EXPONENT parameter -- \b IN. - */ - void set_MESH_REFINING_EXPONENT ( int mre ); - - /// Set the \c MESH_COARSENING_EXPONENT parameter. - /** - \param mce The \c MESH_COARSENING_EXPONENT parameter -- \b IN. - */ - void set_MESH_COARSENING_EXPONENT ( int mce ); - - /// Set the \c MIN_MESH_SIZE parameter. - /** - \param mms Minimum mesh size -- \b IN. - \param relative Indicated as a relative value - -- \b IN -- \b optional (default = \c false). - */ - void set_MIN_MESH_SIZE ( const NOMAD::Double & mms , bool relative = false ); - - /// Set the \c MIN_MESH_SIZE parameter. - /** - \param index Index of a variable -- \b IN. - \param mms Minimum mesh size -- \b IN. - \param relative Indicated as a relative value - -- \b IN -- \b optional (default = \c false). - */ - void set_MIN_MESH_SIZE ( int index , - const NOMAD::Double & mms , - bool relative = false ); - - /// Set the \c MIN_MESH_SIZE parameter. - /** - \param mms Minimum mesh size -- \b IN. - \param relative Indicated as relative values - -- \b IN -- \b optional (default = \c false). - */ - void set_MIN_MESH_SIZE ( const NOMAD::Point & mms , bool relative = false ); - - /// Set the \c MIN_POLL_SIZE parameter. - /** - \param mps Minimum poll size -- \b IN. - \param relative Indicated as a relative value - -- \b IN -- \b optional (default = \c false). - */ - void set_MIN_POLL_SIZE ( const NOMAD::Double & mps , bool relative = false ); - - /// Set the \c MIN_POLL_SIZE parameter. - /** - \param index Index of a variable -- \b IN. - \param mps Minimum poll size -- \b IN. - \param relative Indicated as a relative value - -- \b IN -- \b optional (default = \c false). - */ - void set_MIN_POLL_SIZE ( int index , - const NOMAD::Double & mps , - bool relative = false ); - - /// Set the \c MIN_POLL_SIZE parameter. - /** - \param mps Minimum poll size -- \b IN. - \param relative Indicated as relative values - -- \b IN -- \b optional (default = \c false). - */ - void set_MIN_POLL_SIZE ( const NOMAD::Point & mps , bool relative = false ); - - /// Set the \c INITIAL_MESH_SIZE parameter. - /** - \param ims Initial mesh size -- \b IN. - \param relative Indicated as a relative value - -- \b IN -- \b optional (default = \c false). - */ - void set_INITIAL_MESH_SIZE ( const NOMAD::Double & ims , bool relative = false ); - - /// Set the \c INITIAL_MESH_SIZE parameter. - /** - \param index Index of a variable -- \b IN. - \param ims Initial mesh size -- \b IN. - \param relative Indicated as a relative value - -- \b IN -- \b optional (default = \c false). - */ - void set_INITIAL_MESH_SIZE ( int index , - const NOMAD::Double & ims , - bool relative = false ); - - /// Set the \c INITIAL_MESH_SIZE parameter. - /** - \param ims Initial mesh size -- \b IN. - \param relative Indicated as relative values - -- \b IN -- \b optional (default = \c false). - */ - void set_INITIAL_MESH_SIZE ( const NOMAD::Point & ims , bool relative = false ); - - // Directions: - // ----------- - private: - - /// Types of poll directions. - std::set<NOMAD::direction_type> _direction_types; - - /// Types of directions for the secondary poll. - std::set<NOMAD::direction_type> _sec_poll_dir_types; - - - /// Halton seed for Ortho-MADS directions. - /** - If the default value of \c -1 is left, - the Halton seed is decided by NOMAD::Directions. - */ - int _halton_seed; - - /// Change direction types to prevent using models for finding the (n+1)th direction - /// Apply if ORTHO N+1 QUAD -> ORTHO N+1 NEG. - void set_DIRECTION_TYPE_NO_MODEL ( void ); - - - public: - - /// Access to the list of poll direction types. - /** - \return The list of poll direction types. - */ - const std::set<NOMAD::direction_type> & get_direction_types ( void ) const; - - /// Access to the list of secondary poll direction types. - /** - \return The list of secondary poll direction types. - */ - const std::set<NOMAD::direction_type> & get_sec_poll_dir_types ( void ) const; - - - /// Check if there are Ortho-MADS directions. - /** - \return A boolean equal to \c true if there is at least one - Ortho-MADS direction in the list of poll directions - or in the list of secondary poll directions. - */ - bool has_orthomads_directions ( void ) const; - - - /// Check if a direction type that required dynamic completion for the (n+1)th direction. - /** - \return true if a dynamic completion is required. - */ - bool has_dynamic_direction(void) const; - - - - /// Access to the Halton seed. - /** - \return The Halton seed. - */ - int get_halton_seed ( void ) const; - - /// Reset the directions. - /** - \param halton_seed Halton seed -- \b IN. - */ - void reset_directions ( int halton_seed ); - - /// Add a new direction type. - /** - \param dt The new direction type -- \b IN. - */ - void set_DIRECTION_TYPE ( NOMAD::direction_type dt ); - - /// Add a set of new direction types. - /** - \param dt The set of new direction types -- \b IN. - */ - void set_DIRECTION_TYPE ( const std::set<NOMAD::direction_type> & dt ); - - - /// Add a new direction type for the secondary poll. - /** - \param dt The new direction type -- \b IN. - */ - void set_SEC_POLL_DIR_TYPE ( NOMAD::direction_type dt ); - - /// Add a set of new direction types for the secondary poll. - /** - \param dt The set of new direction types -- \b IN. - */ - void set_SEC_POLL_DIR_TYPE ( const std::set<NOMAD::direction_type> & dt ); - - /// Set the Halton seed. - /** - \param hs The Halton seed -- \b IN. - */ - void set_HALTON_SEED ( int hs ); - - - /// Enables use of quad model to determine prospect direction - /// for Ortho n+1 direction type - /** - \param qmpd boolean -- \b IN. - */ - void set_QUAD_MODEL_PROSPECT_DIR ( bool qmpd ) ; - - // Starting point(s): - // ------------------ - private: - - std::vector<NOMAD::Point *> _x0s; ///< List of starting points. - std::string _x0_cache_file; ///< Cache file containing starting points. - - public: - - /// Add a new point in the list of starting points. - /** - \param x0 The new point -- \b IN. - */ - void set_X0 ( const NOMAD::Point & x0 ); - - /// Indicate a cache file containing starting points. - /** - \param file_name Name of the cache file -- \b IN. - */ - void set_X0 ( const std::string & file_name ); - - /// Reset all string points. - void reset_X0 ( void ); - - /// Access to the list of starting points. - /** - \return The list of starting points. - */ - const std::vector<NOMAD::Point *> & get_x0s ( void ) const; - - /// Access to the name of a cache file containing starting points. - /** - \return The file name. - */ - const std::string & get_x0_cache_file ( void ) const; - - // Signature: standard or extern (only one is != NULL): - // ---------------------------------------------------- - private: - - /// Standard signature. - /** - Created and deleted by the Parameters class. - */ - NOMAD::Signature * _std_signature; - - /// Extern signature. - /** - Created and deleted outside the class. - */ - NOMAD::Signature * _extern_signature; - - public: - - /// Access to the signature. - /** - \return The one non-NULL signature. - */ - NOMAD::Signature * get_signature ( void ) const; - - /// Set a new extern signature. - /** - Deletes the standard signature. - \param s A pointer to the extern signature -- \b IN. - */ - void set_EXTERN_SIGNATURE ( NOMAD::Signature * s ); - - // Dimension: - // ---------- - private: - - /// Dimension. - /** - - Number of variables. - - Parameter \c DIMENSION. - */ - int _dimension; - - public: - - /// Access to the dimension. - /** - \return The dimension. - */ - int get_dimension ( void ) const; - - /// Set the dimension. - /** - \param n The dimension -- \b IN. - \return \c true if the operation succeeded. - */ - bool set_DIMENSION ( int n ); - - // Fixed variables: - // ---------------- - private: - - /// Fixed variables. - /** - - This point is of dimension \c n (parameter \c DIMENSION). - - Undefined values correspond to free variables. - */ - NOMAD::Point _fixed_variables; - - /// Number of free variables. - int _nb_free_variables; - - public: - - /// Access to the number of free variables. - /** - \return The number of free variables. - */ - int get_nb_free_variables ( void ) const; - - /// Access to the fixed variables. - /** - \return The fixed variables. - */ - const NOMAD::Point & get_fixed_variable ( void ) const - { - return get_fixed_variables(); - } - - /// Access to the fixed variables. - /** - \return The fixed variables. - */ - const NOMAD::Point & get_fixed_variables ( void ) const; - - /// Test if a variable is fixed. - /** - \param i Index of the variable -- \b IN. - \return A boolean equal to \c true if the variable \c i is fixed. - */ - bool variable_is_fixed ( int i ) const; - - /// Reset the fixed variables. - /** - This frees all the variables. - */ - void reset_fixed_variables ( void ); - - /// Fix one variable. - /** - \param i Index of the variable -- \b IN. - \param value Value of the fixed variable -- \b IN. - */ - void set_FIXED_VARIABLE ( int i , const NOMAD::Double & value ); - - /// Fix one variable. - /** - The value of the variable is based on the starting point. - \param i Index of the variable -- \b IN. - */ - void set_FIXED_VARIABLE ( int i ); - - /// Fix a series of variables. - /** - \param fv The fixed variables; This point is of dimension \c n; - free variables correspond to undefined values -- \b IN. - */ - void set_FIXED_VARIABLE ( const NOMAD::Point & fv ); - - /// Free a variable. - /** - \param i Index of the variable -- \b IN. - */ - void set_FREE_VARIABLE ( int i ) { set_FIXED_VARIABLE ( i , NOMAD::Double() ); } - - // Periodic variables: - // ------------------- - - /// Periodic variables. - /** - - This vector is of size \c n. - - \c _periodic_variables[i] is equal to \c true if - the variable \c i is periodic. - */ - std::vector<bool> _periodic_variables; - - /// Access to the periodic variables. - /** - \return The periodic variables - */ - const std::vector<bool> & get_periodic_variable ( void ) const - { - return get_periodic_variables(); - } - - /// Access to the periodic variables. - /** - \return The periodic variables - */ - const std::vector<bool> & get_periodic_variables ( void ) const; - - /// Check if there is periodic variables. - /** - \return A boolean equal to \c true if there is periodic variables. - */ - bool has_periodic_variables ( void ) const - { - return !_periodic_variables.empty(); - } - - /// Reset periodic variables. - void reset_periodic_variables ( void ); - - /// Set one variable to be periodic. - /** - \param i Index of the variable -- \b IN. - */ - void set_PERIODIC_VARIABLE ( int i ); - - /// Set a series of variables to be periodic. - /** - \param pv Vector of size \c n indicating the - periodic variables -- \b IN. - */ - void set_PERIODIC_VARIABLE ( const std::vector<bool> & pv ); - - // Categorical variables: - // ---------------------- - private: - - /// Extended poll trigger. - /** - - Must be strictly positive. - - May be relative. - */ - NOMAD::Double _extended_poll_trigger; - - /// Equal to \c true if the extended poll trigger is relative. - bool _relative_ept; - - /// Equal to \c true if the extended poll is enabled. - bool _extended_poll_enabled; - - /// Neighborhood executable for using batch mode with categorical variables. - std::string _neighbors_exe; - - public: - - /// Access to the extended poll trigger. - /** - \return The extended poll trigger. - */ - const NOMAD::Double & get_extended_poll_trigger ( void ) const; - - /// Check if the extended poll trigger is relative. - /** - \return A boolean equal to \c true if the extended poll trigger is relative. - */ - bool get_relative_ept ( void ) const; - - /// Check if the extended poll is enabled. - /** - \return A boolean equal to \c true if the extended poll is enabled. - */ - bool get_extended_poll_enabled ( void ) const; - - /// Access to the neighborhood executable. - /** - \return The neighborhood executable. - */ - const std::string & get_neighbors_exe ( void ) const; - - /// Set the extended poll trigger. - /** - \param ept The extended poll trigger -- \b IN. - \param rel A boolean equal to \c true if the extended poll - trigger is relative -- \b IN. - */ - void set_EXTENDED_POLL_TRIGGER ( const NOMAD::Double & ept , bool rel ); - - /// Enable or disable the extended poll. - /** - \param epe A boolean equal to \c true if the extended poll is enabled -- \b IN. - */ - void set_EXTENDED_POLL_ENABLED ( bool epe ); - - /// Set the neighborhood executable. - /** - \param ne The neighborhood executable. - */ - void set_NEIGHBORS_EXE ( const std::string & ne ); - - // Groups of variables: - // -------------------- - private: - - /// Groups of variables. - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> _var_groups; - - /// User groups of variables. - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> _user_var_groups; - - /// Reset a group of variables. - /** - \param g Group to reset; may be \c _var_groups or \c _user_var_groups - -- \b IN/OUT. - */ - void reset_variable_groups - ( std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & g ) const; - - public: - - /// Reset groups of variables. - void reset_variable_groups ( void ); - - /// Access to the groups of variables. - /** - \return The groups of variables. - */ - const std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & - get_variable_groups ( void ) const; - - /// Set one group of variables. - /** - Basic version. - \param var_indexes Indexes of the variables of the group -- \b IN. - \param halton_seed Halton seed - -- \b IN -- \b optional (default = \c -1). - */ - void set_VARIABLE_GROUP ( const std::set<int> & var_indexes , - int halton_seed = -1 ); - - /// Set one group of variables. - /** - Advanced version. - \param var_indexes Indexes of the variables of the group -- \b IN. - \param prim_poll_dir_types Types of the poll directions -- \b IN. - \param sec_poll_dir_types Types of the secondary poll directions -- \b IN. - \param halton_seed Halton seed -- \b IN. - */ - void set_VARIABLE_GROUP - ( const std::set<int> & var_indexes , - const std::set<NOMAD::direction_type> & prim_poll_dir_types , - const std::set<NOMAD::direction_type> & sec_poll_dir_types , - int halton_seed ); - - /// Set several groups of variables. - /** - \param vg A list of groups of variables -- \b IN. - */ - void set_VARIABLE_GROUP ( const std::list<NOMAD::Variable_Group*> & vg ); - - // Bounds and scaling: - // ------------------- - private: - - NOMAD::Point _lb; ///< Lower bounds. - NOMAD::Point _ub; ///< Upper bounds. - NOMAD::Point _scaling; ///< Scaling. - - public: - - /// Access to the lower bounds. - /** - \return The lower bounds. - */ - const NOMAD::Point & get_lb ( void ) const; - - /// Access to the upper bounds. - /** - \return The upper bounds. - */ - const NOMAD::Point & get_ub ( void ) const; - - /// Access to the lower bounds. - /** - \return The lower bounds. - */ - const NOMAD::Point & get_lower_bound ( void ) const { return get_lb(); } - - /// Access to the upper bounds. - /** - \return The upper bounds. - */ - const NOMAD::Point & get_upper_bound ( void ) const { return get_ub(); } - - /// Access to the scaling. - /** - \return The scaling. - */ - const NOMAD::Point & get_scaling ( void ) const; - - /// Reset the bounds. - void reset_bounds ( void ); - - /// Reset the scaling. - void reset_scaling ( void ); - - /// Set one lower bound. - /** - \param i Index of the variable -- \b IN. - \param lb Lower bound -- \b IN. - */ - void set_LOWER_BOUND ( int i , const NOMAD::Double & lb ); - - /// Set all lower bounds. - /** - Use undefined values for variables without bounds. - \param lb Lower bounds -- \b IN. - */ - void set_LOWER_BOUND ( const NOMAD::Point & lb ); - - /// Set one upper bound. - /** - \param i Index of the variable -- \b IN. - \param ub Upper bound -- \b IN. - */ - void set_UPPER_BOUND ( int i , const NOMAD::Double & ub ); - - /// Set all upper bounds. - /** - Use undefined values for variables without bounds. - \param ub Upper bounds -- \b IN. - */ - void set_UPPER_BOUND ( const NOMAD::Point & ub ); - - /// Set the scaling of one variable. - /** - \param i Index of the variable -- \b IN. - \param s Scaling -- \b IN. - */ - void set_SCALING ( int i , const NOMAD::Double & s ); - - /// Set the scaling for all variables. - /** - Use undefined values for variables scaling. - \param s Scaling -- \b IN. - */ - void set_SCALING ( const NOMAD::Point & s ); - - // Blackboxes (inputs and outputs): - // -------------------------------- - private: - - /// Blackbox input types. - std::vector<NOMAD::bb_input_type> _bb_input_type; - - /// Parameter \c BB_INPUT_INCLUDE_TAG. - bool _bb_input_include_tag; - - /// Parameter \c BB_INPUT_INCLUDE_SEED. - bool _bb_input_include_seed; - - /// Blackbox output types. - /** - May be modified during the algorithm (PEB constraints). - */ - mutable std::vector<NOMAD::bb_output_type> _bb_output_type; - - /// List of blackbox executables. - std::list<std::string> _bb_exe; - - /// List of objective indexes. - std::list<int> _index_obj; - - /// Index for the output \c STAT_SUM. - int _index_stat_sum; - - /// Index for the output \c STAT_AVG. - int _index_stat_avg; - - /// Index for the output \c CNT_EVAL. - /** - - \c 0 or \c 1. - - \c CNT_EVAL indicates if a blackbox evaluation has to be counted. - */ - int _index_cnt_eval; - - /// Parameter \c BB_REDIRECTION. - bool _bb_redirection; - - public: - - /// Access to the number of blackbox outputs. - /** - \return The number of blackbox outputs. - */ - int get_bb_nb_outputs ( void ) const; - - /// Access to the \c BB_INPUT_INCLUDE_TAG parameter. - /** - \return The \c BB_INPUT_INCLUDE_TAG parameter. - */ - bool get_bb_input_include_tag ( void ) const; - - /// Access to the \c BB_INPUT_INCLUDE_SEED parameter. - /** - \return The \c BB_INPUT_INCLUDE_SEED parameter. - */ - bool get_bb_input_include_seed ( void ) const; - - /// Access to the blackbox input types. - /** - \return The blackbox input types. - */ - const std::vector<NOMAD::bb_input_type> & get_bb_input_type ( void ) const; - - /// Access to the blackbox output types. - /** - \return The blackbox output types. - */ - const std::vector<NOMAD::bb_output_type> & get_bb_output_type ( void ) const; - - /// Access to the objective indexes. - /** - \return The list of objective indexes. - */ - const std::list<int> & get_index_obj ( void ) const; - - /// Access to the number of objective functions. - /** - \return The number of objective functions. - */ - int get_nb_obj ( void ) const; - - /// Check the display and file stats. - /** - \param stats The stats -- \b IN. - \return A booleam equal to \c true if the stats are valid. - */ - bool check_display_stats ( const std::list<std::string> & stats ) const; - - /// Check if there is a \c STAT_SUM output. - /** - \return A boolean equal to \c true if there a \c STAT_SUM output. - */ - bool check_stat_sum ( void ) const; - - /// Check if there is a \c STAT_AVG output. - /** - \return A boolean equal to \c true if there is a \c STAT_AVG output. - */ - bool check_stat_avg ( void ) const; - - /// Access the index of output \c CNT_EVAL output. - /** - \return Index of the \c CNT_EVAL output. - \return \c -1 if there is no \c CNT_EVAL output. - */ - int get_index_cnt_eval ( void ) const; - - /// Access the index of output \c STAT_SUM output. - /** - \return Index of the \c STAT_SUM output. - \return \c -1 if there is no \c STAT_SUM output. - */ - int get_index_stat_sum ( void ) const; - - /// Access the index of output \c STAT_AVG output. - /** - \return Index of the \c STAT_AVG output. - \return \c -1 if there is no \c STAT_AVG output. - */ - int get_index_stat_avg ( void ) const; - - /// Access to the list of blackbox executables. - /** - \return The list of blackbox executables. - */ - const std::list<std::string> & get_bb_exe ( void ) const; - - /// Access to the \c BB_REDIRECTION parameter. - /** - \return The \c BB_REDIRECTION parameter. - */ - bool get_bb_redirection ( void ) const; - - /// Set the \c BB_INPUT_INCLUDE_TAG parameter. - /** - \param bbiit The \c BB_INPUT_INCLUDE_TAG parameter -- \b IN. - */ - void set_BB_INPUT_INCLUDE_TAG ( bool bbiit ); - - /// Set the \c BB_INPUT_INCLUDE_SEED parameter. - /** - \param bbiis The \c BB_INPUT_INCLUDE_SEED parameter -- \b IN. - */ - void set_BB_INPUT_INCLUDE_SEED ( bool bbiis ); - - /// Set the blackbox input type of one variable. - /** - \param index Index of the variable -- \b IN. - \param bbit Type of the variable -- \b IN. - */ - void set_BB_INPUT_TYPE ( int index , NOMAD::bb_input_type bbit ); - - /// Set the blackbox input types of all variables. - /** - \param bbit Types of the variables -- \b IN. - */ - void set_BB_INPUT_TYPE ( const std::vector<NOMAD::bb_input_type> & bbit ); - - /// Set the blackbox input types of all variables. - /** - \param bbit Types of the variables -- \b IN. - */ - void set_BB_INPUT_TYPE ( const std::list<NOMAD::bb_input_type> & bbit ); - - /// Set the blackbox output types. - /** - \param bbot Blackbox output types -- \b IN. - */ - void set_BB_OUTPUT_TYPE ( const std::list<NOMAD::bb_output_type> & bbot ); - - /// Set the blackbox output types. - /** - \param bbot Blackbox output types -- \b IN. - */ - void set_BB_OUTPUT_TYPE ( const std::vector<NOMAD::bb_output_type> & bbot ); - - /// Set a list of blackbox executable names. - /** - Must correspond to the blackbox output types. - \param bbexe The list of blackbox executable names -- \b IN. - */ - void set_BB_EXE ( const std::list<std::string> & bbexe ); - - /// Set a list of blackbox executable names. - /** - \param m Number of blackbox outputs and size of \c bbexe -- \b IN. - \param bbexe The list of blackbox executable names -- \b IN. - */ - void set_BB_EXE ( int m , const std::string * bbexe ); - - /// Set a unique blackbox executable name. - /** - \param bbexe The blackbox executable name -- \b IN. - */ - void set_BB_EXE ( const std::string & bbexe ); - - /// Set the \c BB_REDIRECTION parameter. - /** - \param bbr The \c BB_REDIRECTION parameter -- \b IN. - */ - void set_BB_REDIRECTION ( bool bbr ); - - /// Reset the PEB statuses. - /** - Set all outputs at NOMAD::PEB_E (PEB constraint in "extreme" status) - to NOMAD::PEB_P (PEB constraint in "progressive" status). - */ - void reset_PEB_changes ( void ) const; - - /// Change constraints from PEB to PB. - /** - Set all outputs at NOMAD::PEB to NOMAD::PB - */ - void change_PEB_to_PB ( void ); - - /// Change the status of one PEB constraint. - /** - The status is changed from - NOMAD::PEB_P (PEB constraint in "progressive" status) - to NOMAD::PEB_E (PEB constraint in "extreme" status). - \param index Index of the PEB constraint. - */ - void change_PEB_constraint_status ( int index ) const; - - // Surrogates: - // ----------- - private: - - /// Surrogate executables. - /** - \c _sgte_exe[bb_exe] corresponds to the surrogate associated - with the blackbox true executable \c bb_exe. - */ - std::map<std::string,std::string> _sgte_exe; - - /// Flag equal to \c true if surrogates are used to sort evaluation points. - bool _sgte_eval_sort; - - /// Flag equal to \c true if the problem has a surrogate. - bool _has_sgte; - - /// Flag equal to \c true if NOMAD considers only surrogates. - bool _opt_only_sgte; - - /// Surrogate cost. - /** - Number of surrogate evaluations counting as one blackbox evaluation. - */ - int _sgte_cost; - - /// Maximum number of surrogate evaluations. - int _sgte_max_eval; - - /// Surrogate cache file. - std::string _sgte_cache_file; - - public: - - /// Access to the surrogate associated with a truth executable. - /** - \param bb_exe The truth executable -- \b IN. - \return The surrogate executable name. - \return An empty string if \c bb_exe has no surrogate. - */ - std::string get_sgte_exe ( const std::string & bb_exe ) const; - - /// Access to the \c SGTE_EVAL_SORT parameter. - /** - \return The \c SGTE_EVAL_SORT parameter. - */ - bool get_sgte_eval_sort ( void ) const; - - /// Access to the \c SGTE_COST parameter. - /** - \return The \c SGTE_COST parameter. - */ - int get_sgte_cost ( void ) const; - - /// Access to the \c MAX_SGTE_EVAL parameter. - /** - \return The \c MAX_SGTE_EVAL parameter. - */ - int get_max_sgte_eval ( void ) const; - - /// Access to the \c SGTE_CACHE_FILE parameter. - /** - \return The \c SGTE_CACHE_FILE parameter. - */ - const std::string & get_sgte_cache_file ( void ) const; - - /// Access to the \c HAS_SGTEparameter. - /** - \return The \c HAS_SGTEparameter. - */ - bool has_sgte ( void ) const; - - /// Access to the \c OPT_ONLY_SGTE parameter. - /** - \return The \c OPT_ONLY_SGTE parameter. - */ - bool get_opt_only_sgte ( void ) const; - - /// Check if a surrogate executable has been defined. - /** - \return A boolean equal to \c true if - a surrogate executable has been defined. - */ - bool has_sgte_exe ( void ) const; - - /// Set the \c SGTE_EXE parameter. - /** - \param bb_exe Truth executable -- \b IN. - \param sgte_exe Associated surrogate executable -- \b IN. - */ - void set_SGTE_EXE ( const std::string & bb_exe , const std::string & sgte_exe ); - - /// Set the \c SGTE_EVAL_SORT parameter. - /** - \param ses The \c SGTE_EVAL_SORT parameter -- \b IN. - */ - void set_SGTE_EVAL_SORT ( bool ses ); - - /// Set the \c HAS_SGTE parameter. - /** - \param hs The \c HAS_SGTE parameter -- \b IN. - */ - void set_HAS_SGTE ( bool hs ); - - /// Set the \c OPT_ONLY_SGTE parameter. - /** - \param oos The \c OPT_ONLY_SGTE parameter -- \b IN. - */ - void set_OPT_ONLY_SGTE ( bool oos ); - - /// Set the \c SGTE_COST parameter. - /** - \param sc The \c SGTE_COST parameter -- \b IN. - */ - void set_SGTE_COST ( int sc ); - - /// Set the \c MAX_SGTE_EVAL parameter. - /** - \param mse The \c MAX_SGTE_EVAL parameter -- \b IN. - */ - void set_MAX_SGTE_EVAL ( int mse ); - - /// Set the \c SGTE_CACHE_FILE parameter. - /** - \param scf The \c SGTE_CACHE_FILE parameter -- \b IN. - */ - void set_SGTE_CACHE_FILE ( const std::string & scf ); - - // Barrier: - // -------- - private: - NOMAD::Double _h_min; ///< Value of \c h_min. - NOMAD::Double _h_max_0; ///< Initial value of \c h_max. - NOMAD::Double _rho; ///< Rho parameter of the progressive barrier. - NOMAD::hnorm_type _h_norm; ///< Norm used to compute the feasibility function \c h. - - /// Flag equal to \c true if there are constraints. - bool _has_constraints; - - /// Flag equal to \c true if there are filter or progressive barrier constraints. - bool _has_filter_constraints; - - /// Flag equal to \c true if there are extreme barrier constraints. - bool _has_EB_constraints; - - /// Type of the barrier. - /** - May be NOMAD::FILTER, NOMAD::PB, NOMAD::PEB_P, or NOMAD::EB. - */ - NOMAD::bb_output_type _barrier_type; - - public: - - /// Access to the \c H_MIN parameter. - /** - \return The \c H_MIN parameter. - */ - const NOMAD::Double & get_h_min ( void ) const; - - /// Access to the \c H_MAX_0 parameter. - /** - \return The \c H_MAX_0 parameter. - */ - const NOMAD::Double & get_h_max_0 ( void ) const; - - /// Access to the \c RHO parameter. - /** - \return The \c RHO parameter. - */ - const NOMAD::Double & get_rho ( void ) const; - - /// Access to the \c H_NORM parameter. - /** - \return The \c H_NORM parameter. - */ - NOMAD::hnorm_type get_h_norm ( void ) const; - - /// Access to the type of barrier. - /** - \return The type of barrier. - */ - NOMAD::bb_output_type get_barrier_type ( void ) const; - - /// Check if there are constraints. - /** - \return A boolean equal to \c true if there are constraints. - */ - bool has_constraints ( void ) const; - - /// Check if there are extreme barrier constraints. - /** - \return A boolean equal to \c true if there are extreme barrier constraints. - */ - bool has_EB_constraints ( void ) const; - - /// Check if the progressive barrier (PB) is used. - /** - \return A boolean equal to \c true if the PB is used. - */ - bool use_sec_poll_center ( void ) const; - - /// Set the \c H_MIN parameter. - /** - \param h_min The \c H_MIN parameter -- \b IN. - */ - void set_H_MIN ( const NOMAD::Double & h_min ); - - /// Set the \c H_MAX_0 parameter. - /** - \param h_max The \c H_MAX_0 parameter -- \b IN. - */ - void set_H_MAX_0 ( const NOMAD::Double & h_max ); - - /// Set the \c RHO parameter. - /** - \param rho The \c RHO parameter -- \b IN. - */ - void set_RHO ( const NOMAD::Double & rho ); - - /// Set the \c H_NORM parameter. - /** - \param h_norm The \c H_NORM parameter -- \b IN. - */ - void set_H_NORM ( NOMAD::hnorm_type h_norm ); - - // MULTI-MADS parameters: - // ---------------------- - private: - - /// Number of MADS runs in Multi-MADS. - int _multi_nb_mads_runs; - - /// Maximum number of blackbox evaluations in Multi-MADS. - int _multi_overall_bb_eval; - - /// Flag equal to \c true if the delta criterion is used in Multi-MADS. - bool _multi_use_delta_crit; - - /// Bounds on the objective necessary for the display of the \c surf stat. - NOMAD::Point _multi_f_bounds; - - /// Multi-MADS reformulation. - /** - May be NOMAD::NORMALIZED, NOMAD::PRODUCT, - NOMAD::DIST_L1, NOMAD::DIST_L2, or NOMAD::DIST_LINF. - */ - NOMAD::multi_formulation_type _multi_formulation; - - public: - - /// Access to the \c MULTI_NB_MADS_RUNS parameter. - /** - \return The \c MULTI_NB_MADS_RUNS parameter. - */ - int get_multi_nb_mads_runs ( void ) const; - - /// Access to the \c MULTI_OVERALL_BB_EVAL parameter. - /** - \return The \c MULTI_OVERALL_BB_EVAL parameter. - */ - int get_multi_overall_bb_eval ( void ) const; - - /// Access to the \c MULTI_USE_DELTA_CRIT parameter. - /** - \return The \c MULTI_USE_DELTA_CRIT parameter. - */ - bool get_multi_use_delta_crit ( void ) const; - - /// Access to the \c MULTI_F_BOUNDS parameter. - /** - \return The \c MULTI_F_BOUNDS parameter. - */ - const NOMAD::Point & get_multi_f_bounds ( void ) const; - - /// Access to the \c MULTI_FORMULATION parameter. - /** - \return The \c MULTI_FORMULATION parameter. - */ - NOMAD::multi_formulation_type get_multi_formulation ( void ) const; - - /// Set the \c MULTI_NB_MADS_RUNS parameter. - /** - \param mads_runs The \c MULTI_NB_MADS_RUNS parameter -- \b IN. - */ - void set_MULTI_NB_MADS_RUNS ( int mads_runs ); - - /// Set the \c MULTI_OVERALL_BB_EVAL parameter. - /** - \param bbe The \c MULTI_OVERALL_BB_EVAL parameter -- \b IN. - */ - void set_MULTI_OVERALL_BB_EVAL ( int bbe ); - - /// Set the \c MULTI_USE_DELTA_CRIT parameter. - /** - \param udc The \c MULTI_USE_DELTA_CRIT parameter -- \b IN. - */ - void set_MULTI_USE_DELTA_CRIT ( bool udc ); - - /// Set the \c MULTI_F_BOUNDS parameter. - /** - \param mfb The \c MULTI_F_BOUNDS parameter -- \b IN. - */ - void set_MULTI_F_BOUNDS ( const NOMAD::Point & mfb ); - - /// Set the \c MULTI_FORMULATION parameter. - /** - \param mf The \c MULTI_FORMULATION parameter -- \b IN. - */ - void set_MULTI_FORMULATION ( NOMAD::multi_formulation_type mf ); - - // Opportunistic strategy parameters: - // ---------------------------------- - private: - - /// Flag equal to \c true if the opportunistic strategy is enabled. - bool _opportunistic_eval; - - /// Minimum number of successes. - /** - Parameter \c OPPORTUNISTIC_MIN_NB_SUCCESS. - */ - int _opportunistic_min_nb_success; - - /// Minimum number of evaluations. - /** - Parameter \c OPPORTUNISTIC_MIN_EVAL. - */ - int _opportunistic_min_eval; - - /// Minimum (relative) percentage of feasible objective improvement. - /** - Parameter \c OPPORTUNISTIC_MIN_F_IMPRVMT. - */ - NOMAD::Double _opportunistic_min_f_imprvmt; - - /// Flag equal to \c true if the lucky evaluation is enabled. - /** - Do one more eval "for luck". - */ - bool _opportunistic_lucky_eval; - - public: - - /// Access to the \c OPPORTUNISTIC_EVAL parameter. - /** - \return The \c OPPORTUNISTIC_EVAL parameter - */ - bool get_opportunistic_eval ( void ) const; - - /// Access to the \c OPPORTUNISTIC_MIN_NB_SUCCESS parameter. - /** - \return The \c OPPORTUNISTIC_MIN_NB_SUCCESS parameter. - */ - int get_opportunistic_min_nb_success ( void ) const; - - /// Access to the \c OPPORTUNISTIC_MIN_EVAL parameter. - /** - \return The \c OPPORTUNISTIC_MIN_EVAL parameter. - */ - int get_opportunistic_min_eval ( void ) const; - - /// Access to the \c OPPORTUNISTIC_MIN_F_IMPRVMT parameter. - /** - \return The \c OPPORTUNISTIC_MIN_F_IMPRVMT parameter. - */ - const NOMAD::Double & get_opportunistic_min_f_imprvmt ( void ) const; - - /// Access to the \c OPPORTUNISTIC_LUCKY_EVAL parameter. - /** - \return The \c OPPORTUNISTIC_LUCKY_EVAL parameter. - */ - bool get_opportunistic_lucky_eval ( void ) const; - - /// Set the \c OPPORTUNISTIC_EVAL parameter. - /** - \param opp_eval The \c OPPORTUNISTIC_EVAL parameter -- \b IN. - */ - void set_OPPORTUNISTIC_EVAL ( bool opp_eval ); - - /// Set the \c OPPORTUNISTIC_MIN_NB_SUCCESS parameter. - /** - \param opp_min_nb_succ The \c OPPORTUNISTIC_MIN_NB_SUCCESS parameter -- \b IN. - */ - void set_OPPORTUNISTIC_MIN_NB_SUCCESS ( int opp_min_nb_succ ); - - /// Set the \c OPPORTUNISTIC_MIN_EVAL parameter. - /** - \param opp_min_eval The \c OPPORTUNISTIC_MIN_EVAL parameter -- \b IN. - */ - void set_OPPORTUNISTIC_MIN_EVAL ( int opp_min_eval ); - - /// Set the \c OPPORTUNISTIC_MIN_F_IMPRVMT parameter. - /** - \param opp_min_f_imprvt The \c OPPORTUNISTIC_MIN_F_IMPRVMT parameter -- \b IN. - */ - void set_OPPORTUNISTIC_MIN_F_IMPRVMT ( const NOMAD::Double & opp_min_f_imprvt ); - - /// Set the \c OPPORTUNISTIC_LUCKY_EVAL parameter. - /** - \param opp_lucky_eval The \c OPPORTUNISTIC_LUCKY_EVAL parameter -- \b IN. - */ - void set_OPPORTUNISTIC_LUCKY_EVAL ( bool opp_lucky_eval ); - }; - - /*----------------------------------------------------------------------*/ - - /// Display a NOMAD::Parameters object. - /** - \param out The NOMAD::Display object -- \b IN. - \param p The NOMAD::Parameters object to be displayed -- \b IN. - \return The NOMAD::Display object. - */ - inline const NOMAD::Display & operator << ( const NOMAD::Display & out , - const NOMAD::Parameters & p ) - { - p.display ( out ); - return out; - } } #endif diff --git a/src/Pareto_Front.cpp b/src/Pareto_Front.cpp index 0369f48..0abcee5 100644 --- a/src/Pareto_Front.cpp +++ b/src/Pareto_Front.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Pareto_Front.hpp b/src/Pareto_Front.hpp index 1b2c2be..c7d251f 100644 --- a/src/Pareto_Front.hpp +++ b/src/Pareto_Front.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Pareto_Point.cpp b/src/Pareto_Point.cpp index 318289e..75ad0ae 100644 --- a/src/Pareto_Point.cpp +++ b/src/Pareto_Point.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Pareto_Point.hpp b/src/Pareto_Point.hpp index ccfe632..1d981f6 100644 --- a/src/Pareto_Point.hpp +++ b/src/Pareto_Point.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Phase_One_Evaluator.cpp b/src/Phase_One_Evaluator.cpp index e9697d4..27d57ef 100644 --- a/src/Phase_One_Evaluator.cpp +++ b/src/Phase_One_Evaluator.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Phase_One_Evaluator.cpp - \brief NOMAD::Evaluator subclass for the phase one (implementation) - \author Sebastien Le Digabel - \date 2010-04-09 - \see Phase_One_Evaluator.hpp -*/ + \file Phase_One_Evaluator.cpp + \brief NOMAD::Evaluator subclass for the phase one (implementation) + \author Sebastien Le Digabel + \date 2010-04-09 + \see Phase_One_Evaluator.hpp + */ #include "Phase_One_Evaluator.hpp" /*------------------------------------------------------------------*/ @@ -48,28 +48,30 @@ /*------------------------------------------------------------------*/ void NOMAD::Phase_One_Evaluator::compute_f ( NOMAD::Eval_Point & x ) const { - if ( x.get_bb_outputs().size() != _p.get_bb_nb_outputs() ) { - std::ostringstream err; - err << "Phase_One_Evaluator::compute_f(x): " - << "x has a wrong number of blackbox outputs (" - << x.get_bb_outputs().size() << " != " << _p.get_bb_nb_outputs() << ")"; - throw NOMAD::Exception ( "Phase_One_Evaluator.cpp" , __LINE__ , err.str() ); - } - - // objective value for MADS phase 1: the squared sum of all EB constraint violations - // (each EB constraint has been previously transformed into OBJ values): - const std::list<int> & index_obj = _p.get_index_obj(); - const std::list<int>::const_iterator end = index_obj.end(); - const NOMAD::Point & bbo = x.get_bb_outputs(); - NOMAD::Double h_min = _p.get_h_min(); - NOMAD::Double sum = 0.0; - NOMAD::Double v; - - for ( std::list<int>::const_iterator it = index_obj.begin() ; it != end ; ++it ) { - v = bbo[*it]; - if ( v > h_min ) - sum += v.pow2(); - } - - x.set_f ( sum ); + if ( x.get_bb_outputs().size() != _p.get_bb_nb_outputs() ) + { + std::ostringstream err; + err << "Phase_One_Evaluator::compute_f(x): " + << "x has a wrong number of blackbox outputs (" + << x.get_bb_outputs().size() << " != " << _p.get_bb_nb_outputs() << ")"; + throw NOMAD::Exception ( "Phase_One_Evaluator.cpp" , __LINE__ , err.str() ); + } + + // objective value for MADS phase 1: the squared sum of all EB constraint violations + // (each EB constraint has been previously transformed into OBJ values): + const std::list<int> & index_obj = _p.get_index_obj(); + const std::list<int>::const_iterator end = index_obj.end(); + const NOMAD::Point & bbo = x.get_bb_outputs(); + NOMAD::Double h_min = _p.get_h_min(); + NOMAD::Double sum = 0.0; + NOMAD::Double v; + + for ( std::list<int>::const_iterator it = index_obj.begin() ; it != end ; ++it ) + { + v = bbo[*it]; + if ( v > h_min ) + sum += v.pow2(); + } + + x.set_f ( sum ); } diff --git a/src/Phase_One_Evaluator.hpp b/src/Phase_One_Evaluator.hpp index 88d1bcc..a22ca4e 100644 --- a/src/Phase_One_Evaluator.hpp +++ b/src/Phase_One_Evaluator.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,85 +34,133 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Phase_One_Evaluator.hpp - \brief NOMAD::Evaluator subclass for the phase one (headers) - \author Sebastien Le Digabel - \date 2010-04-22 - \see Phase_One_Evaluator.cpp -*/ + \file Phase_One_Evaluator.hpp + \brief NOMAD::Evaluator subclass for the phase one (headers) + \author Sebastien Le Digabel + \date 2010-04-22 + \see Phase_One_Evaluator.cpp + */ #ifndef __PHASE_ONE_EVALUATOR__ #define __PHASE_ONE_EVALUATOR__ #include "Evaluator.hpp" namespace NOMAD { - - /// NOMAD::Evaluator subclass for the phase one. - class Phase_One_Evaluator : public NOMAD::Evaluator { - - private: - - NOMAD::Evaluator & _basic_ev; ///< The original evaluator. - - public: - - /// Constructor. - /** - \param p Parameters -- \b IN. - \param ev Original evaluator -- \b IN. - */ - Phase_One_Evaluator ( const NOMAD::Parameters & p , NOMAD::Evaluator & ev ) - : NOMAD::Evaluator ( p ) , - _basic_ev ( ev ) {} - - /// Destructor. - virtual ~Phase_One_Evaluator ( void ) {} - - /// User updates after a success. - /** - This virtual method is called every time a new (full) success is made. - \param s Stats -- \b IN. - \param x Successful point -- \b IN. - */ - virtual void update_success ( const NOMAD::Stats & s , const NOMAD::Eval_Point & x ) - { - _basic_ev.update_success ( s , x ); - } - - /// Evaluate the blackboxes at a given trial point. - /** - \param x The trial point -- \b IN/OUT. - \param h_max Maximal feasibility value \c h_max -- \b IN. - \param count_eval Flag indicating if the evaluation has to be counted - or not -- \b OUT. - \return A boolean equal to \c false if the evaluation failed. - */ - virtual bool eval_x ( NOMAD::Eval_Point & x , - const NOMAD::Double & h_max , - bool & count_eval ) const - { - return _basic_ev.eval_x ( x , h_max , count_eval ); - } - - /// User preprocessing of points before evaluations. - /** - This method is called before the evaluation of a list of points. - \param pts List of points to preprocess -- \b IN/OUT. - */ - virtual void list_of_points_preprocessing - ( std::set<NOMAD::Priority_Eval_Point> & pts ) const - { - _basic_ev.list_of_points_preprocessing ( pts ); - } - /// Objective computation. - /** - - Compute \c f(x) from the blackbox outputs of a point. - - Special objective for MADS phase one. - \param x The trial point -- \b IN/OUT. - */ - virtual void compute_f ( NOMAD::Eval_Point & x ) const; - }; + /// NOMAD::Evaluator subclass for the phase one. + class Phase_One_Evaluator : public NOMAD::Evaluator { + + private: + + NOMAD::Evaluator & _basic_ev; ///< The original evaluator. + + public: + + /// Constructor. + /** + \param p Parameters -- \b IN. + \param ev Original evaluator -- \b IN. + */ + Phase_One_Evaluator ( const NOMAD::Parameters & p , NOMAD::Evaluator & ev ) + : NOMAD::Evaluator ( p ) , + _basic_ev ( ev ) {} + + /// Destructor. + virtual ~Phase_One_Evaluator ( void ) {} + + /// User updates after a success. + /** + This virtual method is called every time a new (full) success is made. + \param s Stats -- \b IN. + \param x Successful point -- \b IN. + */ + virtual void update_success ( const NOMAD::Stats & s , const NOMAD::Eval_Point & x ) + { + _basic_ev.update_success ( s , x ); + } + + /// Evaluate the blackboxes at a given trial point. + /** + \param x The trial point -- \b IN/OUT. + \param h_max Maximal feasibility value \c h_max -- \b IN. + \param count_eval Flag indicating if the evaluation has to be counted + or not -- \b OUT. + \return A boolean equal to \c false if the evaluation failed. + */ + virtual bool eval_x ( NOMAD::Eval_Point & x , + const NOMAD::Double & h_max , + bool & count_eval ) const + { + return _basic_ev.eval_x ( x , h_max , count_eval ); + } + + + /// Evaluate the blackboxes at a given list of trial points. + /** + \param list_x The list of trial points -- \b IN/OUT. + \param h_max Maximal feasibility value \c h_max -- \b IN. + \param list_count_eval Flags indicating if the evaluations have to be counted + or not -- \b OUT. + \return A boolean equal to \c false if the evaluation failed. + */ + virtual bool eval_x ( std::list<NOMAD::Eval_Point *> & list_x , + const NOMAD::Double & h_max , + std::list<bool> & list_count_eval ) const + { + return _basic_ev.eval_x ( list_x , h_max , list_count_eval ); + } + + + /// User preprocessing of points before evaluations. + /** + This method is called before the evaluation of a list of points. + \param pts List of points to preprocess -- \b IN/OUT. + */ + virtual void list_of_points_preprocessing + ( std::set<NOMAD::Priority_Eval_Point> & pts ) const + { + _basic_ev.list_of_points_preprocessing ( pts ); + } + + + /// Access to the model evaluator flag. + /** + \return The model evaluator flag. + */ + virtual bool is_model_evaluator ( void ) const + { + return _basic_ev.is_model_evaluator(); + } + + /// User updates after an iteration. + /** + This virtual method is called every time a MADS iteration is terminated. + \param success Success of the iteration -- \b IN. + \param stats Stats -- \b IN. + \param ev_control The NOMAD::Evaluator_Control object -- \b IN. + \param true_barrier Barrier for true evaluations -- \b IN. + \param sgte_barrier Barrier for surrogate evaluations -- \b IN. + \param pareto_front Pareto front -- \b IN. + \param stop Allows the user to stop the algorithm -- \b OUT. + */ + virtual void update_iteration ( NOMAD::success_type success , + const NOMAD::Stats & stats , + const NOMAD::Evaluator_Control & ev_control , + const NOMAD::Barrier & true_barrier , + const NOMAD::Barrier & sgte_barrier , + const NOMAD::Pareto_Front & pareto_front , + bool & stop ) {} + + + + /// Objective computation. + /** + - Compute \c f(x) from the blackbox outputs of a point. + - Special objective for MADS phase one. + \param x The trial point -- \b IN/OUT. + */ + virtual void compute_f ( NOMAD::Eval_Point & x ) const; + }; } #endif diff --git a/src/Phase_One_Search.cpp b/src/Phase_One_Search.cpp index 1a9ed3e..d058fe2 100644 --- a/src/Phase_One_Search.cpp +++ b/src/Phase_One_Search.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Phase_One_Search.cpp - \brief NOMAD::Search subclass for the phase one (implementation) - \author Sebastien Le Digabel - \date 2010-04-09 - \see Phase_One_Search.hpp -*/ + \file Phase_One_Search.cpp + \brief NOMAD::Search subclass for the phase one (implementation) + \author Sebastien Le Digabel + \date 2010-04-09 + \see Phase_One_Search.hpp + */ #include "Phase_One_Search.hpp" /*-------------------------------------------------------------*/ @@ -47,279 +47,283 @@ /* (try to satisfy EB constraints) */ /*-------------------------------------------------------------*/ void NOMAD::Phase_One_Search::search ( NOMAD::Mads & mads , - int & nb_search_pts , - bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::success_type & success , - bool & count_search , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc ) + int & nb_search_pts , + bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::success_type & success , + bool & count_search , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc ) { - new_feas_inc = new_infeas_inc = NULL; - nb_search_pts = 0; - success = NOMAD::UNSUCCESSFUL; - stop = false; - count_search = true; - - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_search_dd(); - - // initial display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - std::ostringstream oss; - oss << NOMAD::P1_SEARCH; - out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; - } - - // stats: - NOMAD::Stats & stats = mads.get_stats(); - - // counters: - int old_bbe = stats.get_bb_eval(); - int old_it = stats.get_iterations(); - - // Evaluator_Control: - NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); - - // save and modify parameters: - std::string old_display_degree; - _p.out().get_display_degree ( old_display_degree ); - const std::list<std::string> old_ds = _p.get_display_stats(); - NOMAD::Double old_VNS_trigger = _p.get_VNS_trigger(); - const std::string old_stats_file_name = _p.get_stats_file_name(); - const std::string old_sol_file = _p.get_solution_file(); - const std::list<std::string> old_stats_file = _p.get_stats_file(); - const NOMAD::Point old_f_target = _p.get_f_target(); - NOMAD::Double old_lct = _p.get_L_curve_target(); - bool old_sif = _p.get_stop_if_feasible(); - const std::vector<NOMAD::bb_output_type> old_bbot = _p.get_bb_output_type(); - std::vector<NOMAD::bb_output_type> p1_bbot = old_bbot; - - - if ( display_degree == NOMAD::NORMAL_DISPLAY) // Normal display -> minimal display for Phase one - _p.set_DISPLAY_DEGREE( NOMAD::MINIMAL_DISPLAY); - else if (display_degree == NOMAD::FULL_DISPLAY) - _p.set_DISPLAY_DEGREE( NOMAD::FULL_DISPLAY);// Full display -> full display for Phase one - - - - int m = static_cast<int> ( old_bbot.size() ); - int cnt = 0; - for ( int i = 0 ; i < m ; ++i ) { - if ( old_bbot[i] == NOMAD::EB ) { - p1_bbot[i] = NOMAD::OBJ; - ++cnt; - } - else if ( old_bbot[i] == NOMAD::OBJ ) - p1_bbot[i] = NOMAD::UNDEFINED_BBO; - } - - if ( cnt == 0 ) { - stop = true; - stop_reason = NOMAD::P1_FAIL; - return; - } - - _p.set_F_TARGET ( NOMAD::Point ( cnt , 0.0 ) ); - _p.set_L_CURVE_TARGET ( NOMAD::Double() ); - _p.set_STOP_IF_FEASIBLE ( false ); - _p.set_VNS_SEARCH ( false ); - _p.set_BB_OUTPUT_TYPE ( p1_bbot ); - _p.set_SOLUTION_FILE ( "" ); - _p.reset_stats_file(); - - // DISPLAY_STATS and STATS_FILE - { - std::list<std::string> ds = old_ds; - std::list<std::string> sf = old_stats_file; - ds.push_back ( " (PhaseOne)" ); - _p.set_DISPLAY_STATS ( ds ); - sf.push_back ( " (PhaseOne)" ); - _p.set_STATS_FILE ( old_stats_file_name , sf ); - - } - - - _p.check ( false , // remove_history_file = false - true , // remove_solution_file = true - false ); // remove_stats_file = false - - // modify evaluator: - NOMAD::Evaluator * old_ev = ev_control.get_evaluator(); - NOMAD::Phase_One_Evaluator * p1ev = new NOMAD::Phase_One_Evaluator ( _p , *old_ev ); - ev_control.set_evaluator ( p1ev ); - - // disable the Pareto front: - NOMAD::Pareto_Front * old_pareto_front = mads.get_pareto_front(); - mads.set_pareto_front ( NULL ); - - int old_eval = stats.get_eval(); - - // run MADS with modified parameters: - // ---------------------------------- - - // C. Tribes march 2013 ---- these flags are mads static and must be put back to their original value after running mads (see below) - // get flags: - bool flag_check_bimads , flag_reset_mesh , flag_reset_barriers , flag_p1_active; - NOMAD::Mads::get_flags ( flag_check_bimads , - flag_reset_mesh , - flag_reset_barriers , - flag_p1_active ); - - - // set flags: - NOMAD::Mads::set_flag_check_bimads ( false ); - NOMAD::Mads::set_flag_reset_mesh ( false ); - NOMAD::Mads::set_flag_p1_active ( true ); - NOMAD::Mads::set_flag_reset_barriers ( true ); - - // run: - stop_reason = mads.run(); - - // reset stopping condition: - if ( stop_reason == NOMAD::F_TARGET_REACHED ) { - - // stop if feasible: - if ( old_sif ) { - stop = true; - stop_reason = NOMAD::FEAS_REACHED; - } - - // continue: - else { - stop = false; - stop_reason = NOMAD::NO_STOP; - } - } - else - stop = true; - - // reset flags to there previous state : - // C. Tribes march 2013 ---- these flags are mads static and must be put back to their original value after running mads - NOMAD::Mads::set_flag_check_bimads ( flag_check_bimads ); - NOMAD::Mads::set_flag_reset_mesh ( flag_reset_mesh ); - NOMAD::Mads::set_flag_p1_active ( flag_p1_active ); - NOMAD::Mads::set_flag_reset_barriers ( flag_reset_barriers ); - -// NOMAD::Mads::set_flag_check_bimads ( true ); -// NOMAD::Mads::set_flag_reset_mesh ( true ); -// NOMAD::Mads::set_flag_p1_active ( false ); - - // number of search points: - nb_search_pts = stats.get_eval() - old_eval; - - // restore evaluator: - ev_control.set_evaluator ( old_ev ); - delete p1ev; - - // restore the Pareto front: - mads.set_pareto_front ( old_pareto_front ); - - // restore parameters: - _p.set_VNS_SEARCH ( old_VNS_trigger ); - _p.set_F_TARGET ( old_f_target ); - _p.set_L_CURVE_TARGET ( old_lct ); - _p.set_BB_OUTPUT_TYPE ( old_bbot ); - _p.set_DISPLAY_DEGREE ( old_display_degree ); - _p.set_SOLUTION_FILE ( old_sol_file ); - _p.reset_stats_file(); - _p.set_STATS_FILE ( old_stats_file_name , old_stats_file ); - _p.set_DISPLAY_STATS (old_ds); - - _p.check ( false , // remove_history_file = false - true , // remove_solution_file = true - false ); // remove_stats_file = true - - // reset mesh index: - NOMAD::Mesh::set_mesh_index ( _p.get_initial_mesh_index() ); - - // counters: - stats.add_p1_iterations ( stats.get_iterations() - old_it ); - stats.add_p1_bbe ( stats.get_bb_eval () - old_bbe ); - - // for the update of new_feas_inc and new_infeas_inc (1/2): - const NOMAD::Barrier & active_barrier = mads.get_active_barrier(); - const NOMAD::Eval_Point * old_feasible_incumbent = NULL; - const NOMAD::Eval_Point * old_infeasible_incumbent = NULL; - old_feasible_incumbent = active_barrier.get_best_feasible(); - old_infeasible_incumbent = active_barrier.get_best_infeasible(); - - // update the barriers and compute the true values - // of f and h for all evaluated points: - NOMAD::Barrier & true_barrier = mads.get_true_barrier(); - NOMAD::Barrier & sgte_barrier = mads.get_sgte_barrier(); - - true_barrier.reset(); - sgte_barrier.reset(); - - // scan the active cache: - const NOMAD::Cache & active_cache = mads.get_cache(); - if ( active_cache.empty() ) { - stop = true; - stop_reason = NOMAD::P1_FAIL; - return; - } - - const NOMAD::Eval_Point * cur = active_cache.begin(); - while ( cur ) { - - if ( cur->get_current_run() && cur->is_eval_ok() ) { - - NOMAD::Eval_Point * modifiable_x = &NOMAD::Cache::get_modifiable_point ( *cur ); - - modifiable_x->set_direction ( NULL ); - modifiable_x->set_mesh_index ( NULL ); - modifiable_x->set_poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ); - modifiable_x->set_user_eval_priority ( NOMAD::Double() ); - modifiable_x->set_rand_eval_priority ( NOMAD::Double() ); - - old_ev->compute_f ( *modifiable_x ); - old_ev->compute_h ( *modifiable_x ); - - // insertion in barrier: - (( cur->get_eval_type() == NOMAD::TRUTH ) ? - true_barrier : sgte_barrier).insert (*cur); - } - cur = active_cache.next(); - } - - success = active_barrier.get_success(); - - if ( !stop && success == NOMAD::UNSUCCESSFUL ) { - stop = true; - stop_reason = NOMAD::P1_FAIL; - return; - } - - true_barrier.update_and_reset_success(); - sgte_barrier.update_and_reset_success(); - - // update of new_feas_inc and new_infeas_inc (2/2): - const NOMAD::Eval_Point * bf = active_barrier.get_best_feasible (); - const NOMAD::Eval_Point * bi = active_barrier.get_best_infeasible(); - if ( bf && bf != old_feasible_incumbent ) - new_feas_inc = bf; - if ( bi && bi != old_infeasible_incumbent ) - new_infeas_inc = bi; - - // final displays: - if ( bf ) - { - - // solution file: - ev_control.write_solution_file ( *bf ); - - // stats_file: - const std::string & stats_file_name = _p.get_stats_file_name(); - if ( !stats_file_name.empty() && display_degree > NOMAD::NO_DISPLAY) - ev_control.stats_file ( stats_file_name , bf , true , NULL ); - - // display_stats - if (display_degree > NOMAD::NO_DISPLAY) - ev_control.display_stats(false, out, old_ds , bf , true , NULL ); - } - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::close_block ( "end of phase one" ); + new_feas_inc = new_infeas_inc = NULL; + nb_search_pts = 0; + success = NOMAD::UNSUCCESSFUL; + stop = false; + count_search = true; + + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_search_dd(); + + // initial display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << NOMAD::P1_SEARCH; + out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; + } + + // stats: + NOMAD::Stats & stats = mads.get_stats(); + + // counters: + int old_bbe = stats.get_bb_eval(); + int old_it = stats.get_iterations(); + + // Evaluator_Control: + NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); + + // save and modify parameters: + std::string old_display_degree; + _p.out().get_display_degree ( old_display_degree ); + const std::list<std::string> old_ds = _p.get_display_stats(); + NOMAD::Double old_VNS_trigger = _p.get_VNS_trigger(); + const std::string old_stats_file_name = _p.get_stats_file_name(); + const std::string old_sol_file = _p.get_solution_file(); + const std::list<std::string> old_stats_file = _p.get_stats_file(); + const NOMAD::Point old_f_target = _p.get_f_target(); + NOMAD::Double old_lct = _p.get_L_curve_target(); + bool old_sif = _p.get_stop_if_feasible(); + const std::vector<NOMAD::bb_output_type> old_bbot = _p.get_bb_output_type(); + std::vector<NOMAD::bb_output_type> p1_bbot = old_bbot; + + + if ( display_degree == NOMAD::NORMAL_DISPLAY) // Normal display -> minimal display for Phase one + _p.set_DISPLAY_DEGREE( NOMAD::MINIMAL_DISPLAY); + else if (display_degree == NOMAD::FULL_DISPLAY) + _p.set_DISPLAY_DEGREE( NOMAD::FULL_DISPLAY);// Full display -> full display for Phase one + + + + int m = static_cast<int> ( old_bbot.size() ); + int cnt = 0; + for ( int i = 0 ; i < m ; ++i ) + { + if ( old_bbot[i] == NOMAD::EB ) + { + p1_bbot[i] = NOMAD::OBJ; + ++cnt; + } + else if ( old_bbot[i] == NOMAD::OBJ ) + p1_bbot[i] = NOMAD::UNDEFINED_BBO; + } + + if ( cnt == 0 ) { + stop = true; + stop_reason = NOMAD::P1_FAIL; + return; + } + + _p.set_F_TARGET ( NOMAD::Point ( cnt , 0.0 ) ); + _p.set_L_CURVE_TARGET ( NOMAD::Double() ); + _p.set_STOP_IF_FEASIBLE ( false ); + _p.set_VNS_SEARCH ( false ); + _p.set_BB_OUTPUT_TYPE ( p1_bbot ); + _p.set_SOLUTION_FILE ( "" ); + _p.reset_stats_file(); + + // DISPLAY_STATS and STATS_FILE + { + std::list<std::string> ds = old_ds; + std::list<std::string> sf = old_stats_file; + ds.push_back ( " (PhaseOne)" ); + _p.set_DISPLAY_STATS ( ds ); + sf.push_back ( " (PhaseOne)" ); + _p.set_STATS_FILE ( old_stats_file_name , sf ); + + } + + _p.check ( false , // remove_history_file = false + true , // remove_solution_file = true + false ); // remove_stats_file = false + + // modify evaluator: + NOMAD::Evaluator * old_ev = ev_control.get_evaluator(); + NOMAD::Phase_One_Evaluator * p1ev = new NOMAD::Phase_One_Evaluator ( _p , *old_ev ); + ev_control.set_evaluator ( p1ev ); + + // disable the Pareto front: + NOMAD::Pareto_Front * old_pareto_front = mads.get_pareto_front(); + mads.set_pareto_front ( NULL ); + + int old_eval = stats.get_eval(); + + // run MADS with modified parameters: + // ---------------------------------- + + // C. Tribes march 2014 ---- these flags are mads static and must be put back to their original value after running mads (see below) + // get flags: + bool flag_check_bimads , flag_reset_mesh , flag_reset_barriers , flag_p1_active; + NOMAD::Mads::get_flags ( flag_check_bimads , + flag_reset_mesh , + flag_reset_barriers , + flag_p1_active ); + + + // set flags: + NOMAD::Mads::set_flag_check_bimads ( false ); + NOMAD::Mads::set_flag_reset_mesh ( false ); + NOMAD::Mads::set_flag_p1_active ( true ); + NOMAD::Mads::set_flag_reset_barriers ( true ); + + // run: + stop_reason = mads.run(); + + // reset stopping condition: + if ( stop_reason == NOMAD::F_TARGET_REACHED ) + { + + // stop if feasible: + if ( old_sif ) + { + stop = true; + stop_reason = NOMAD::FEAS_REACHED; + } + + // continue: + else { + stop = false; + stop_reason = NOMAD::NO_STOP; + } + } + else + stop = true; + + // reset flags to there previous state : + // C. Tribes march 2014 ---- these flags are mads static and must be put back to their original value after running mads + NOMAD::Mads::set_flag_check_bimads ( flag_check_bimads ); + NOMAD::Mads::set_flag_reset_mesh ( flag_reset_mesh ); + NOMAD::Mads::set_flag_p1_active ( flag_p1_active ); + NOMAD::Mads::set_flag_reset_barriers ( flag_reset_barriers ); + + // NOMAD::Mads::set_flag_check_bimads ( true ); + // NOMAD::Mads::set_flag_reset_mesh ( true ); + // NOMAD::Mads::set_flag_p1_active ( false ); + + // number of search points: + nb_search_pts = stats.get_eval() - old_eval; + + // restore evaluator: + ev_control.set_evaluator ( old_ev ); + delete p1ev; + + // restore the Pareto front: + mads.set_pareto_front ( old_pareto_front ); + + // restore parameters: + _p.set_VNS_SEARCH ( old_VNS_trigger ); + _p.set_F_TARGET ( old_f_target ); + _p.set_L_CURVE_TARGET ( old_lct ); + _p.set_BB_OUTPUT_TYPE ( old_bbot ); + _p.set_DISPLAY_DEGREE ( old_display_degree ); + _p.set_SOLUTION_FILE ( old_sol_file ); + _p.reset_stats_file(); + _p.set_STATS_FILE ( old_stats_file_name , old_stats_file ); + _p.set_DISPLAY_STATS (old_ds); + + _p.check ( false , // remove_history_file = false + true , // remove_solution_file = true + false ); // remove_stats_file = true + + + // counters: + stats.add_p1_iterations ( stats.get_iterations() - old_it ); + stats.add_p1_bbe ( stats.get_bb_eval () - old_bbe ); + + // for the update of new_feas_inc and new_infeas_inc (1/2): + const NOMAD::Barrier & active_barrier = mads.get_active_barrier(); + const NOMAD::Eval_Point * old_feasible_incumbent = NULL; + const NOMAD::Eval_Point * old_infeasible_incumbent = NULL; + old_feasible_incumbent = active_barrier.get_best_feasible(); + old_infeasible_incumbent = active_barrier.get_best_infeasible(); + + // update the barriers and compute the true values + // of f and h for all evaluated points: + NOMAD::Barrier & true_barrier = mads.get_true_barrier(); + NOMAD::Barrier & sgte_barrier = mads.get_sgte_barrier(); + + true_barrier.reset(); + sgte_barrier.reset(); + + // scan the active cache: + const NOMAD::Cache & active_cache = mads.get_cache(); + if ( active_cache.empty() ) + { + stop = true; + stop_reason = NOMAD::P1_FAIL; + return; + } + + const NOMAD::Eval_Point * cur = active_cache.begin(); + while ( cur ) + { + + if ( cur->is_eval_ok() && cur->get_signature() ) + { + + NOMAD::Eval_Point * modifiable_x = &NOMAD::Cache::get_modifiable_point ( *cur ); + + modifiable_x->set_direction ( NULL ); + modifiable_x->set_poll_center_type ( NOMAD::UNDEFINED_POLL_CENTER_TYPE ); + modifiable_x->set_user_eval_priority ( NOMAD::Double() ); + modifiable_x->set_rand_eval_priority ( NOMAD::Double() ); + + old_ev->compute_f ( *modifiable_x ); + old_ev->compute_h ( *modifiable_x ); + + // insertion in barrier: + (( cur->get_eval_type() == NOMAD::TRUTH ) ? true_barrier : sgte_barrier).insert (*cur); + } + + cur = active_cache.next(); + } + + success = active_barrier.get_success(); + + if ( !stop && success == NOMAD::UNSUCCESSFUL ) + { + stop = true; + stop_reason = NOMAD::P1_FAIL; + return; + } + + true_barrier.update_and_reset_success(); + sgte_barrier.update_and_reset_success(); + + // update of new_feas_inc and new_infeas_inc (2/2): + const NOMAD::Eval_Point * bf = active_barrier.get_best_feasible (); + const NOMAD::Eval_Point * bi = active_barrier.get_best_infeasible(); + if ( bf && bf != old_feasible_incumbent ) + new_feas_inc = bf; + if ( bi && bi != old_infeasible_incumbent ) + new_infeas_inc = bi; + + // final displays: + if ( bf && bf->get_current_run() ) + { + + // solution file: + ev_control.write_solution_file ( *bf ); + + // stats_file: + const std::string & stats_file_name = _p.get_stats_file_name(); + if ( !stats_file_name.empty() && display_degree > NOMAD::NO_DISPLAY) + ev_control.stats_file ( stats_file_name , bf , true , NULL ); + + // display_stats + if (display_degree > NOMAD::NO_DISPLAY) + ev_control.display_stats(false, out, old_ds , bf , true , NULL ); + } + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << NOMAD::close_block ( "end of phase one" ); } diff --git a/src/Phase_One_Search.hpp b/src/Phase_One_Search.hpp index 2991666..46b57d6 100644 --- a/src/Phase_One_Search.hpp +++ b/src/Phase_One_Search.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Point.cpp b/src/Point.cpp index 57f10c8..fe27123 100644 --- a/src/Point.cpp +++ b/src/Point.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -62,7 +62,8 @@ NOMAD::Point::Point ( int n , const NOMAD::Double & d ) : _n (n) , _coords (NULL if ( NOMAD::Point::_cardinality > NOMAD::Point::_max_cardinality ) ++NOMAD::Point::_max_cardinality; #endif - if (_n > 0) { + if (_n > 0) + { _coords = new NOMAD::Double [_n]; if ( d.is_defined() ) std::fill ( _coords , _coords+_n , d ); @@ -81,7 +82,8 @@ NOMAD::Point::Point ( const NOMAD::Point & p ) : _n (p._n) , _coords (NULL) if ( NOMAD::Point::_cardinality >= NOMAD::Point::_max_cardinality ) ++NOMAD::Point::_max_cardinality; #endif - if ( _n > 0 ) { + if ( _n > 0 ) + { NOMAD::Double * p1 = _coords = new NOMAD::Double [_n]; const NOMAD::Double * p2 = p._coords; for ( int k = 0 ; k < _n ; ++k , ++p1 , ++p2 ) @@ -106,13 +108,16 @@ NOMAD::Point::~Point ( void ) /*-----------------------------------------------*/ void NOMAD::Point::reset ( int n , const NOMAD::Double & d ) { - if ( n <= 0 ) { + if ( n <= 0 ) + { _n = 0; delete [] _coords; _coords = NULL; } - else { - if ( _n != n ) { + else + { + if ( _n != n ) + { delete [] _coords; _n = n; _coords = new NOMAD::Double [_n]; @@ -129,15 +134,17 @@ void NOMAD::Point::resize ( int n ) { if ( n == _n ) return; - if ( n <= 0 ) { + + if ( n <= 0 ) + { _n = 0; delete [] _coords; _coords = NULL; return; } NOMAD::Double * new_coords = new NOMAD::Double [n]; - if ( _coords ) { - + if ( _coords ) + { int min = ( n < _n ) ? n : _n; NOMAD::Double * p1 = new_coords; @@ -188,7 +195,8 @@ const NOMAD::Point & NOMAD::Point::operator = ( const NOMAD::Point & p ) if ( this == &p ) return *this; - if ( _n != p._n ) { + if ( _n != p._n ) + { delete [] _coords; _n = p._n; if (_n > 0) @@ -306,7 +314,8 @@ void NOMAD::Point::set ( int n , const NOMAD::Double * a ) if ( n <= 0 || !a ) return; - if ( _n != n ) { + if ( _n != n ) + { delete [] _coords; _n = n; _coords = new NOMAD::Double [_n]; @@ -475,7 +484,8 @@ bool NOMAD::Point::operator < ( const NOMAD::Point & p ) const const NOMAD::Double * p1 = _coords; const NOMAD::Double * p2 = p._coords; - for ( int k = 0 ; k < _n ; ++k , ++p1 , ++p2 ) { + for ( int k = 0 ; k < _n ; ++k , ++p1 , ++p2 ) + { if ( *p1 < *p2 ) return true; @@ -505,8 +515,8 @@ bool NOMAD::Point::comp_with_undef ( const NOMAD::Point & p ) const bool p1d , p2d; - for ( int k = 0 ; k < _n ; ++k , ++p1 , ++p2 ) { - + for ( int k = 0 ; k < _n ; ++k , ++p1 , ++p2 ) + { p1d = p1->is_defined(); p2d = p2->is_defined(); @@ -560,7 +570,8 @@ const NOMAD::Double NOMAD::Point::get_angle ( const NOMAD::Point & x ) const const NOMAD::Double * p1 = _coords; const NOMAD::Double * p2 = x._coords; - for ( int i = 0 ; i < _n ; ++i , ++p1 , ++p2 ) { + for ( int i = 0 ; i < _n ; ++i , ++p1 , ++p2 ) + { norm_1 += *p1 * *p1; norm_2 += *p2 * *p2; inner_product += *p1 * *p2; diff --git a/src/Point.hpp b/src/Point.hpp index f889910..344ade6 100644 --- a/src/Point.hpp +++ b/src/Point.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -43,9 +43,6 @@ #ifndef __POINT__ #define __POINT__ -/// Avoids warnings on std::inner_product with visual C++. -#define _SCL_SECURE_NO_WARNINGS - #include <numeric> #include <functional> #include "Double.hpp" diff --git a/src/Priority_Eval_Point.cpp b/src/Priority_Eval_Point.cpp index af60cb1..f5059e4 100644 --- a/src/Priority_Eval_Point.cpp +++ b/src/Priority_Eval_Point.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -42,6 +42,8 @@ */ #include "Priority_Eval_Point.hpp" +bool NOMAD::Priority_Eval_Point::_lexicographic_order=false; + /*------------------------------------------------*/ /* comparison operator */ /*------------------------------------------------*/ @@ -54,10 +56,14 @@ bool NOMAD::Priority_Eval_Point::dominates { if ( this == &x ) return false; - - const NOMAD::Eval_Point * x1 = get_element(); + const NOMAD::Eval_Point * x1 = get_element(); const NOMAD::Eval_Point * x2 = x.get_element(); + // criterion 0: lexicographic order + if (_lexicographic_order) + return NOMAD::Point(*x1) < NOMAD::Point(*x2); + + // criterion 1: user criterion: // ------------ const NOMAD::Double uep1 = x1->get_user_eval_priority(); @@ -115,7 +121,7 @@ bool NOMAD::Priority_Eval_Point::dominates // ------------ flag = compare_hf_values ( _h_sgte , _f_sgte , x_h_sgte , x_f_sgte ); if ( flag ) - return ( flag > 0 ); + return ( flag > 0 ); // criterion 6: model f and h values: // ------------ @@ -135,22 +141,8 @@ bool NOMAD::Priority_Eval_Point::dominates return false; } - // !not used! - // criterion 8: check the angle with the simplex gradient: - // ------------ - if ( _angle_simplex_grad.is_defined() && x_angle_simplex_grad.is_defined() ) - { - - if ( _angle_simplex_grad < x_angle_simplex_grad ) - return true; - - if ( x_angle_simplex_grad < _angle_simplex_grad ) - return false; - } - - - // criterion 9: take the point with the best h value: + // criterion 8: take the point with the best h value: // ------------ flag = compare_h_values ( x1->get_h() , x2->get_h() ); if ( flag ) @@ -164,12 +156,14 @@ bool NOMAD::Priority_Eval_Point::dominates if ( flag ) return ( flag > 0 ); - // criterion 10: random criterion for randomly generated directions: + // criterion 9: random criterion for randomly generated directions: // ------------- const NOMAD::Double rep1 = x1->get_rand_eval_priority(); - if ( rep1.is_defined() ) { + if ( rep1.is_defined() ) + { const NOMAD::Double rep2 = x2->get_rand_eval_priority(); - if ( rep2.is_defined() ) { + if ( rep2.is_defined() ) + { if ( rep1 < rep2 ) return true; if ( rep2 < rep1 ) @@ -177,9 +171,10 @@ bool NOMAD::Priority_Eval_Point::dominates } } - // criterion 11: compare the tags: + // criterion 10: compare the tags: // ------------- return x1->get_tag() < x2->get_tag(); + } /*-----------------------------------------------*/ @@ -194,7 +189,8 @@ bool NOMAD::Priority_Eval_Point::dominates int NOMAD::Priority_Eval_Point::compare_h_values ( const NOMAD::Double & hx1 , const NOMAD::Double & hx2 ) const { - if ( hx1.is_defined() && hx2.is_defined() ) { + if ( hx1.is_defined() && hx2.is_defined() ) + { if ( hx1 < hx2 ) return 1; if ( hx2 < hx1 ) @@ -218,53 +214,56 @@ int NOMAD::Priority_Eval_Point::compare_hf_values ( const NOMAD::Double & hx1 , const NOMAD::Double & hx2 , const NOMAD::Double & fx2 ) const { - if ( fx1.is_defined() && fx2.is_defined() ) { - - if ( hx1.is_defined() && hx2.is_defined() ) { - - // x1 is feasible: - if ( hx1 <= _h_min ) { - - // both points are feasible: - if ( hx2 <= _h_min ) { - if ( fx1 < fx2 ) - return 1; - if ( fx2 < fx1 ) - return -1; + if ( fx1.is_defined() && fx2.is_defined() ) + { + + if ( hx1.is_defined() && hx2.is_defined() ) + { + // x1 is feasible: + if ( hx1 <= _h_min ) + { + // both points are feasible: + if ( hx2 <= _h_min ) + { + if ( fx1 < fx2 ) + return 1; + if ( fx2 < fx1 ) + return -1; + } + + // x1 feasible and x2 infeasible: + else + return 1; + } + + // x1 is infeasible: + else + { + // x2 is feasible: + if ( hx2 <= _h_min ) + return -1; + + // both points are infeasible: + if ( ( hx1 < hx2 && fx1 < fx2 ) || + ( hx1 == hx2 && fx1 < fx2 ) || + ( hx1 < hx2 && fx1 == fx2 ) ) + return 1; + + if ( ( hx2 < hx1 && fx2 < fx1 ) || + ( hx2 == hx1 && fx2 < fx1 ) || + ( hx2 < hx1 && fx2 == fx1 ) ) + return -1; + } + } + + // we only have f values: + else + { + if ( fx1 < fx2 ) + return 1; + if ( fx2 < fx1 ) + return -1; + } } - - // x1 feasible and x2 infeasible: - else - return 1; - } - - // x1 is infeasible: - else { - - // x2 is feasible: - if ( hx2 <= _h_min ) - return -1; - - // both points are infeasible: - if ( ( hx1 < hx2 && fx1 < fx2 ) || - ( hx1 == hx2 && fx1 < fx2 ) || - ( hx1 < hx2 && fx1 == fx2 ) ) - return 1; - - if ( ( hx2 < hx1 && fx2 < fx1 ) || - ( hx2 == hx1 && fx2 < fx1 ) || - ( hx2 < hx1 && fx2 == fx1 ) ) - return -1; - } - } - - // we only have f values: - else { - if ( fx1 < fx2 ) - return 1; - if ( fx2 < fx1 ) - return -1; - } - } - return 0; + return 0; } diff --git a/src/Priority_Eval_Point.hpp b/src/Priority_Eval_Point.hpp index 24939ca..e74885d 100644 --- a/src/Priority_Eval_Point.hpp +++ b/src/Priority_Eval_Point.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -60,6 +60,7 @@ namespace NOMAD { NOMAD::Double _h_model; ///< Feasibility model value. NOMAD::Double _angle_success_dir; ///< Angle with last successful direction. NOMAD::Double _angle_simplex_grad; ///< Angle with simplex gradient. + static bool _lexicographic_order; ///< Use lexicographic order for comparison /// Affectation operator. /** @@ -214,6 +215,12 @@ namespace NOMAD { */ void set_h_model ( const NOMAD::Double & h ) { _h_model = h; } + /// Set the lexicographic order for sorting. + /** + */ + static void set_lexicographic_order ( bool order ) { _lexicographic_order = order; } + + }; } diff --git a/src/Quad_Model.cpp b/src/Quad_Model.cpp index 668d525..0bb28ef 100644 --- a/src/Quad_Model.cpp +++ b/src/Quad_Model.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Quad_Model.cpp - \brief Quadratic regression or MFN interpolation model (implementation) - \author Sebastien Le Digabel - \date 2010-08-31 - \see Quad_Model.hpp -*/ + \file Quad_Model.cpp + \brief Quadratic regression or MFN interpolation model (implementation) + \author Sebastien Le Digabel + \date 2010-08-31 + \see Quad_Model.hpp + */ #include "Quad_Model.hpp" /*-----------------------------------------------------------*/ @@ -47,24 +47,24 @@ /*-----------------------------------------------------------*/ NOMAD::Quad_Model::Quad_Model ( const NOMAD::Display & out , - const std::vector<NOMAD::bb_output_type> & bbot , - const NOMAD::Cache & cache , - const NOMAD::Signature & signature ) - : _out ( out ) , - _bbot ( bbot ) , - _interpolation_type ( NOMAD::UNDEFINED_INTERPOLATION_TYPE ) , - _n ( signature.get_n() ) , - _nfree ( _n ) , - _fixed_vars ( new bool [_n] ) , - _index ( NULL ) , - _alpha ( NULL ) , - _cache ( cache ) , - _signature ( signature ) , - _error_flag ( true ) + const std::vector<NOMAD::bb_output_type> & bbot , + const NOMAD::Cache & cache , + const NOMAD::Signature & signature ) +: _out ( out ) , +_bbot ( bbot ) , +_interpolation_type ( NOMAD::UNDEFINED_INTERPOLATION_TYPE ) , +_n ( signature.get_n() ) , +_nfree ( _n ) , +_fixed_vars ( new bool [_n] ) , +_index ( NULL ) , +_alpha ( NULL ) , +_cache ( cache ) , +_signature ( signature ) , +_error_flag ( true ) { - for ( int i = 0 ; i < _n ; ++i ) - _fixed_vars[i] = false; - init_alpha(); + for ( int i = 0 ; i < _n ; ++i ) + _fixed_vars[i] = false; + init_alpha(); } /*-----------------------------------------------------------*/ @@ -72,16 +72,16 @@ NOMAD::Quad_Model::Quad_Model /*-----------------------------------------------------------*/ NOMAD::Quad_Model::~Quad_Model ( void ) { - int m = static_cast<int> ( _bbot.size() ); - for ( int i = 0 ; i < m ; ++i ) - delete _alpha[i]; - delete [] _alpha; - delete [] _fixed_vars; - delete [] _index; - - // clear the interpolation set Y: - for ( size_t k = 0 ; k < _Y.size() ; ++k ) - delete _Y[k]; + int m = static_cast<int> ( _bbot.size() ); + for ( int i = 0 ; i < m ; ++i ) + delete _alpha[i]; + delete [] _alpha; + delete [] _fixed_vars; + delete [] _index; + + // clear the interpolation set Y: + for ( size_t k = 0 ; k < _Y.size() ; ++k ) + delete _Y[k]; } /*-----------------------------------------------------------*/ @@ -89,72 +89,76 @@ NOMAD::Quad_Model::~Quad_Model ( void ) /*-----------------------------------------------------------*/ void NOMAD::Quad_Model::init_alpha ( void ) { - _n_alpha = ( _nfree + 1 ) * ( _nfree + 2 ) / 2; - - int i , m = static_cast<int> ( _bbot.size() ); - - // initialize _alpha: - // ------------------ - if ( _alpha ) { + _n_alpha = ( _nfree + 1 ) * ( _nfree + 2 ) / 2; + + int i , m = static_cast<int> ( _bbot.size() ); + + // initialize _alpha: + // ------------------ + if ( _alpha ) + { + for ( i = 0 ; i < m ; ++i ) + delete _alpha[i]; + delete [] _alpha; + } + + _alpha = new NOMAD::Point * [m]; + for ( i = 0 ; i < m ; ++i ) - delete _alpha[i]; - delete [] _alpha; - } - - _alpha = new NOMAD::Point * [m]; - - for ( i = 0 ; i < m ; ++i ) - _alpha[i] = ( _bbot[i] == NOMAD::OBJ || NOMAD::bbot_is_constraint(_bbot[i]) ) ? - new NOMAD::Point ( _n_alpha ) : NULL; - - // initialize _index: - // ------------------ - - // example: with 3 variables (X,Y,Z) with Y fixed. - // -------- - // the problem is reduced to the two variables x=X and y=Z, - // and _index is corresponds to: - // - // 0 1 0 1 : index[0] = 0 - // 1 X 1 x : index[1] = 1 - // 2 Y 2 y : index[2] = 3 - // 3 Z 3 .5 x^2 : index[3] = 4 - // 4 .5 X^2 4 .5 y^2 : index[4] = 6 - // 5 .5 Y^2 5 xy : index[5] = 8 - // 6 .5 Z^2 - // 7 XY - // 8 XZ - // 9 YZ - // - // If there are no fixed variables, index is of size (n+1)(n+2)/2 - // with index[i] = i. - - delete [] _index; - - _index = new int [_n_alpha]; - - int nm1 = _n - 1; - int c1 = 2*_n + 1; - int c2 = 1; - int k1 , k2; - - _index[0] = 0; - for ( i = 0 ; i < _n ; ++i ) { - if ( !_fixed_vars[i] ) { - _index[c2 ] = i+1; - _index[c2+_nfree] = i+1+_n; - ++c2; - } - } - - c2 += _nfree; - - for ( k1 = 0 ; k1 < nm1 ; ++k1 ) - for ( k2 = k1+1 ; k2 < _n ; ++k2 ) { - if ( !_fixed_vars[k1] && !_fixed_vars[k2] ) - _index[c2++] = c1; - ++c1; + _alpha[i] = ( _bbot[i] == NOMAD::OBJ || NOMAD::bbot_is_constraint(_bbot[i]) ) ? + new NOMAD::Point ( _n_alpha ) : NULL; + + // initialize _index: + // ------------------ + + // example: with 3 variables (X,Y,Z) with Y fixed. + // -------- + // the problem is reduced to the two variables x=X and y=Z, + // and _index is corresponds to: + // + // 0 1 0 1 : index[0] = 0 + // 1 X 1 x : index[1] = 1 + // 2 Y 2 y : index[2] = 3 + // 3 Z 3 .5 x^2 : index[3] = 4 + // 4 .5 X^2 4 .5 y^2 : index[4] = 6 + // 5 .5 Y^2 5 xy : index[5] = 8 + // 6 .5 Z^2 + // 7 XY + // 8 XZ + // 9 YZ + // + // If there are no fixed variables, index is of size (n+1)(n+2)/2 + // with index[i] = i. + + delete [] _index; + + _index = new int [_n_alpha]; + + int nm1 = _n - 1; + int c1 = 2*_n + 1; + int c2 = 1; + int k1 , k2; + + _index[0] = 0; + for ( i = 0 ; i < _n ; ++i ) + { + if ( !_fixed_vars[i] ) + { + _index[c2 ] = i+1; + _index[c2+_nfree] = i+1+_n; + ++c2; + } } + + c2 += _nfree; + + for ( k1 = 0 ; k1 < nm1 ; ++k1 ) + for ( k2 = k1+1 ; k2 < _n ; ++k2 ) + { + if ( !_fixed_vars[k1] && !_fixed_vars[k2] ) + _index[c2++] = c1; + ++c1; + } } /*---------------------------------------------------------*/ @@ -162,119 +166,125 @@ void NOMAD::Quad_Model::init_alpha ( void ) /* into an interpolation set (private) */ /*---------------------------------------------------------*/ bool NOMAD::Quad_Model::check_outputs ( const NOMAD::Point & bbo , int m ) const { - - if ( bbo.size() != m ) - return false; - - for ( int i = 0 ; i < m ; ++i ) - if ( !bbo[i].is_defined() || bbo[i].value() > NOMAD::MODEL_MAX_OUTPUT ) - return false; - - return true; + + if ( bbo.size() != m ) + return false; + + for ( int i = 0 ; i < m ; ++i ) + if ( !bbo[i].is_defined() || bbo[i].value() > NOMAD::MODEL_MAX_OUTPUT ) + return false; + + return true; } /*-----------------------------------------------------------*/ /* construct the interpolation set Y */ /*-----------------------------------------------------------*/ void NOMAD::Quad_Model::construct_Y ( const NOMAD::Point & center , - const NOMAD::Point & interpolation_radius , - int max_Y_size ) + const NOMAD::Point & interpolation_radius , + int max_Y_size ) { - _error_flag = true; - - if ( center.size() != _n || - interpolation_radius.size() != _n || - !center.is_complete() || - !interpolation_radius.is_complete() ) - return; - - _error_flag = false; - _center = center; - - int m = static_cast<int> ( _bbot.size() ); - - // browse the cache: - const NOMAD::Eval_Point * cur = _cache.begin(); - while ( cur ) - { - - if ( cur->get_eval_status() == NOMAD::EVAL_OK && - cur->get_n () == _n && - _signature.is_compatible (*cur) ) - { - - const NOMAD::Point & bbo = cur->get_bb_outputs(); - - if ( check_outputs ( bbo , m ) ) { - - // the center point has been found - // (it is put in first position): - if ( _center == *cur ) { - _Y.push_back ( new NOMAD::Eval_Point ( *cur ) ); - int nYm1 = get_nY() - 1; - if ( nYm1 > 0 ) { - NOMAD::Eval_Point * tmp = _Y[0]; - _Y[0 ] = _Y[nYm1]; - _Y[nYm1] = tmp; - } - } - - // other points must within the interpolation radius: - else if ( is_within_radius ( *cur , interpolation_radius ) ) - _Y.push_back ( new NOMAD::Eval_Point ( *cur ) ); - } + _error_flag = true; + + if ( center.size() != _n || + interpolation_radius.size() != _n || + !center.is_complete() || + !interpolation_radius.is_complete() ) + return; + + _error_flag = false; + _center = center; + + int m = static_cast<int> ( _bbot.size() ); + + // browse the cache: + const NOMAD::Eval_Point * cur = _cache.begin(); + while ( cur ) + { + + if ( cur->get_eval_status() == NOMAD::EVAL_OK && + cur->get_n () == _n && + _signature.is_compatible (*cur) ) + { + + const NOMAD::Point & bbo = cur->get_bb_outputs(); + + if ( check_outputs ( bbo , m ) ) + { + + // the center point has been found + // (it is put in first position): + if ( _center == *cur ) + { + _Y.push_back ( new NOMAD::Eval_Point ( *cur ) ); + int nYm1 = get_nY() - 1; + if ( nYm1 > 0 ) + { + NOMAD::Eval_Point * tmp = _Y[0]; + _Y[0 ] = _Y[nYm1]; + _Y[nYm1] = tmp; + } + } + + // other points must within the interpolation radius: + else if ( is_within_radius ( *cur , interpolation_radius ) ) + { + _Y.push_back ( new NOMAD::Eval_Point ( *cur ) ); + } + } + } + cur = _cache.next(); } - cur = _cache.next(); - } - - // respect the limit on the number of points: - if ( get_nY() > max_Y_size ) - reduce_Y ( center , max_Y_size ); + + // respect the limit on the number of points: + if ( get_nY() > max_Y_size ) + reduce_Y ( center , max_Y_size ); } /*-----------------------------------------------------------------*/ /* reduce the number of interpolation points */ /*-----------------------------------------------------------------*/ void NOMAD::Quad_Model::reduce_Y ( const NOMAD::Point & center , - int max_Y_size ) + int max_Y_size ) { - int nY = get_nY(); - - if ( nY <= max_Y_size ) - return; - - std::multiset<NOMAD::Model_Sorted_Point> Ys; - for ( int k = 0 ; k < nY ; ++k ) - Ys.insert ( NOMAD::Model_Sorted_Point ( _Y[k] , center ) ); - - _Y.clear(); - - std::multiset<NOMAD::Model_Sorted_Point>::const_iterator it , end = Ys.end(); - for ( it = Ys.begin() ; it != end ; ++it ) { - if ( get_nY() < max_Y_size ) - _Y.push_back ( static_cast<NOMAD::Eval_Point *> ( it->get_point() ) ); - else - delete it->get_point(); - } + int nY = get_nY(); + + if ( nY <= max_Y_size ) + return; + + std::multiset<NOMAD::Model_Sorted_Point> Ys; + for ( int k = 0 ; k < nY ; ++k ) + Ys.insert ( NOMAD::Model_Sorted_Point ( _Y[k] , center ) ); + + _Y.clear(); + + std::multiset<NOMAD::Model_Sorted_Point>::const_iterator it , end = Ys.end(); + for ( it = Ys.begin() ; it != end ; ++it ) { + if ( get_nY() < max_Y_size ) + _Y.push_back ( static_cast<NOMAD::Eval_Point *> ( it->get_point() ) ); + else + delete it->get_point(); + } } /*-----------------------------------------------------------*/ /* check if an unscaled point is in B(center,radius) for a */ /* given radius (private) */ /*-----------------------------------------------------------*/ -bool NOMAD::Quad_Model::is_within_radius ( const NOMAD::Point & x , - const NOMAD::Point & radius ) const +bool NOMAD::Quad_Model::is_within_radius ( const NOMAD::Point & x , + const NOMAD::Point & radius ) const { - if ( x.size() != _n || radius.size() != _n ) - return false; - - for ( int i = 0 ; i < _n ; ++i ) - if ( !x[i].is_defined() || - !radius[i].is_defined() || - radius[i] < ( x[i] - _center[i]).abs() ) - return false; - - return true; + if ( x.size() != _n || radius.size() != _n ) + return false; + + for ( int i = 0 ; i < _n ; ++i ) + { + if ( !x[i].is_defined() || + !radius[i].is_defined() || + radius[i] < ( x[i] - _center[i]).abs() ) + return false; + } + return true; } /*------------------------------------------------------*/ @@ -282,16 +292,16 @@ bool NOMAD::Quad_Model::is_within_radius ( const NOMAD::Point & x , /*------------------------------------------------------*/ bool NOMAD::Quad_Model::is_within_trust_radius ( const NOMAD::Point & x ) const { - // check that all scaled coordinates are in [-1;1] and - // that fixed variables are equal to zero: - for ( int i = 0 ; i < _n ; ++i ) - if ( !_ref [i].is_defined() || - !_scaling[i].is_defined() || - ! x[i].is_defined() || - x[i].abs() > 1.0 || - ( _fixed_vars[i] && x[i] != 0.0 ) ) - return false; - return true; + // check that all scaled coordinates are in [-1;1] and + // that fixed variables are equal to zero: + for ( int i = 0 ; i < _n ; ++i ) + if ( !_ref [i].is_defined() || + !_scaling[i].is_defined() || + ! x[i].is_defined() || + x[i].abs() > 1.0 || + ( _fixed_vars[i] && x[i] != 0.0 ) ) + return false; + return true; } /*--------------------------------------------------------------*/ @@ -300,253 +310,253 @@ bool NOMAD::Quad_Model::is_within_trust_radius ( const NOMAD::Point & x ) const /*--------------------------------------------------------------*/ void NOMAD::Quad_Model::define_scaling ( const NOMAD::Double & r ) { - if ( _error_flag || _Y.empty() ) { - _error_flag = true; - return; - } - - int i , k; - int nY = get_nY(); - NOMAD::Point min(_n) , max(_n); - NOMAD::Double tmp; - - // The parameters defining the scaling with rotation (see define_scaling_by_direction) are cleared. - // Only the parameters for the basic scaling are set - _dirP.clear(); - _epsilon.clear(); - _delta_m.clear(); - - - _scaling.clear(); - _ref.clear (); - _ref.reset ( _n ); - _scaling.reset ( _n ); - - // compute the reference (center of Y): - for ( k = 0 ; k < nY ; ++k ) - { - - if ( !_Y[k] || _n != _Y[k]->size() ) - { - _error_flag = true; - return; - } - - for ( i = 0 ; i < _n ; ++i ) - { - tmp = (*_Y[k])[i]; - if ( !min[i].is_defined() || tmp < min[i] ) - min[i] = tmp; - if ( !max[i].is_defined() || tmp > max[i] ) - max[i] = tmp; - } - } - - for ( i = 0 ; i < _n ; ++i ) - _ref[i] = ( min[i] + max[i] ) / 2.0; - + if ( _error_flag || _Y.empty() ) { + _error_flag = true; + return; + } + + int i , k; + int nY = get_nY(); + NOMAD::Point min(_n) , max(_n); + NOMAD::Double tmp; + + // The parameters defining the scaling with rotation (see define_scaling_by_direction) are cleared. + // Only the parameters for the basic scaling are set + _dirP.clear(); + _epsilon.clear(); + _delta_m.clear(); + + + _scaling.clear(); + _ref.clear (); + _ref.reset ( _n ); + _scaling.reset ( _n ); + + // compute the reference (center of Y): + for ( k = 0 ; k < nY ; ++k ) + { + + if ( !_Y[k] || _n != _Y[k]->size() ) + { + _error_flag = true; + return; + } + + for ( i = 0 ; i < _n ; ++i ) + { + tmp = (*_Y[k])[i]; + if ( !min[i].is_defined() || tmp < min[i] ) + min[i] = tmp; + if ( !max[i].is_defined() || tmp > max[i] ) + max[i] = tmp; + } + } + + for ( i = 0 ; i < _n ; ++i ) + _ref[i] = ( min[i] + max[i] ) / 2.0; + #ifdef MODEL_STATS - _Yw = NOMAD::Double(); - for ( i = 0 ; i < _n ; ++i ) - { - tmp = max[i]-min[i]; - if ( !_Yw.is_defined() || tmp > _Yw ) - _Yw = tmp; - } + _Yw = NOMAD::Double(); + for ( i = 0 ; i < _n ; ++i ) + { + tmp = max[i]-min[i]; + if ( !_Yw.is_defined() || tmp > _Yw ) + _Yw = tmp; + } #endif - + #ifdef DEBUG - _out << std::endl - << "define_scaling(): reference = ( " << _ref << " )" << std::endl; + _out << std::endl + << "define_scaling(): reference = ( " << _ref << " )" << std::endl; #endif - - // compute the scaling (and detect fixed variables): - for ( k = 0 ; k < nY ; ++k ) { - - for ( i = 0 ; i < _n ; ++i ) { - tmp = ( (*_Y[k])[i] - _ref[i] ).abs(); - if ( !_scaling[i].is_defined() || _scaling[i] < tmp ) - _scaling[i] = tmp; + + // compute the scaling (and detect fixed variables): + for ( k = 0 ; k < nY ; ++k ) { + + for ( i = 0 ; i < _n ; ++i ) { + tmp = ( (*_Y[k])[i] - _ref[i] ).abs(); + if ( !_scaling[i].is_defined() || _scaling[i] < tmp ) + _scaling[i] = tmp; + } } - } - - _nfree = _n; - - for ( i = 0 ; i < _n ; ++i ) - { - if ( _scaling[i] == 0.0 ) - { - _scaling [i] = 0.0; - _fixed_vars[i] = true; - --_nfree; - if ( _nfree == 0 ) - { - _scaling.clear(); - _ref.clear(); - _error_flag = true; - return; - } - } - else - _scaling[i] *= 1.0/r; // all coordinates in [-r;r] - } - - if ( _nfree < _n ) - init_alpha(); - - for ( k = 0 ; k < nY ; ++k ) - { - if ( !scale ( *_Y[k] ) ) - { - _scaling.clear(); - _error_flag = true; - return; - } - } - + + _nfree = _n; + + for ( i = 0 ; i < _n ; ++i ) + { + if ( _scaling[i] == 0.0 ) + { + _scaling [i] = 0.0; + _fixed_vars[i] = true; + --_nfree; + if ( _nfree == 0 ) + { + _scaling.clear(); + _ref.clear(); + _error_flag = true; + return; + } + } + else + _scaling[i] *= 1.0/r; // all coordinates in [-r;r] + } + + if ( _nfree < _n ) + init_alpha(); + + for ( k = 0 ; k < nY ; ++k ) + { + if ( !scale ( *_Y[k] ) ) + { + _scaling.clear(); + _error_flag = true; + return; + } + } + #ifdef DEBUG - _out << "define_scaling(): scaling = ( " << _scaling << " )" << std::endl; + _out << "define_scaling(): scaling = ( " << _scaling << " )" << std::endl; #endif - - _error_flag = false; + + _error_flag = false; } - + /*-------------------------------------------------------------------*/ /* . Scaling with rotation based on a set of directions. */ /* See paper: */ /* Reducing the number of function evaluations in */ /* Mesh Adaptive Direct Search algorithms, Audet, Ianni, */ -/* LeDigabel, Tribes, 2012 */ +/* LeDigabel, Tribes, 2014 */ /* . looks also for fixed variables */ /*-------------------------------------------------------------------*/ void NOMAD::Quad_Model::define_scaling_by_directions ( const std::list<NOMAD::Direction> & dirs, const NOMAD::Point & delta_m, const NOMAD::Double & epsilon ) { - if ( _error_flag || _Y.empty() ) { - _error_flag = true; - return; - } - - int i , k; - int nY = get_nY(); - NOMAD::Point min(_n) , max(_n); - NOMAD::Double tmp; - - - // The parameters defining the basic scaling (see define_scaling) are cleared. - // Only the parameters for the direction scaling are set - _scaling.clear(); - _ref.clear (); - - // For direction scaling - if (static_cast<int> (dirs.size())!=_n || static_cast<int>(delta_m.size()) != _n || epsilon<=0.0 || epsilon>=1) - { - _error_flag = true; - return; - } - _delta_m=delta_m; - // Get D' from dirs (scaling with delta_m - std::list<NOMAD::Direction>::const_iterator itDir; - for (itDir=dirs.begin(); itDir != dirs.end(); itDir++) - { - NOMAD::Direction dir_i(_n,0.0,itDir->get_type()); - dir_i.set_index(itDir->get_index()); - for ( int i = 0 ; i < _n ; ++i ) - { - if (_delta_m[i]<=0.0) - { - _error_flag=true; - return; - } - dir_i[i]=(*itDir)[i]/_delta_m[i]; - } - _dirP.push_back(dir_i); - } - - _epsilon=epsilon; - - - // compute the min and the max: - for ( k = 0 ; k < nY ; ++k ) - { - - if ( !_Y[k] || _n != _Y[k]->size() ) - { - _error_flag = true; - return; - } - - for ( i = 0 ; i < _n ; ++i ) - { - tmp = (*_Y[k])[i]; - if ( !min[i].is_defined() || tmp < min[i] ) - min[i] = tmp; - if ( !max[i].is_defined() || tmp > max[i] ) - max[i] = tmp; - } - } - + if ( _error_flag || _Y.empty() ) { + _error_flag = true; + return; + } + + int i , k; + int nY = get_nY(); + NOMAD::Point min(_n) , max(_n); + NOMAD::Double tmp; + + + // The parameters defining the basic scaling (see define_scaling) are cleared. + // Only the parameters for the direction scaling are set + _scaling.clear(); + _ref.clear (); + + // For direction scaling + if (static_cast<int> (dirs.size())!=_n || static_cast<int>(delta_m.size()) != _n || epsilon<=0.0 || epsilon>=1) + { + _error_flag = true; + return; + } + _delta_m=delta_m; + // Get D' from dirs (scaling with delta_m + std::list<NOMAD::Direction>::const_iterator itDir; + for (itDir=dirs.begin(); itDir != dirs.end(); itDir++) + { + NOMAD::Direction dir_i(_n,0.0,itDir->get_type()); + dir_i.set_index(itDir->get_index()); + for ( int i = 0 ; i < _n ; ++i ) + { + if (_delta_m[i]<=0.0) + { + _error_flag=true; + return; + } + dir_i[i]=(*itDir)[i]/_delta_m[i]; + } + _dirP.push_back(dir_i); + } + + _epsilon=epsilon; + + + // compute the min and the max: + for ( k = 0 ; k < nY ; ++k ) + { + + if ( !_Y[k] || _n != _Y[k]->size() ) + { + _error_flag = true; + return; + } + + for ( i = 0 ; i < _n ; ++i ) + { + tmp = (*_Y[k])[i]; + if ( !min[i].is_defined() || tmp < min[i] ) + min[i] = tmp; + if ( !max[i].is_defined() || tmp > max[i] ) + max[i] = tmp; + } + } + #ifdef MODEL_STATS - _Yw = NOMAD::Double(); - for ( i = 0 ; i < _n ; ++i ) - { - tmp = max[i]-min[i]; - if ( !_Yw.is_defined() || tmp > _Yw ) - _Yw = tmp; - } + _Yw = NOMAD::Double(); + for ( i = 0 ; i < _n ; ++i ) + { + tmp = max[i]-min[i]; + if ( !_Yw.is_defined() || tmp > _Yw ) + _Yw = tmp; + } #endif - - // Detect fixed variables: - _nfree = _n; - for ( i = 0 ; i < _n ; ++i ) - { - bool fixed_var_i=true; - for ( k = 0 ; k < nY ; ++k ) - { - if ( ( (*_Y[k])[i] - _center[i] ).abs() > 0.0 ) - { - fixed_var_i=false; - break; - } - } - _fixed_vars[i]=fixed_var_i; - if (fixed_var_i) - --_nfree; - - if ( _nfree == 0 ) - { - _scaling.clear(); - _ref.clear(); - _dirP.clear(); - _error_flag = true; - return; - } - } - if ( _nfree < _n ) - init_alpha(); - - // Perform scaling of Y - for ( k = 0 ; k < nY ; ++k ) - { - if ( !scale ( *_Y[k] ) ) - { - _scaling.clear(); - _dirP.clear(); - _error_flag = true; - return; - } - } - + + // Detect fixed variables: + _nfree = _n; + for ( i = 0 ; i < _n ; ++i ) + { + bool fixed_var_i=true; + for ( k = 0 ; k < nY ; ++k ) + { + if ( ( (*_Y[k])[i] - _center[i] ).abs() > 0.0 ) + { + fixed_var_i=false; + break; + } + } + _fixed_vars[i]=fixed_var_i; + if (fixed_var_i) + --_nfree; + + if ( _nfree == 0 ) + { + _scaling.clear(); + _ref.clear(); + _dirP.clear(); + _error_flag = true; + return; + } + } + if ( _nfree < _n ) + init_alpha(); + + // Perform scaling of Y + for ( k = 0 ; k < nY ; ++k ) + { + if ( !scale ( *_Y[k] ) ) + { + _scaling.clear(); + _dirP.clear(); + _error_flag = true; + return; + } + } + #ifdef DEBUG - _out << "define_scaling_by_direction(): " << std::endl; - for ( itDir = _dirP.begin() ; itDir != _dirP.end() ; ++itDir ) - { - _out << "dirPrime "; - _out.display_int_w ( (*itDir).get_index() , _dirP.size() ); - _out << " : " << *itDir << std::endl; - } + _out << "define_scaling_by_direction(): " << std::endl; + for ( itDir = _dirP.begin() ; itDir != _dirP.end() ; ++itDir ) + { + _out << "dirPrime "; + _out.display_int_w ( (*itDir).get_index() , static_cast<int>(_dirP.size()) ); + _out << " : " << *itDir << std::endl; + } #endif - - _error_flag = false; + + _error_flag = false; } @@ -555,55 +565,55 @@ void NOMAD::Quad_Model::define_scaling_by_directions ( const std::list<NOMAD::Di /*--------------------------------------------------------------*/ bool NOMAD::Quad_Model::scale ( NOMAD::Point & x ) const { - if ( _error_flag || _n != x.size() ) - return false; - - if (_dirP.size()==0) - { - // Scale without rotation - for ( int i = 0 ; i < _n ; ++i ) - { - if ( !_ref [i].is_defined() || - !_scaling[i].is_defined() || - ! x[i].is_defined() ) - return false; - x[i] -= _ref[i]; - if ( _scaling[i] != 0 ) - x[i] /= _scaling[i]; - } - } - else - { - if (! _epsilon.is_defined() || !_delta_m.is_complete()) - return false; - // Scale with rotation based on direction and center (see paper Reducing the number of function evaluations in Mesh Adaptive Direct Search algorithms, Audet, Ianni, LeDigabel, Tribes, 2012 - // T(y)=(D')^-1*(center-x)/delta_m/(1-epsilon) - epsilon*1/(1-epsilon) - // (D')^-1=(D')^T/normCol^2 - NOMAD::Point temp(_n,0.0); - double normCol2=0.0; - std::list<NOMAD::Direction>::const_iterator itDir=_dirP.begin(); - for ( int i = 0 ; i < _n ; ++i ) - { - normCol2+=pow((*itDir)[i].value(),2); - - if (_delta_m[i] !=0.0) - temp[i]=(_center[i]-x[i])/_delta_m[i]/(1-_epsilon); - else - return false; - x[i]=0.0; - } - int j=0; - for (itDir=_dirP.begin(); itDir != _dirP.end(); itDir++,j++) - { - for ( int i = 0 ; i < _n ; ++i ) - { - x[j]+=temp[i]*(*itDir)[i]/normCol2; - } - x[j]-=_epsilon/(1.0-_epsilon); - } - } - - return true; + if ( _error_flag || _n != x.size() ) + return false; + + if (_dirP.size()==0) + { + // Scale without rotation + for ( int i = 0 ; i < _n ; ++i ) + { + if ( !_ref [i].is_defined() || + !_scaling[i].is_defined() || + ! x[i].is_defined() ) + return false; + x[i] -= _ref[i]; + if ( _scaling[i] != 0 ) + x[i] /= _scaling[i]; + } + } + else + { + if (! _epsilon.is_defined() || !_delta_m.is_complete()) + return false; + // Scale with rotation based on direction and center (see paper Reducing the number of function evaluations in Mesh Adaptive Direct Search algorithms, Audet, Ianni, LeDigabel, Tribes, 2014 + // T(y)=(D')^-1*(center-x)/delta_m/(1-epsilon) - epsilon*1/(1-epsilon) + // (D')^-1=(D')^T/normCol^2 + NOMAD::Point temp(_n,0.0); + NOMAD::Double normCol2=0.0; + std::list<NOMAD::Direction>::const_iterator itDir=_dirP.begin(); + for ( int i = 0 ; i < _n ; ++i ) + { + normCol2+=pow((*itDir)[i].value(),2.0); + + if (_delta_m[i] !=0.0) + temp[i]=(_center[i].value()-x[i].value())/_delta_m[i].value()/(1.0-_epsilon.value()); + else + return false; + x[i]=0.0; + } + int j=0; + for (itDir=_dirP.begin(); itDir != _dirP.end(); itDir++,j++) + { + for ( int i = 0 ; i < _n ; ++i ) + { + x[j]+=temp[i].value()*(*itDir)[i].value()/normCol2.value(); + } + x[j]-=_epsilon.value()/(1.0-_epsilon.value()); + } + } + + return true; } /*-----------------------------------------------------------*/ @@ -611,53 +621,53 @@ bool NOMAD::Quad_Model::scale ( NOMAD::Point & x ) const /*-----------------------------------------------------------*/ bool NOMAD::Quad_Model::unscale ( NOMAD::Point & x ) const { - if ( _error_flag || _n != x.size() ) - return false; - - if (_dirP.size()==0) - { - // Scale without rotation - for ( int i = 0 ; i < _n ; ++i ) - { - if ( !_ref [i].is_defined() || - !_scaling[i].is_defined() || - ! x[i].is_defined() ) - return false; - - x[i] *= _scaling[i]; - x[i] += _ref [i]; - } - } - else - { - - if (! _epsilon.is_defined() || !_delta_m.is_complete()) - return false; - - // UnScale with rotation see paper Reducing the number of function evaluations in Mesh Adaptive Direct Search algorithms, Audet, Ianni, LeDigabel, Tribes, 2012 - //T^−1(x) = center+ _delta_m Dp ((ε−1)x−ε1) - NOMAD::Point temp(_n,0.0); - for ( int i = 0 ; i < _n ; ++i ) - { - temp[i]=(x[i]*(_epsilon-1.0)-_epsilon)*_delta_m[i]; - x[i]=0.0; - } - std::list<NOMAD::Direction>::const_iterator itDir; - int j=0; - for (itDir=_dirP.begin(); itDir != _dirP.end(); itDir++,j++) - { - for (int i=0 ; i< _n ; i++) - { - x[i]+=temp[j]*(*itDir)[i]; - } - } - for ( int i = 0 ; i < _n ; ++i ) - { - x[i]+=_center[i]; - } - } - - return true; + if ( _error_flag || _n != x.size() ) + return false; + + if (_dirP.size()==0) + { + // Scale without rotation + for ( int i = 0 ; i < _n ; ++i ) + { + if ( !_ref [i].is_defined() || + !_scaling[i].is_defined() || + ! x[i].is_defined() ) + return false; + + x[i] *= _scaling[i]; + x[i] += _ref [i]; + } + } + else + { + + if (! _epsilon.is_defined() || !_delta_m.is_complete()) + return false; + + // UnScale with rotation see paper Reducing the number of function evaluations in Mesh Adaptive Direct Search algorithms, Audet, Ianni, LeDigabel, Tribes, 2014 + //T^−1(x) = center+ _delta_m Dp ((ε−1)x−ε1) + NOMAD::Point temp(_n,0.0); + for ( int i = 0 ; i < _n ; ++i ) + { + temp[i]=(x[i]*(_epsilon-1.0)-_epsilon)*_delta_m[i]; + x[i]=0.0; + } + std::list<NOMAD::Direction>::const_iterator itDir; + int j=0; + for (itDir=_dirP.begin(); itDir != _dirP.end(); itDir++,j++) + { + for (int i=0 ; i< _n ; i++) + { + x[i]+=temp[j]*(*itDir)[i]; + } + } + for ( int i = 0 ; i < _n ; ++i ) + { + x[i]+=_center[i]; + } + } + + return true; } /*-----------------------------------------------------------*/ @@ -665,19 +675,19 @@ bool NOMAD::Quad_Model::unscale ( NOMAD::Point & x ) const /*-----------------------------------------------------------*/ bool NOMAD::Quad_Model::unscale_grad ( NOMAD::Point & x ) const { - if ( _error_flag || _n != x.size() ) - return false; - - for ( int i = 0 ; i < _n ; ++i ) - { - - if (!_scaling[i].is_defined() || !x[i].is_defined() ) - return false; - - x[i] *= _scaling[i]; - } - - return true; + if ( _error_flag || _n != x.size() ) + return false; + + for ( int i = 0 ; i < _n ; ++i ) + { + + if (!_scaling[i].is_defined() || !x[i].is_defined() ) + return false; + + x[i] *= _scaling[i]; + } + + return true; } /*------------------------------------------------------------------*/ @@ -685,73 +695,73 @@ bool NOMAD::Quad_Model::unscale_grad ( NOMAD::Point & x ) const /* (private) */ /*------------------------------------------------------------------*/ double NOMAD::Quad_Model::compute_M ( int i , int j ) const { - - if ( _error_flag ) - return 0.0; - - if ( j == 0 ) - return 1.0; - - if ( j <= _nfree ) - return (*_Y[i])[_index[j]-1].value(); - - if ( j <= 2 * _nfree ) - return 0.5 * pow ( (*_Y[i])[_index[j-_nfree]-1].value() , 2.0 ); - - int nm1 = _nfree - 1; - int jm2n , dec , r , i1 , i2; - - jm2n = j - 2 * _nfree; - dec = nm1; - r = jm2n; - i1 = -1; - - while ( r > 0 ) { - r -= dec; - ++i1; - --dec; - } - - i2 = r + nm1; - - return (*_Y[i])[_index[i1+1]-1].value() * (*_Y[i])[_index[i2+1]-1].value(); + + if ( _error_flag ) + return 0.0; + + if ( j == 0 ) + return 1.0; + + if ( j <= _nfree ) + return (*_Y[i])[_index[j]-1].value(); + + if ( j <= 2 * _nfree ) + return 0.5 * pow ( (*_Y[i])[_index[j-_nfree]-1].value() , 2.0 ); + + int nm1 = _nfree - 1; + int jm2n , dec , r , i1 , i2; + + jm2n = j - 2 * _nfree; + dec = nm1; + r = jm2n; + i1 = -1; + + while ( r > 0 ) { + r -= dec; + ++i1; + --dec; + } + + i2 = r + nm1; + + return (*_Y[i])[_index[i1+1]-1].value() * (*_Y[i])[_index[i2+1]-1].value(); } /*-----------------------------------------------------------*/ /* construct m models (one by output) */ /*-----------------------------------------------------------*/ void NOMAD::Quad_Model::construct ( bool use_WP , - double eps , - int max_mpn , - int max_Y_size ) + double eps , + int max_mpn , + int max_Y_size ) { - if ( _error_flag ) - return; - - int p1 = get_nY(); - - - // MFN interpolation: - if ( p1 < _n_alpha ) { - _interpolation_type = NOMAD::MFN; - _error_flag = !construct_MFN_model ( eps , max_mpn , max_Y_size ); - } - else { - - _error_flag = true; - - // well-poised regression: - if ( use_WP && p1 > _n_alpha ) { - _interpolation_type = NOMAD::WP_REGRESSION; - _error_flag = !construct_WP_model ( max_Y_size ); + if ( _error_flag ) + return; + + int p1 = get_nY(); + + + // MFN interpolation: + if ( p1 < _n_alpha ) { + _interpolation_type = NOMAD::MFN; + _error_flag = !construct_MFN_model ( eps , max_mpn , max_Y_size ); } - - // regression: - if ( _error_flag ) { - _interpolation_type = NOMAD::REGRESSION; - _error_flag = !construct_regression_model ( eps , max_mpn , max_Y_size ); + else { + + _error_flag = true; + + // well-poised regression: + if ( use_WP && p1 > _n_alpha ) { + _interpolation_type = NOMAD::WP_REGRESSION; + _error_flag = !construct_WP_model ( max_Y_size ); + } + + // regression: + if ( _error_flag ) { + _interpolation_type = NOMAD::REGRESSION; + _error_flag = !construct_regression_model ( eps , max_mpn , max_Y_size ); + } } - } } /*---------------------------------------------------------------*/ @@ -763,27 +773,27 @@ void NOMAD::Quad_Model::construct ( bool use_WP , /*---------------------------------------------------------------*/ int NOMAD::Quad_Model::find_max_lix ( const NOMAD::Point & li , - const std::vector<NOMAD::Eval_Point *> & Y , - int i1 , - int i2 , - NOMAD::Double & max_lix ) const + const std::vector<NOMAD::Eval_Point *> & Y , + int i1 , + int i2 , + NOMAD::Double & max_lix ) const { - max_lix = -1.0; - int ji = -1; - NOMAD::Double tmp; - for ( int j = i1 ; j <= i2 ; ++j ) { - tmp = eval ( *Y[j] , li ); - if ( tmp.is_defined() ) { - tmp = tmp.abs(); - if ( tmp > max_lix ) { - max_lix = tmp; - ji = j; - } - } - } - if ( ji < 0 ) - max_lix.clear(); - return ji; + max_lix = -1.0; + int ji = -1; + NOMAD::Double tmp; + for ( int j = i1 ; j <= i2 ; ++j ) { + tmp = eval ( *Y[j] , li ); + if ( tmp.is_defined() ) { + tmp = tmp.abs(); + if ( tmp > max_lix ) { + max_lix = tmp; + ji = j; + } + } + } + if ( ji < 0 ) + max_lix.clear(); + return ji; } /*-----------------------------------------------------------*/ @@ -791,378 +801,378 @@ int NOMAD::Quad_Model::find_max_lix /*-----------------------------------------------------------*/ bool NOMAD::Quad_Model::construct_WP_model ( int max_Y_size ) { - -#ifdef DEBUG - _out << std::endl - << NOMAD::open_block ( "NOMAD::Quad_Model::construct_WP_model()" ); -#endif - - // check the set Y: - if ( !check_Y() ) - return false; - - int i , j , k , p1 = get_nY(); - - // the number of points (p+1) must be in [1+(n+1)(n+2)/2;MS_MAX_Y_SIZE]: - if ( p1 <= _n_alpha || p1 > max_Y_size ) { + #ifdef DEBUG _out << std::endl - << "NOMAD::Quad_Model::construct_WP_model(): " - << "(p+1) not in [1+(n+1)(n+2)/2;" << max_Y_size << "]" - << std::endl << NOMAD::close_block() << std::endl; + << NOMAD::open_block ( "NOMAD::Quad_Model::construct_WP_model()" ); #endif - return false; - } - - // Lagrange polynomials: - std::vector<NOMAD::Point *> l; - for ( i = 0 ; i < _n_alpha ; ++i ) { - l.push_back ( new NOMAD::Point ( _n_alpha ) ); - for ( j = 0 ; j < _n_alpha ; ++j ) - (*l[i])[j] = (i==j) ? 1.0 : 0.0; - } - - // creation of sets Y1 and Y2; Y2 contains all available points - // of _Y and Y1 will be the 'well-poised' set with n_alpha points: - std::vector<NOMAD::Eval_Point *> Y1 , Y2 = _Y; - int iy2 , ny2m1 = p1-1; - NOMAD::Double max_lix , liyi , ljyi; - - // we init Y1 with the first point of Y: - Y1.push_back ( Y2[0] ); - Y2[0] = Y2[ny2m1]; - Y2.resize ( ny2m1 ); - - // use algo 6.2 p.95 of the DFO book in order to construct Lagrange polynomials: - // ----------------------------------------------------------------------------- - for ( i = 0 ; i < _n_alpha ; ++i ) { - - // 1. point selection (select a point in Y2: Y2[iy2]): - // ------------------- - if ( i > 0 ) { - - ny2m1 = static_cast<int>(Y2.size())-1; - iy2 = find_max_lix ( *l[i] , Y2 , 0 , ny2m1 , max_lix ); - - if ( iy2 < 0 ) { + + // check the set Y: + if ( !check_Y() ) + return false; + + int i , j , k , p1 = get_nY(); + + // the number of points (p+1) must be in [1+(n+1)(n+2)/2;MS_MAX_Y_SIZE]: + if ( p1 <= _n_alpha || p1 > max_Y_size ) { #ifdef DEBUG - _out << std::endl - << "NOMAD::Quad_Model::construct_WP_model(): " - << "cannot find candidate in Y" - << std::endl << NOMAD::close_block() << std::endl; + _out << std::endl + << "NOMAD::Quad_Model::construct_WP_model(): " + << "(p+1) not in [1+(n+1)(n+2)/2;" << max_Y_size << "]" + << std::endl << NOMAD::close_block() << std::endl; #endif - for ( i = 0 ; i < _n_alpha ; ++i ) - delete l[i]; - return false; - } - - // add Y2[iy2] in Y1: - Y1.push_back ( Y2[iy2] ); - Y2[iy2] = Y2[ny2m1]; - Y2.resize (ny2m1); + return false; } - - // 2. normalization: - // ----------------- - liyi = eval ( *Y1[i] , *l[i] ); - - if ( liyi.abs().value() < 1e-15 ) { + + // Lagrange polynomials: + std::vector<NOMAD::Point *> l; + for ( i = 0 ; i < _n_alpha ; ++i ) { + l.push_back ( new NOMAD::Point ( _n_alpha ) ); + for ( j = 0 ; j < _n_alpha ; ++j ) + (*l[i])[j] = (i==j) ? 1.0 : 0.0; + } + + // creation of sets Y1 and Y2; Y2 contains all available points + // of _Y and Y1 will be the 'well-poised' set with n_alpha points: + std::vector<NOMAD::Eval_Point *> Y1 , Y2 = _Y; + int iy2 , ny2m1 = p1-1; + NOMAD::Double max_lix , liyi , ljyi; + + // we init Y1 with the first point of Y: + Y1.push_back ( Y2[0] ); + Y2[0] = Y2[ny2m1]; + Y2.resize ( ny2m1 ); + + // use algo 6.2 p.95 of the DFO book in order to construct Lagrange polynomials: + // ----------------------------------------------------------------------------- + for ( i = 0 ; i < _n_alpha ; ++i ) { + + // 1. point selection (select a point in Y2: Y2[iy2]): + // ------------------- + if ( i > 0 ) { + + ny2m1 = static_cast<int>(Y2.size())-1; + iy2 = find_max_lix ( *l[i] , Y2 , 0 , ny2m1 , max_lix ); + + if ( iy2 < 0 ) { #ifdef DEBUG - _out << std::endl - << "NOMAD::Quad_Model::construct_WP_model(): set Y is not poised" - << std::endl << NOMAD::close_block() << std::endl; + _out << std::endl + << "NOMAD::Quad_Model::construct_WP_model(): " + << "cannot find candidate in Y" + << std::endl << NOMAD::close_block() << std::endl; #endif - for ( i = 0 ; i < _n_alpha ; ++i ) - delete l[i]; - return false; - } - - for ( k = 0 ; k < _n_alpha ; ++k ) { - (*l[i])[k] /= liyi; - if ( (*l[i])[k].abs().value() < 1e-15 ) - (*l[i])[k] = 0.0; - } - - // 3. orthogonalization: - // --------------------- - for ( j = 0 ; j < _n_alpha ; ++j ) - if ( j != i ) { - ljyi = eval ( *Y1[i] , *l[j] ); - for ( k = 0 ; k < _n_alpha ; ++k ) { - (*l[j])[k] = (*l[j])[k] - ljyi * (*l[i])[k]; - if ( (*l[j])[k].abs().value() < 1e-15 ) - (*l[j])[k] = 0.0; - } - } - } - + for ( i = 0 ; i < _n_alpha ; ++i ) + delete l[i]; + return false; + } + + // add Y2[iy2] in Y1: + Y1.push_back ( Y2[iy2] ); + Y2[iy2] = Y2[ny2m1]; + Y2.resize (ny2m1); + } + + // 2. normalization: + // ----------------- + liyi = eval ( *Y1[i] , *l[i] ); + + if ( liyi.abs().value() < 1e-15 ) { #ifdef DEBUG - display_lagrange_polynomials ( l , Y1 ); + _out << std::endl + << "NOMAD::Quad_Model::construct_WP_model(): set Y is not poised" + << std::endl << NOMAD::close_block() << std::endl; #endif - - // compute alpha: - // -------------- - int m = static_cast<int> ( _bbot.size() ); - for ( i = 0 ; i < m ; ++i ) - if ( _alpha[i] ) { - for ( j = 0 ; j < _n_alpha ; ++j ) { - (*_alpha[i])[j] = 0.0; - for ( k = 0 ; k < _n_alpha ; ++k ) - (*_alpha[i])[j] += Y1[k]->get_bb_outputs()[i] * (*l[k])[j]; - } + for ( i = 0 ; i < _n_alpha ; ++i ) + delete l[i]; + return false; + } + + for ( k = 0 ; k < _n_alpha ; ++k ) { + (*l[i])[k] /= liyi; + if ( (*l[i])[k].abs().value() < 1e-15 ) + (*l[i])[k] = 0.0; + } + + // 3. orthogonalization: + // --------------------- + for ( j = 0 ; j < _n_alpha ; ++j ) + if ( j != i ) { + ljyi = eval ( *Y1[i] , *l[j] ); + for ( k = 0 ; k < _n_alpha ; ++k ) { + (*l[j])[k] = (*l[j])[k] - ljyi * (*l[i])[k]; + if ( (*l[j])[k].abs().value() < 1e-15 ) + (*l[j])[k] = 0.0; + } + } } - - // poisedness improvement using algorithm 6.3 page 95: - // --------------------------------------------------- - - // old alpha: - NOMAD::Point ** old_alpha = new NOMAD::Point * [m] , ** tmp_alpha; - for ( i = 0 ; i < m ; ++i ) - old_alpha[i] = ( _alpha[i] ) ? - new NOMAD::Point ( _n_alpha ) : NULL; - - int ik; - NOMAD::Double ljyk , lkyk , lix , new_rel_err , - cur_rel_err = compute_max_rel_err(); - - if ( cur_rel_err.is_defined() && cur_rel_err.value() > 1e-15 ) { - - for ( int niter = 0 ; niter < 10 ; ++niter ) { - - ny2m1 = static_cast<int>(Y2.size())-1; - - if ( ny2m1 < 0 ) - break; - - max_lix = -1.0; - iy2 = -1; - ik = -1; - - for ( i = 0 ; i < _n_alpha ; ++i ) { - - j = find_max_lix ( *l[i] , Y2 , 0 , ny2m1 , lix ); - if ( j >= 0 && lix > max_lix ) { - max_lix = lix; - iy2 = j; - ik = i; - } - } - - if ( ik < 0 ) - break; - - // set Y1[ik] = Y2[iy2]: - Y1[ik ] = Y2[iy2]; - Y2[iy2] = Y2[ny2m1]; - Y2.resize ( ny2m1 ); - - lkyk = eval ( *Y1[ik] , *l[ik] ); - - if ( lkyk.abs() <= 1e-15 ) - break; - - // update Lagrange polynomials: - // ---------------------------- - - // normalization and orthogonalization: - for ( i = 0 ; i < _n_alpha ; ++i ) - (*l[ik])[i] /= lkyk; - - for ( j = 0 ; j < _n_alpha ; ++j ) { - if ( j != ik ) { - ljyk = eval ( *Y1[ik] , *l[j] ); - for ( i = 0 ; i < _n_alpha ; ++i ) - (*l[j])[i] = (*l[j])[i] - ljyk * (*l[ik])[i]; - } - } - - // save old alpha and compute new one: - for ( i = 0 ; i < m ; ++i ) - if ( _alpha[i] ) { - *(old_alpha[i]) = *(_alpha[i]); - for ( j = 0 ; j < _n_alpha ; ++j ) { - (*_alpha[i])[j] = 0.0; - for ( k = 0 ; k < _n_alpha ; ++k ) - (*_alpha[i])[j] += Y1[k]->get_bb_outputs()[i] * (*l[k])[j]; - } - } - - // compute new error: - new_rel_err = compute_max_rel_err(); - - // if no better error, restore old alpha and exit loop: - if ( !new_rel_err.is_defined() || new_rel_err >= cur_rel_err ) { - tmp_alpha = _alpha; - _alpha = old_alpha; - old_alpha = tmp_alpha; - break; - } - - cur_rel_err = new_rel_err; + +#ifdef DEBUG + display_lagrange_polynomials ( l , Y1 ); +#endif + + // compute alpha: + // -------------- + int m = static_cast<int> ( _bbot.size() ); + for ( i = 0 ; i < m ; ++i ) + if ( _alpha[i] ) { + for ( j = 0 ; j < _n_alpha ; ++j ) { + (*_alpha[i])[j] = 0.0; + for ( k = 0 ; k < _n_alpha ; ++k ) + (*_alpha[i])[j] += Y1[k]->get_bb_outputs()[i] * (*l[k])[j]; + } + } + + // poisedness improvement using algorithm 6.3 page 95: + // --------------------------------------------------- + + // old alpha: + NOMAD::Point ** old_alpha = new NOMAD::Point * [m] , ** tmp_alpha; + for ( i = 0 ; i < m ; ++i ) + old_alpha[i] = ( _alpha[i] ) ? + new NOMAD::Point ( _n_alpha ) : NULL; + + int ik; + NOMAD::Double ljyk , lkyk , lix , new_rel_err , + cur_rel_err = compute_max_rel_err(); + + if ( cur_rel_err.is_defined() && cur_rel_err.value() > 1e-15 ) { + + for ( int niter = 0 ; niter < 10 ; ++niter ) { + + ny2m1 = static_cast<int>(Y2.size())-1; + + if ( ny2m1 < 0 ) + break; + + max_lix = -1.0; + iy2 = -1; + ik = -1; + + for ( i = 0 ; i < _n_alpha ; ++i ) { + + j = find_max_lix ( *l[i] , Y2 , 0 , ny2m1 , lix ); + if ( j >= 0 && lix > max_lix ) { + max_lix = lix; + iy2 = j; + ik = i; + } + } + + if ( ik < 0 ) + break; + + // set Y1[ik] = Y2[iy2]: + Y1[ik ] = Y2[iy2]; + Y2[iy2] = Y2[ny2m1]; + Y2.resize ( ny2m1 ); + + lkyk = eval ( *Y1[ik] , *l[ik] ); + + if ( lkyk.abs() <= 1e-15 ) + break; + + // update Lagrange polynomials: + // ---------------------------- + + // normalization and orthogonalization: + for ( i = 0 ; i < _n_alpha ; ++i ) + (*l[ik])[i] /= lkyk; + + for ( j = 0 ; j < _n_alpha ; ++j ) { + if ( j != ik ) { + ljyk = eval ( *Y1[ik] , *l[j] ); + for ( i = 0 ; i < _n_alpha ; ++i ) + (*l[j])[i] = (*l[j])[i] - ljyk * (*l[ik])[i]; + } + } + + // save old alpha and compute new one: + for ( i = 0 ; i < m ; ++i ) + if ( _alpha[i] ) { + *(old_alpha[i]) = *(_alpha[i]); + for ( j = 0 ; j < _n_alpha ; ++j ) { + (*_alpha[i])[j] = 0.0; + for ( k = 0 ; k < _n_alpha ; ++k ) + (*_alpha[i])[j] += Y1[k]->get_bb_outputs()[i] * (*l[k])[j]; + } + } + + // compute new error: + new_rel_err = compute_max_rel_err(); + + // if no better error, restore old alpha and exit loop: + if ( !new_rel_err.is_defined() || new_rel_err >= cur_rel_err ) { + tmp_alpha = _alpha; + _alpha = old_alpha; + old_alpha = tmp_alpha; + break; + } + + cur_rel_err = new_rel_err; + } } - } - - for ( i = 0 ; i < m ; ++i ) - delete old_alpha[i]; - delete [] old_alpha; - for ( i = 0 ; i < _n_alpha ; ++i ) - delete l[i]; - + + for ( i = 0 ; i < m ; ++i ) + delete old_alpha[i]; + delete [] old_alpha; + for ( i = 0 ; i < _n_alpha ; ++i ) + delete l[i]; + #ifdef DEBUG - _out.close_block(); + _out.close_block(); #endif - - return true; + + return true; } /*-----------------------------------------------------------*/ /* construct regression model (private) */ /*-----------------------------------------------------------*/ bool NOMAD::Quad_Model::construct_regression_model ( double eps , - int max_mpn , - int max_Y_size ) + int max_mpn , + int max_Y_size ) { #ifdef DEBUG - _out << std::endl - << NOMAD::open_block ( "NOMAD::Quad_Model::construct_regression_model()" ); -#endif - - _error_flag = false; - - // check the set Y: - if ( !check_Y() ) - return false; - - int p1 = get_nY(); - - // the number of points (p+1) must be in [(n+1)(n+2)/2;MS_MAX_Y_SIZE]: - if ( p1 < _n_alpha || p1 > max_Y_size ) { -#ifdef DEBUG - _out << std::endl - << "NOMAD::Quad_Model::construct_regression_model(): " - << "(p+1) not in [(n+1)(n+2)/2;" - << max_Y_size << "]" - << std::endl << NOMAD::close_block() << std::endl; -#endif - return false; - } - - // for this procedure, the number of points is limited to 500 - // (because of the SVD decomposition): - if ( p1 > 500 ) { - reduce_Y ( NOMAD::Point ( _n , 0.0 ) , 500 ); - p1 = 500; - } - - // construct the matrix F=M'M (_n_alpha,_n_alpha): - // ----------------------------------------------- - int i , j , k; - double ** F = new double *[_n_alpha]; - double ** M = new double *[p1]; - for ( i = 0 ; i < p1 ; ++i ) { - M[i] = new double[_n_alpha]; - for ( j = 0 ; j < _n_alpha ; ++j ) - M[i][j] = compute_M ( i , j ); - } - - for ( i = 0 ; i < _n_alpha ; ++i ) { - F[i] = new double[_n_alpha]; - for ( j = 0 ; j <= i ; ++j ) { - F[i][j] = 0.0; - for ( k = 0 ; k < p1 ; ++k ) - F[i][j] += M[k][i] * M[k][j]; - if ( i != j ) - F[j][i] = F[i][j]; - } - } - -#ifdef DEBUG - _out << std::endl << "F="; - for ( i = 0 ; i < _n_alpha ; ++i ) { - _out << "\t"; - for ( j = 0 ; j < _n_alpha ; ++j ) - _out << std::setw(12) << F[i][j] << " "; - _out << std::endl; - } + _out << std::endl + << NOMAD::open_block ( "NOMAD::Quad_Model::construct_regression_model()" ); #endif - - bool error = false; - - // SVD decomposition of the F matrix (F=U.W.V'): - // --------------------------------------------- - // (F will be transformed in U) - - double * W = new double [_n_alpha]; - double ** V = new double *[_n_alpha]; - for ( i = 0 ; i < _n_alpha ; ++i ) - V[i] = new double[_n_alpha]; - - std::string error_msg; - if ( NOMAD::SVD_decomposition ( error_msg , F , W , V , _n_alpha , _n_alpha , max_mpn ) ) { - - // compute condition number: - compute_cond ( W , _n_alpha , eps ); - + + _error_flag = false; + + // check the set Y: + if ( !check_Y() ) + return false; + + int p1 = get_nY(); + + // the number of points (p+1) must be in [(n+1)(n+2)/2;MS_MAX_Y_SIZE]: + if ( p1 < _n_alpha || p1 > max_Y_size ) { #ifdef DEBUG - _out << std::endl << "F="; + _out << std::endl + << "NOMAD::Quad_Model::construct_regression_model(): " + << "(p+1) not in [(n+1)(n+2)/2;" + << max_Y_size << "]" + << std::endl << NOMAD::close_block() << std::endl; +#endif + return false; + } + + // for this procedure, the number of points is limited to 500 + // (because of the SVD decomposition): + if ( p1 > 500 ) { + reduce_Y ( NOMAD::Point ( _n , 0.0 ) , 500 ); + p1 = 500; + } + + // construct the matrix F=M'M (_n_alpha,_n_alpha): + // ----------------------------------------------- + int i , j , k; + double ** F = new double *[_n_alpha]; + double ** M = new double *[p1]; + for ( i = 0 ; i < p1 ; ++i ) { + M[i] = new double[_n_alpha]; + for ( j = 0 ; j < _n_alpha ; ++j ) + M[i][j] = compute_M ( i , j ); + } + for ( i = 0 ; i < _n_alpha ; ++i ) { - _out << "\t"; - for ( j = 0 ; j < _n_alpha ; ++j ) - _out << std::setw(12) << F[i][j] << " "; - _out << std::endl; + F[i] = new double[_n_alpha]; + for ( j = 0 ; j <= i ; ++j ) { + F[i][j] = 0.0; + for ( k = 0 ; k < p1 ; ++k ) + F[i][j] += M[k][i] * M[k][j]; + if ( i != j ) + F[j][i] = F[i][j]; + } } - - _out << std::endl << "W=\t"; - for ( i = 0 ; i < _n_alpha ; ++i ) - _out << std::setw(12) << W[i] << " "; - _out << std::endl << std::endl << "cond=" << _cond << std::endl; - _out << std::endl << "V="; +#ifdef DEBUG + _out << std::endl << "F="; for ( i = 0 ; i < _n_alpha ; ++i ) { - _out << "\t"; - for ( j = 0 ; j < _n_alpha ; ++j ) - _out << std::setw(12) << V[i][j] << " "; - _out << std::endl; + _out << "\t"; + for ( j = 0 ; j < _n_alpha ; ++j ) + _out << std::setw(12) << F[i][j] << " "; + _out << std::endl; } #endif - - } - else { + + bool error = false; + + // SVD decomposition of the F matrix (F=U.W.V'): + // --------------------------------------------- + // (F will be transformed in U) + + double * W = new double [_n_alpha]; + double ** V = new double *[_n_alpha]; + for ( i = 0 ; i < _n_alpha ; ++i ) + V[i] = new double[_n_alpha]; + + std::string error_msg; + if ( NOMAD::SVD_decomposition ( error_msg , F , W , V , _n_alpha , _n_alpha , max_mpn ) ) { + + // compute condition number: + compute_cond ( W , _n_alpha , eps ); + #ifdef DEBUG - _out << std::endl << "NOMAD::Quad_Model::construct_regression_model(): " - << "SVD decomposition (" << error_msg << ")" - << std::endl << NOMAD::close_block() << std::endl; + _out << std::endl << "F="; + for ( i = 0 ; i < _n_alpha ; ++i ) { + _out << "\t"; + for ( j = 0 ; j < _n_alpha ; ++j ) + _out << std::setw(12) << F[i][j] << " "; + _out << std::endl; + } + + _out << std::endl << "W=\t"; + for ( i = 0 ; i < _n_alpha ; ++i ) + _out << std::setw(12) << W[i] << " "; + _out << std::endl << std::endl << "cond=" << _cond << std::endl; + + _out << std::endl << "V="; + for ( i = 0 ; i < _n_alpha ; ++i ) { + _out << "\t"; + for ( j = 0 ; j < _n_alpha ; ++j ) + _out << std::setw(12) << V[i][j] << " "; + _out << std::endl; + } #endif - error = true; - _cond.clear(); - } - - // resolution of system F.alpha = M'.f(Y): - // --------------------------------------- - if ( !error ) { - int m = static_cast<int> ( _bbot.size() ); - for ( i = 0 ; i < m ; ++i ) - if ( _alpha[i] ) - solve_regression_system ( M , F , W , V , i , *_alpha[i] , eps ); - } - - // free memory: - for ( i = 0 ; i < _n_alpha ; ++i ) { - delete [] F[i]; - delete [] V[i]; - } - for ( i = 0 ; i < p1 ; ++i ) - delete [] M[i]; - delete [] M; - delete [] F; - delete [] V; - delete [] W; - + + } + else { #ifdef DEBUG - _out.close_block(); + _out << std::endl << "NOMAD::Quad_Model::construct_regression_model(): " + << "SVD decomposition (" << error_msg << ")" + << std::endl << NOMAD::close_block() << std::endl; #endif - - return !error; + error = true; + _cond.clear(); + } + + // resolution of system F.alpha = M'.f(Y): + // --------------------------------------- + if ( !error ) { + int m = static_cast<int> ( _bbot.size() ); + for ( i = 0 ; i < m ; ++i ) + if ( _alpha[i] ) + solve_regression_system ( M , F , W , V , i , *_alpha[i] , eps ); + } + + // free memory: + for ( i = 0 ; i < _n_alpha ; ++i ) { + delete [] F[i]; + delete [] V[i]; + } + for ( i = 0 ; i < p1 ; ++i ) + delete [] M[i]; + delete [] M; + delete [] F; + delete [] V; + delete [] W; + +#ifdef DEBUG + _out.close_block(); +#endif + + return !error; } /*-------------------------------------------------------------*/ @@ -1170,17 +1180,17 @@ bool NOMAD::Quad_Model::construct_regression_model ( double eps , /*-------------------------------------------------------------*/ void NOMAD::Quad_Model::compute_cond ( const double * W , int n , double eps ) { - double min = NOMAD::INF; - double max = -min; - for ( int i = 0 ; i < n ; ++i ) { - if ( W[i] < min ) - min = W[i]; - if ( W[i] > max ) - max = W[i]; - } - if ( min < eps ) - min = eps; - _cond = max / min; + double min = NOMAD::INF; + double max = -min; + for ( int i = 0 ; i < n ; ++i ) { + if ( W[i] < min ) + min = W[i]; + if ( W[i] > max ) + max = W[i]; + } + if ( min < eps ) + min = eps; + _cond = max / min; } /*-------------------------------------------------------------*/ @@ -1188,224 +1198,235 @@ void NOMAD::Quad_Model::compute_cond ( const double * W , int n , double eps ) /* (private) */ /*-------------------------------------------------------------*/ void NOMAD::Quad_Model::solve_regression_system ( double ** M , - double ** F , - double * W , - double ** V , - int bbo_index , - NOMAD::Point & alpha , - double eps ) const + double ** F , + double * W , + double ** V , + int bbo_index , + NOMAD::Point & alpha , + double eps ) const { - // resize the alpha vector: - if ( alpha.size() != _n_alpha ) - alpha.reset ( _n_alpha , 0.0 ); - - double * alpha_tmp = new double [_n_alpha]; - int i , k , p1 = get_nY(); - - // solve the system: - for ( i = 0 ; i < _n_alpha ; ++i ) { - alpha_tmp[i] = 0.0; - for ( k = 0 ; k < p1 ; ++k ) - alpha_tmp[i] += M[k][i] * ( _Y[k]->get_bb_outputs()[bbo_index].value() ); - } - - double * alpha_tmp2 = new double [_n_alpha]; - - // some W values will be zero (or near zero); - // each value that is smaller than eps is ignored - - for ( i = 0 ; i < _n_alpha ; ++i ) { - alpha_tmp2[i] = 0.0; - for ( k = 0 ; k < _n_alpha ; ++k ) - if ( W[i] > eps ) - alpha_tmp2[i] += F[k][i] * alpha_tmp[k] / W[i]; - } - - delete [] alpha_tmp; - - for ( i = 0 ; i < _n_alpha ; ++i ) { - alpha[i] = 0.0; - for ( k = 0 ; k < _n_alpha ; ++k ) - alpha[i] += V[i][k] * alpha_tmp2[k]; - } - - delete [] alpha_tmp2; + // resize the alpha vector: + if ( alpha.size() != _n_alpha ) + alpha.reset ( _n_alpha , 0.0 ); + + double * alpha_tmp = new double [_n_alpha]; + int i , k , p1 = get_nY(); + + // solve the system: + for ( i = 0 ; i < _n_alpha ; ++i ) { + alpha_tmp[i] = 0.0; + for ( k = 0 ; k < p1 ; ++k ) + alpha_tmp[i] += M[k][i] * ( _Y[k]->get_bb_outputs()[bbo_index].value() ); + } + + double * alpha_tmp2 = new double [_n_alpha]; + + // some W values will be zero (or near zero); + // each value that is smaller than eps is ignored + + for ( i = 0 ; i < _n_alpha ; ++i ) { + alpha_tmp2[i] = 0.0; + for ( k = 0 ; k < _n_alpha ; ++k ) + if ( W[i] > eps ) + alpha_tmp2[i] += F[k][i] * alpha_tmp[k] / W[i]; + } + + delete [] alpha_tmp; + + for ( i = 0 ; i < _n_alpha ; ++i ) { + alpha[i] = 0.0; + for ( k = 0 ; k < _n_alpha ; ++k ) + alpha[i] += V[i][k] * alpha_tmp2[k]; + } + + delete [] alpha_tmp2; } /*----------------------------------------------------------*/ /* construct Minimum Frobenius Norm (MFN) model (private) */ /*----------------------------------------------------------*/ bool NOMAD::Quad_Model::construct_MFN_model ( double eps , - int max_mpn , - int max_Y_size ) + int max_mpn , + int max_Y_size ) { -#ifdef DEBUG - _out << std::endl - << NOMAD::open_block ( "NOMAD::Quad_Model::construct_MFN_model()" ); -#endif - - // check the set Y: - if ( !check_Y() ) - return false; - - int p1 = get_nY(); - - // the number of points (p+1) must be in [n+1;(n+1)(n+2)/2-1]: - if ( p1 <= _nfree || p1 >= _n_alpha ) { #ifdef DEBUG _out << std::endl - << "NOMAD::Quad_Model::construct_MFN_model(): " - << "(p+1) not in [n+1;(n+1)(n+2)/2-1]" - << std::endl << NOMAD::close_block() << std::endl; + << NOMAD::open_block ( "NOMAD::Quad_Model::construct_MFN_model()" ); #endif - return false; - } - - // for this procedure, the number of points is limited to 250 - // (because of the SVD decomposition): - if ( p1 > 250 ) { - reduce_Y ( NOMAD::Point ( _n , 0.0 ) , 250 ); - p1 = 250; - } - - // construct the matrix F (4 parts): - // --------------------------------- - // [ 1 | 2 ] - // [ --+-- ] - // [ 3 | 4 ] - - int i , j , k; - int np1 = _nfree + 1; - int nF = np1 + p1; - double ** F = new double *[nF]; - double ** M = new double *[p1]; - for ( i = 0 ; i < nF ; ++i ) - F[i] = new double[nF]; - - // 1/4: MQ.MQ' (p+1,p+1): - { - for ( i = 0 ; i < p1 ; ++i ) { - M[i] = new double[_n_alpha]; - for ( j = 0 ; j < _n_alpha ; ++j ) - M[i][j] = compute_M ( i , j ); - for ( j = 0 ; j <= i ; ++j ) { - F[i][j] = 0.0; - for ( k = np1 ; k < _n_alpha ; ++k ) - F[i][j] += M[i][k] * M[j][k]; - if ( i != j ) - F[j][i] = F[i][j]; - } - } - } - - // 2/4: ML (p+1,n+1): - for ( i = 0 ; i < p1 ; ++i ) { - F[i][p1] = 1.0; - for ( j = p1+1 ; j < nF ; ++j ) - F[i][j] = M[i][j-p1]; - } - - // 3/4: ML' (n+1,p+1): - for ( j = 0 ; j < p1 ; ++j ) { - F[p1][j] = 1.0; - for ( i = p1+1 ; i < nF ; ++i ) - F[i][j] = M[j][i-p1]; - } - - // 4/4: 0 (n+1,n+1): - for ( i = p1 ; i < nF ; ++i ) - for ( j = p1 ; j < nF ; ++j ) - F[i][j] = 0.0; - + + // check the set Y: + if ( !check_Y() ) + return false; + + int p1 = get_nY(); + + // the number of points (p+1) must be in [n+1;(n+1)(n+2)/2-1]: + if ( p1 <= _nfree || p1 >= _n_alpha ) { #ifdef DEBUG - _out << std::endl << "F="; - for ( i = 0 ; i < nF ; ++i ) { - _out << "\t"; - for ( j = 0 ; j < nF ; ++j ) - _out << std::setw(12) << F[i][j] << " "; - _out << std::endl; - } + _out << std::endl + << "NOMAD::Quad_Model::construct_MFN_model(): " + << "(p+1) not in [n+1;(n+1)(n+2)/2-1]" + << std::endl << NOMAD::close_block() << std::endl; #endif - - for ( i = 0 ; i < p1 ; ++i ) - delete [] M[i]; - delete [] M; - - bool error = false; - - // SVD decomposition of the F matrix (F = U.W.V'): - // ----------------------------------------------- - // (F will be transformed in U) - - double * W = new double [nF]; - double ** V = new double *[nF]; - for ( i = 0 ; i < nF ; ++i ) - V[i] = new double[nF]; - - std::string error_msg; - - if ( NOMAD::SVD_decomposition ( error_msg , F , W , V , nF , nF , max_mpn ) ) { - - // compute condition number: - compute_cond ( W , nF , eps ); - + return false; + } + + // for this procedure, the number of points is limited to 250 + // (because of the SVD decomposition): + if ( p1 > 250 ) { + reduce_Y ( NOMAD::Point ( _n , 0.0 ) , 250 ); + p1 = 250; + } + + // construct the matrix F (4 parts): + // --------------------------------- + // [ 1 | 2 ] + // [ --+-- ] + // [ 3 | 4 ] + + int i , j , k; + int np1 = _nfree + 1; + int nF = np1 + p1; + double ** F = new double *[nF]; + double ** M = new double *[p1]; + for ( i = 0 ; i < nF ; ++i ) + F[i] = new double[nF]; + + // 1/4: MQ.MQ' (p+1,p+1): + { + for ( i = 0 ; i < p1 ; ++i ) + { + M[i] = new double[_n_alpha]; + for ( j = 0 ; j < _n_alpha ; ++j ) + M[i][j] = compute_M ( i , j ); + for ( j = 0 ; j <= i ; ++j ) + { + F[i][j] = 0.0; + for ( k = np1 ; k < _n_alpha ; ++k ) + F[i][j] += M[i][k] * M[j][k]; + if ( i != j ) + F[j][i] = F[i][j]; + } + } + } + + // 2/4: ML (p+1,n+1): + for ( i = 0 ; i < p1 ; ++i ) + { + F[i][p1] = 1.0; + for ( j = p1+1 ; j < nF ; ++j ) + F[i][j] = M[i][j-p1]; + } + + // 3/4: ML' (n+1,p+1): + for ( j = 0 ; j < p1 ; ++j ) + { + F[p1][j] = 1.0; + for ( i = p1+1 ; i < nF ; ++i ) + F[i][j] = M[j][i-p1]; + } + + // 4/4: 0 (n+1,n+1): + for ( i = p1 ; i < nF ; ++i ) + for ( j = p1 ; j < nF ; ++j ) + F[i][j] = 0.0; + + #ifdef DEBUG _out << std::endl << "F="; - for ( i = 0 ; i < nF ; ++i ) { - _out << "\t"; - for ( j = 0 ; j < nF ; ++j ) - _out << std::setw(12) << F[i][j] << " "; - _out << std::endl; + for ( i = 0 ; i < nF ; ++i ) + { + _out << "\t"; + for ( j = 0 ; j < nF ; ++j ) + _out << std::setw(12) << F[i][j] << " "; + _out << std::endl; } +#endif + + for ( i = 0 ; i < p1 ; ++i ) + delete [] M[i]; + delete [] M; + + bool error = false; + + // SVD decomposition of the F matrix (F = U.W.V'): + // ----------------------------------------------- + // (F will be transformed in U) - _out << std::endl << "W=\t"; + double * W = new double [nF]; + double ** V = new double *[nF]; for ( i = 0 ; i < nF ; ++i ) - _out << std::setw(12) << W[i] << " "; - _out << std::endl << std::endl << "cond=" << _cond << std::endl; + V[i] = new double[nF]; - _out << std::endl << "V="; - for ( i = 0 ; i < nF ; ++i ) { - _out << "\t"; - for ( j = 0 ; j < nF ; ++j ) - _out << std::setw(12) << V[i][j] << " "; - _out << std::endl; - } + std::string error_msg; + + if ( NOMAD::SVD_decomposition ( error_msg , F , W , V , nF , nF , max_mpn ) ) { + + // compute condition number: + compute_cond ( W , nF , eps ); + +#ifdef DEBUG + _out << std::endl << "F="; + for ( i = 0 ; i < nF ; ++i ) + { + _out << "\t"; + for ( j = 0 ; j < nF ; ++j ) + _out << std::setw(12) << F[i][j] << " "; + _out << std::endl; + } + + _out << std::endl << "W=\t"; + for ( i = 0 ; i < nF ; ++i ) + _out << std::setw(12) << W[i] << " "; + _out << std::endl << std::endl << "cond=" << _cond << std::endl; + + _out << std::endl << "V="; + for ( i = 0 ; i < nF ; ++i ) + { + _out << "\t"; + for ( j = 0 ; j < nF ; ++j ) + _out << std::setw(12) << V[i][j] << " "; + _out << std::endl; + } #endif - - } - else { + + } + else + { #ifdef DEBUG - _out << std::endl << "NOMAD::Quad_Model::construct_MFN_model(): " - << "SVD decomposition (" << error_msg << ")" - << std::endl << std::endl; + _out << std::endl << "NOMAD::Quad_Model::construct_MFN_model(): " + << "SVD decomposition (" << error_msg << ")" + << std::endl << std::endl; #endif - error = true; - _cond.clear(); - } - - // resolution of system F.[mu alpha_L]'=[f(Y) 0]' : - // ------------------------------------------------ - if ( !error ) { - int m = static_cast<int> ( _bbot.size() ); - for ( i = 0 ; i < m ; ++i ) - if ( _alpha[i] ) - solve_MFN_system ( F , W , V , i , *_alpha[i] , eps ); - } - - // free memory: - for ( i = 0 ; i < nF ; ++i ) { - delete [] F[i]; - delete [] V[i]; - } - delete [] F; - delete [] V; - delete [] W; - + error = true; + _cond.clear(); + } + + // resolution of system F.[mu alpha_L]'=[f(Y) 0]' : + // ------------------------------------------------ + if ( !error ) + { + int m = static_cast<int> ( _bbot.size() ); + for ( i = 0 ; i < m ; ++i ) + if ( _alpha[i] ) + solve_MFN_system ( F , W , V , i , *_alpha[i] , eps ); + } + + // free memory: + for ( i = 0 ; i < nF ; ++i ) + { + delete [] F[i]; + delete [] V[i]; + } + delete [] F; + delete [] V; + delete [] W; + #ifdef DEBUG - _out.close_block(); + _out.close_block(); #endif - - return !error; + + return !error; } /*--------------------------------------------------*/ @@ -1413,89 +1434,101 @@ bool NOMAD::Quad_Model::construct_MFN_model ( double eps , /* for MFN interpolation (private) */ /*--------------------------------------------------*/ void NOMAD::Quad_Model::solve_MFN_system ( double ** F , - double * W , - double ** V , - int bbo_index , - NOMAD::Point & alpha , - double eps ) const + double * W , + double ** V , + int bbo_index , + NOMAD::Point & alpha , + double eps ) const { - // resize the alpha vector: - if ( alpha.size() != _n_alpha ) - alpha.reset ( _n_alpha , 0.0 ); - - int i , k , k1 , k2 , + // resize the alpha vector: + if ( alpha.size() != _n_alpha ) + alpha.reset ( _n_alpha , 0.0 ); + + int i , k , k1 , k2 , np1 = _nfree + 1 , nm1 = _nfree - 1 , p1 = get_nY() , nF = np1 + p1; - - // step 1/2: find alpha_L and mu: - // --------- - double * alpha_tmp = new double [np1]; - double * mu_tmp = new double [ p1]; - double * mu = new double [ p1]; - - // if F is singular, some W values will be zero (or near zero); - // each value that is smaller than eps is ignored: - for ( i = 0 ; i < p1 ; ++i ) { - mu_tmp[i] = 0.0; - if ( W[i] > eps ) - for ( k = 0 ; k < p1 ; ++k ) - mu_tmp[i] += F[k][i] * - ( _Y[k]->get_bb_outputs()[bbo_index].value() ) / W[i]; - } - - for ( i = p1 ; i < nF ; ++i ) { - alpha_tmp[i-p1] = 0.0; - if ( W[i] > eps ) - for ( k = 0 ; k < p1 ; ++k ) - alpha_tmp[i-p1] += F[k][i] * - ( _Y[k]->get_bb_outputs()[bbo_index].value() ) / W[i]; - } - - for ( i = 0 ; i < p1 ; ++i ) { - mu[i] = 0.0; - for ( k = 0 ; k < p1 ; ++k ) - mu[i] += V[i][k] * mu_tmp[k]; - for ( k = p1 ; k < nF ; ++k ) - mu[i] += V[i][k] * alpha_tmp[k-p1]; - } - - for ( i = p1 ; i < nF ; ++i ) { - alpha[i-p1] = 0.0; - for ( k = 0 ; k < p1 ; ++k ) - alpha[i-p1] += V[i][k] * mu_tmp[k]; - for ( k = p1 ; k < nF ; ++k ) - alpha[i-p1] += V[i][k] * alpha_tmp[k-p1]; - } - - delete [] alpha_tmp; - delete [] mu_tmp; - + + // step 1/2: find alpha_L and mu: + // --------- + double * alpha_tmp = new double [np1]; + double * mu_tmp = new double [ p1]; + double * mu = new double [ p1]; + + // if F is singular, some W values will be zero (or near zero); + // each value that is smaller than eps is ignored: + for ( i = 0 ; i < p1 ; ++i ) + { + mu_tmp[i] = 0.0; + if ( W[i] > eps ) + for ( k = 0 ; k < p1 ; ++k ) + mu_tmp[i] += F[k][i] * + ( _Y[k]->get_bb_outputs()[bbo_index].value() ) / W[i]; + } + + for ( i = p1 ; i < nF ; ++i ) + { + alpha_tmp[i-p1] = 0.0; + if ( W[i] > eps ) + for ( k = 0 ; k < p1 ; ++k ) + alpha_tmp[i-p1] += F[k][i] * + ( _Y[k]->get_bb_outputs()[bbo_index].value() ) / W[i]; + } + + for ( i = 0 ; i < p1 ; ++i ) + { + mu[i] = 0.0; + for ( k = 0 ; k < p1 ; ++k ) + mu[i] += V[i][k] * mu_tmp[k]; + for ( k = p1 ; k < nF ; ++k ) + mu[i] += V[i][k] * alpha_tmp[k-p1]; + } + + for ( i = p1 ; i < nF ; ++i ) + { + alpha[i-p1] = 0.0; + for ( k = 0 ; k < p1 ; ++k ) + alpha[i-p1] += V[i][k] * mu_tmp[k]; + for ( k = p1 ; k < nF ; ++k ) + alpha[i-p1] += V[i][k] * alpha_tmp[k-p1]; + } + + delete [] alpha_tmp; + delete [] mu_tmp; + #ifdef DEBUG - _out << std::endl << "output #" << bbo_index << ": mu=\t"; - for ( i = 0 ; i < p1 ; ++i ) - _out << std::setw(12) << mu[i] << " "; - _out << std::endl; + _out << std::endl << "output #" << bbo_index << ": mu=\t"; + for ( i = 0 ; i < p1 ; ++i ) + _out << std::setw(12) << mu[i] << " "; + _out << std::endl; + + _out << std::endl << "output #" << bbo_index << ": alpha_intermediate=\t"; + for ( i = 0 ; i < alpha.size() ; ++i ) + _out << std::setw(12) << alpha[i] << " "; + _out << std::endl; + #endif - - // step 2/2: find alpha_Q: - // --------- - for ( i = 0 ; i < _nfree ; ++i ) { - alpha[i+np1] = 0.0; - for ( k = 0 ; k < p1 ; ++k ) - alpha[i+np1] += mu[k] * pow ( (*_Y[k])[i].value() , 2.0 ) / 2.0; - } - - for ( k1 = 0 ; k1 < nm1 ; ++k1 ) - for ( k2 = k1+1 ; k2 < _nfree ; ++k2 ) { - alpha[i+np1] = 0.0; - for ( k = 0 ; k < p1 ; ++k ) - alpha[i+np1] += mu[k] * (*_Y[k])[k1].value() * (*_Y[k])[k2].value(); - ++i; + + // step 2/2: find alpha_Q: + // --------- + for ( i = 0 ; i < _nfree ; ++i ) + { + alpha[i+np1] = 0.0; + for ( k = 0 ; k < p1 ; ++k ) + alpha[i+np1] += mu[k] * pow ( (*_Y[k])[_index[i+1]-1].value() , 2.0 ) / 2.0; } - - delete [] mu; + + for ( k1 = 0 ; k1 < nm1 ; ++k1 ) + for ( k2 = k1+1 ; k2 < _nfree ; ++k2 ) + { + alpha[i+np1] = 0.0; + for ( k = 0 ; k < p1 ; ++k ) + alpha[i+np1] += mu[k] * (*_Y[k])[_index[k1+1]-1].value() * (*_Y[k])[_index[k2+1]-1].value(); + ++i; + } + + delete [] mu; } /*-----------------------------------------------------------*/ @@ -1503,69 +1536,69 @@ void NOMAD::Quad_Model::solve_MFN_system ( double ** F , /*-----------------------------------------------------------*/ bool NOMAD::Quad_Model::check_Y ( void ) const { - if ( _Y.empty() ) { + if ( _Y.empty() ) { #ifdef DEBUG - _out << std::endl << "NOMAD::Quad_Model::check_Y(): set Y is empty" - << std::endl << std::endl; + _out << std::endl << "NOMAD::Quad_Model::check_Y(): set Y is empty" + << std::endl << std::endl; #endif - return false; - } - - int nY = get_nY(); - int m = static_cast<int> ( _bbot.size() ); - - for ( int k = 0 ; k < nY ; ++k ) { - - if ( _Y[k] == NULL ) { + return false; + } + + int nY = get_nY(); + int m = static_cast<int> ( _bbot.size() ); + + for ( int k = 0 ; k < nY ; ++k ) { + + if ( _Y[k] == NULL ) { #ifdef DEBUG - _out << std::endl - << "NOMAD::Quad_Model::check_Y(): NULL pointer in the set Y" - << std::endl << std::endl; + _out << std::endl + << "NOMAD::Quad_Model::check_Y(): NULL pointer in the set Y" + << std::endl << std::endl; #endif - return false; - } - - if ( _Y[k]->get_eval_status() != NOMAD::EVAL_OK ) { + return false; + } + + if ( _Y[k]->get_eval_status() != NOMAD::EVAL_OK ) { #ifdef DEBUG - _out << std::endl - << "NOMAD::Quad_Model::check_Y(): a point in Y failed to evaluate" - << std::endl << std::endl; + _out << std::endl + << "NOMAD::Quad_Model::check_Y(): a point in Y failed to evaluate" + << std::endl << std::endl; #endif - return false; - } - - const NOMAD::Point & bbo = _Y[k]->get_bb_outputs(); - - if ( !bbo.is_complete() ) { + return false; + } + + const NOMAD::Point & bbo = _Y[k]->get_bb_outputs(); + + if ( !bbo.is_complete() ) { #ifdef DEBUG - _out << std::endl - << "NOMAD::Quad_Model::check_Y(): some bb outputs in Y are not defined" - << std::endl << std::endl; + _out << std::endl + << "NOMAD::Quad_Model::check_Y(): some bb outputs in Y are not defined" + << std::endl << std::endl; #endif - return false; - } - - if ( bbo.size() != m ) { + return false; + } + + if ( bbo.size() != m ) { #ifdef DEBUG - _out << std::endl - << "NOMAD::Quad_Model::check_Y(): " - << "bb outputs in Y do not have the same dimension" - << std::endl << std::endl; + _out << std::endl + << "NOMAD::Quad_Model::check_Y(): " + << "bb outputs in Y do not have the same dimension" + << std::endl << std::endl; #endif - return false; - } - - if ( _Y[k]->size() != _n ) { + return false; + } + + if ( _Y[k]->size() != _n ) { #ifdef DEBUG - _out << std::endl - << "NOMAD::Quad_Model::check_Y(): " - << "points in Y do not have the same dimension" - << std::endl << std::endl; + _out << std::endl + << "NOMAD::Quad_Model::check_Y(): " + << "points in Y do not have the same dimension" + << std::endl << std::endl; #endif - return false; + return false; + } } - } - return true; + return true; } /*----------------------------------------------------*/ @@ -1573,26 +1606,28 @@ bool NOMAD::Quad_Model::check_Y ( void ) const /*----------------------------------------------------*/ bool NOMAD::Quad_Model::check ( void ) const { - if ( !_alpha ) - return false; - - int nalpha = (_nfree+1)*(_nfree+2)/2; - int i , m = static_cast<int> ( _bbot.size() ); - - for ( int bbo_index = 0 ; bbo_index < m ; ++bbo_index ) { - - if ( _alpha[bbo_index] ) { - - if ( _alpha[bbo_index]->size() != nalpha ) - return false; - - for ( i = 0 ; i < nalpha ; ++i ) - if ( !(*_alpha[bbo_index])[i].is_defined() ) - return false; + if ( !_alpha ) + return false; + + int nalpha = (_nfree+1)*(_nfree+2)/2; + int i , m = static_cast<int> ( _bbot.size() ); + + for ( int bbo_index = 0 ; bbo_index < m ; ++bbo_index ) + { + + if ( _alpha[bbo_index] ) + { + + if ( _alpha[bbo_index]->size() != nalpha ) + return false; + + for ( i = 0 ; i < nalpha ; ++i ) + if ( !(*_alpha[bbo_index])[i].is_defined() ) + return false; + } } - } - - return true; + + return true; } @@ -1604,27 +1639,29 @@ bool NOMAD::Quad_Model::check ( void ) const /* . a more efficient version is used in Quad_Model_Evaluator::eval_x() ) */ /*--------------------------------------------------------------------------*/ NOMAD::Double NOMAD::Quad_Model::eval ( const NOMAD::Point & x , - const NOMAD::Point & alpha ) const + const NOMAD::Point & alpha ) const { - int i , j , k = 1 , nm1 = _n-1; - NOMAD::Double z = alpha[0]; - - for ( i = 0 ; i < _n ; ++i ) { - if ( !_fixed_vars[i] ) { - z += x[i] * ( alpha[k] + 0.5 * alpha[k+_nfree] * x[i] ); - ++k; + int i , j , k = 1 , nm1 = _n-1; + NOMAD::Double z = alpha[0]; + + for ( i = 0 ; i < _n ; ++i ) + { + if ( !_fixed_vars[i] ) + { + z += x[i] * ( alpha[k] + 0.5 * alpha[k+_nfree] * x[i] ); + ++k; + } } - } - - k += _nfree; - - for ( i = 0 ; i < nm1 ; ++i ) - if ( !_fixed_vars[i] ) - for ( j = i+1 ; j < _n ; ++j ) - if ( !_fixed_vars[j] ) - z += alpha[k++] * x[i] * x[j]; - - return z; + + k += _nfree; + + for ( i = 0 ; i < nm1 ; ++i ) + if ( !_fixed_vars[i] ) + for ( j = i+1 ; j < _n ; ++j ) + if ( !_fixed_vars[j] ) + z += alpha[k++] * x[i] * x[j]; + + return z; } @@ -1632,60 +1669,60 @@ NOMAD::Double NOMAD::Quad_Model::eval ( const NOMAD::Point & x , /* compute model h and f values at a point */ /*----------------------------------------------------------------*/ void NOMAD::Quad_Model::eval_hf ( const NOMAD::Point & x , - const NOMAD::Double & h_min , - NOMAD::hnorm_type h_norm , - NOMAD::Double & h , - NOMAD::Double & f ) const + const NOMAD::Double & h_min , + NOMAD::hnorm_type h_norm , + NOMAD::Double & h , + NOMAD::Double & f ) const { - f.clear(); - h = 0.0; - - int m = static_cast<int>(_bbot.size()); - NOMAD::Double bboi; - - for ( int i = 0 ; i < m ; ++i ) { + f.clear(); + h = 0.0; - if ( _alpha[i] ) { - - bboi = eval ( x , *_alpha[i] ); - - if ( bboi.is_defined() ) { - - if ( _bbot[i] == NOMAD::EB || _bbot[i] == NOMAD::PEB_E ) { - - if ( bboi > h_min ) { - h.clear(); - return; - } - } - - else if ( ( _bbot[i] == NOMAD::FILTER || - _bbot[i] == NOMAD::PB || - _bbot[i] == NOMAD::PEB_P ) ) { - if ( bboi > h_min ) { - switch ( h_norm ) { - case NOMAD::L1: - h += bboi; - break; - case NOMAD::L2: - h += bboi * bboi; - break; - case NOMAD::LINF: - if ( bboi > h ) - h = bboi; - break; - } - } - } - - else if ( _bbot[i] == NOMAD::OBJ ) - f = bboi; - } - } - } - - if ( h_norm == NOMAD::L2 ) - h = h.sqrt(); + int m = static_cast<int>(_bbot.size()); + NOMAD::Double bboi; + + for ( int i = 0 ; i < m ; ++i ) { + + if ( _alpha[i] ) { + + bboi = eval ( x , *_alpha[i] ); + + if ( bboi.is_defined() ) { + + if ( _bbot[i] == NOMAD::EB || _bbot[i] == NOMAD::PEB_E ) { + + if ( bboi > h_min ) { + h.clear(); + return; + } + } + + else if ( ( _bbot[i] == NOMAD::FILTER || + _bbot[i] == NOMAD::PB || + _bbot[i] == NOMAD::PEB_P ) ) { + if ( bboi > h_min ) { + switch ( h_norm ) { + case NOMAD::L1: + h += bboi; + break; + case NOMAD::L2: + h += bboi * bboi; + break; + case NOMAD::LINF: + if ( bboi > h ) + h = bboi; + break; + } + } + } + + else if ( _bbot[i] == NOMAD::OBJ ) + f = bboi; + } + } + } + + if ( h_norm == NOMAD::L2 ) + h = h.sqrt(); } @@ -1697,29 +1734,29 @@ void NOMAD::Quad_Model::eval_hf ( const NOMAD::Point & x , /*-----------------------------------------------------*/ NOMAD::Double NOMAD::Quad_Model::compute_max_rel_err ( void ) const { - NOMAD::Double truth_value , model_value , rel_err , max_rel_err; - int k , nY = get_nY() , m = static_cast<int> ( _bbot.size() ); - - for ( int bbo_index = 0 ; bbo_index < m ; ++bbo_index ) { - if ( _alpha[bbo_index] ) { - for ( k = 0 ; k < nY ; ++k ) { - if ( _Y[k] && _Y[k]->get_eval_status() == NOMAD::EVAL_OK ) { - truth_value = _Y[k]->get_bb_outputs()[bbo_index]; - if ( truth_value.is_defined() ) { - model_value = eval ( *_Y[k] , *_alpha[bbo_index] ); - if ( model_value.is_defined() ) { - if ( truth_value.abs() != 0.0 ) { - rel_err = (truth_value-model_value).abs() / truth_value.abs(); - if ( !max_rel_err.is_defined() || rel_err > max_rel_err ) - max_rel_err = rel_err; - } - } - } - } - } - } - } - return max_rel_err; + NOMAD::Double truth_value , model_value , rel_err , max_rel_err; + int k , nY = get_nY() , m = static_cast<int> ( _bbot.size() ); + + for ( int bbo_index = 0 ; bbo_index < m ; ++bbo_index ) { + if ( _alpha[bbo_index] ) { + for ( k = 0 ; k < nY ; ++k ) { + if ( _Y[k] && _Y[k]->get_eval_status() == NOMAD::EVAL_OK ) { + truth_value = _Y[k]->get_bb_outputs()[bbo_index]; + if ( truth_value.is_defined() ) { + model_value = eval ( *_Y[k] , *_alpha[bbo_index] ); + if ( model_value.is_defined() ) { + if ( truth_value.abs() != 0.0 ) { + rel_err = (truth_value-model_value).abs() / truth_value.abs(); + if ( !max_rel_err.is_defined() || rel_err > max_rel_err ) + max_rel_err = rel_err; + } + } + } + } + } + } + } + return max_rel_err; } /*---------------------------------------------*/ @@ -1729,91 +1766,91 @@ NOMAD::Double NOMAD::Quad_Model::compute_max_rel_err ( void ) const /* (private) */ /*---------------------------------------------*/ void NOMAD::Quad_Model::compute_model_error ( int bbo_index , - NOMAD::Double & error , - NOMAD::Double & min_rel_err , - NOMAD::Double & max_rel_err , - NOMAD::Double & avg_rel_err ) const + NOMAD::Double & error , + NOMAD::Double & min_rel_err , + NOMAD::Double & max_rel_err , + NOMAD::Double & avg_rel_err ) const { - NOMAD::Double truth_value , model_value , rel_err; - int nY = get_nY() , cnt = 0; - bool chk = true; - - max_rel_err.clear(); - min_rel_err.clear(); - avg_rel_err = error = 0.0; - + NOMAD::Double truth_value , model_value , rel_err; + int nY = get_nY() , cnt = 0; + bool chk = true; + + max_rel_err.clear(); + min_rel_err.clear(); + avg_rel_err = error = 0.0; + #ifdef DEBUG - std::ostringstream msg; - msg << "output #" << bbo_index; - _out.open_block ( msg.str() ); + std::ostringstream msg; + msg << "output #" << bbo_index; + _out.open_block ( msg.str() ); #endif - - for ( int k = 0 ; k < nY ; ++k ) - if ( _Y[k] && _Y[k]->get_eval_status() == NOMAD::EVAL_OK ) - { - truth_value = _Y[k]->get_bb_outputs()[bbo_index]; - - if ( truth_value.is_defined() ) - { - model_value = eval ( *_Y[k] , *_alpha[bbo_index] ); - if ( model_value.is_defined() ) - { - rel_err.clear(); - if ( truth_value.abs() != 0.0 ) - rel_err = (truth_value-model_value).abs() / truth_value.abs(); - else - { - if (truth_value.abs()==model_value.abs()) - rel_err=0.0; - else - rel_err=NOMAD::INF; - } - if ( !max_rel_err.is_defined() || rel_err > max_rel_err ) - max_rel_err = rel_err; - if ( !min_rel_err.is_defined() || rel_err < min_rel_err ) - min_rel_err = rel_err; - avg_rel_err += rel_err; - ++cnt; - + + for ( int k = 0 ; k < nY ; ++k ) + if ( _Y[k] && _Y[k]->get_eval_status() == NOMAD::EVAL_OK ) + { + truth_value = _Y[k]->get_bb_outputs()[bbo_index]; + + if ( truth_value.is_defined() ) + { + model_value = eval ( *_Y[k] , *_alpha[bbo_index] ); + if ( model_value.is_defined() ) + { + rel_err.clear(); + if ( truth_value.abs() != 0.0 ) + rel_err = (truth_value-model_value).abs() / truth_value.abs(); + else + { + if (truth_value.abs()==model_value.abs()) + rel_err=0.0; + else + rel_err=NOMAD::INF; + } + if ( !max_rel_err.is_defined() || rel_err > max_rel_err ) + max_rel_err = rel_err; + if ( !min_rel_err.is_defined() || rel_err < min_rel_err ) + min_rel_err = rel_err; + avg_rel_err += rel_err; + ++cnt; + #ifdef DEBUG - _out << "Y[" << k << "]= ( "; - _Y[k]->NOMAD::Point::display ( _out ); - _out << " )" << " f=" << truth_value - << " m=" << model_value << " error^2=" - << ( model_value - truth_value ).pow2() - << " rel_err=" << rel_err - << std::endl; + _out << "Y[" << k << "]= ( "; + _Y[k]->NOMAD::Point::display ( _out ); + _out << " )" << " f=" << truth_value + << " m=" << model_value << " error^2=" + << ( model_value - truth_value ).pow2() + << " rel_err=" << rel_err + << std::endl; #endif - error += ( model_value - truth_value ).pow2(); - } - else - { - chk = false; - break; - } - } - else - { - chk = false; - break; - } - } - + error += ( model_value - truth_value ).pow2(); + } + else + { + chk = false; + break; + } + } + else + { + chk = false; + break; + } + } + #ifdef DEBUG - _out.close_block(); + _out.close_block(); #endif - - if ( chk) + + if ( chk) { // Case where chk is true (at least one model_value and the corresponding thruth value were defined => cnt != 0) - error = error.sqrt(); - avg_rel_err = avg_rel_err / cnt; + error = error.sqrt(); + avg_rel_err = avg_rel_err / cnt; } - else + else { - error.clear(); - min_rel_err.clear(); - max_rel_err.clear(); - avg_rel_err.clear(); + error.clear(); + min_rel_err.clear(); + max_rel_err.clear(); + avg_rel_err.clear(); } } @@ -1822,54 +1859,54 @@ void NOMAD::Quad_Model::compute_model_error ( int bbo_index , /*-----------------------------------------------------------*/ void NOMAD::Quad_Model::display_model_coeffs ( const NOMAD::Display & out ) const { - if ( _error_flag ) { - out << "model coefficients: could not be constructed" << std::endl; - return; - } - - int m = static_cast<int> ( _bbot.size() ); - - out << NOMAD::open_block ( "model coefficients" ); - for ( int i = 0 ; i < m ; ++i ) { - out << "output #"; - out.display_int_w ( i , m ); - out << ": "; - if ( _alpha[i] ) { - out<< "[ "; - _alpha[i]->display ( out , " " , 6 ); - out << " ]"; + if ( _error_flag ) { + out << "model coefficients: could not be constructed" << std::endl; + return; } - else - out << "NULL"; - out << std::endl; - } - out.close_block(); + + int m = static_cast<int> ( _bbot.size() ); + + out << NOMAD::open_block ( "model coefficients" ); + for ( int i = 0 ; i < m ; ++i ) { + out << "output #"; + out.display_int_w ( i , m ); + out << ": "; + if ( _alpha[i] ) { + out<< "[ "; + _alpha[i]->display ( out , " " , 6 ); + out << " ]"; + } + else + out << "NULL"; + out << std::endl; + } + out.close_block(); } /*-----------------------------------------------------------*/ /* display the interpolation set Y */ /*-----------------------------------------------------------*/ void NOMAD::Quad_Model::display_Y ( const NOMAD::Display & out , - const std::string & title ) const + const std::string & title ) const { - out << NOMAD::open_block ( title ); - int nY = get_nY(); - for ( int k = 0 ; k < nY ; ++k ) { - out << "#"; - out.display_int_w ( k , nY ); - out << ": "; - if ( _Y[k] ) { - out << "( "; - _Y[k]->NOMAD::Point::display ( out , " " , 12 ); - out << " ) bbo=[ "; - _Y[k]->get_bb_outputs().display ( out , " " , 12 ); - out << " ]"; + out << NOMAD::open_block ( title ); + int nY = get_nY(); + for ( int k = 0 ; k < nY ; ++k ) { + out << "#"; + out.display_int_w ( k , nY ); + out << ": "; + if ( _Y[k] ) { + out << "( "; + _Y[k]->NOMAD::Point::display ( out , " " , 12 ); + out << " ) bbo=[ "; + _Y[k]->get_bb_outputs().display ( out , " " , 12 ); + out << " ]"; + } + else + out << "NULL"; + out << std::endl; } - else - out << "NULL"; - out << std::endl; - } - out.close_block(); + out.close_block(); } /*-------------------------------------------------------*/ @@ -1877,86 +1914,81 @@ void NOMAD::Quad_Model::display_Y ( const NOMAD::Display & out , /*-------------------------------------------------------*/ void NOMAD::Quad_Model::display_Y_error ( const NOMAD::Display & out ) const { - if ( _error_flag ) - { - out << "model error on the interpolation set: cannot be computed" - << std::endl; - return; - } - - int i ; - int index = -1; - int m = static_cast<int> ( _bbot.size() ); - - for ( i = 0 ; i < m ; ++i ) - if ( _alpha[i] ) - { - if ( index >= 0 ) - { - index = -1; - break; - } - else - index = i; - } - - NOMAD::Double error , min_rel_err , max_rel_err , avg_rel_err; - - // only one output: - if ( index >= 0 ) - { - compute_model_error ( index , error , min_rel_err , max_rel_err , avg_rel_err ); - out << "model errors on the interpolation set: error=" - << error << " min_rel_err=" << min_rel_err - << " max_rel_err=" << max_rel_err << " avg_rel_err=" << avg_rel_err - << std::endl; - } - - // several outputs: - else { - - out.open_block ( "model error on the interpolation set" ); - - NOMAD::Double error_i , min_rel_err_i , max_rel_err_i , avg_rel_err_i; - - error = avg_rel_err = 0.0; - min_rel_err.clear(); - max_rel_err.clear(); - - int cnt = 0; - - for ( i = 0 ; i < m ; ++i ) - if ( _alpha[i] ) - { - - ++cnt; - - compute_model_error ( i , - error_i , - min_rel_err_i , - max_rel_err_i , - avg_rel_err_i ); - - if (error_i.is_defined()) - error += error_i; - if (avg_rel_err_i.is_defined()) - avg_rel_err += avg_rel_err_i; - if ( !min_rel_err.is_defined() || min_rel_err_i < min_rel_err ) - min_rel_err = min_rel_err_i; - if ( !max_rel_err.is_defined() || max_rel_err_i > max_rel_err ) - max_rel_err = max_rel_err_i; - - out << "output #" << i << ": error=" << error_i - << " min_rel_err=" << min_rel_err_i << " max_rel_err=" - << max_rel_err_i << " avg_rel_err=" << avg_rel_err_i << std::endl; - } - - out << std::endl << "global: error=" << error - << " min_rel_err=" << min_rel_err - << " max_rel_err=" << max_rel_err - << " avg_rel_err=" << avg_rel_err / cnt - << std::endl << NOMAD::close_block(); - } + if ( _error_flag ) { + out << "model error on the interpolation set: cannot be computed" + << std::endl; + return; + } + + int i ; + int index = -1; + int m = static_cast<int> ( _bbot.size() ); + + for ( i = 0 ; i < m ; ++i ) + if ( _alpha[i] ) { + if ( index >= 0 ) { + index = -1; + break; + } + else + index = i; + } + + NOMAD::Double error , min_rel_err , max_rel_err , avg_rel_err; + + // only one output: + if ( index >= 0 ) { + compute_model_error ( index , error , min_rel_err , max_rel_err , avg_rel_err ); + out << "model errors on the interpolation set: error=" + << error << " min_rel_err=" << min_rel_err + << " max_rel_err=" << max_rel_err << " avg_rel_err=" << avg_rel_err + << std::endl; + } + + // several outputs: + else { + + out.open_block ( "model error on the interpolation set" ); + + NOMAD::Double error_i , min_rel_err_i , max_rel_err_i , avg_rel_err_i; + + error = avg_rel_err = 0.0; + min_rel_err.clear(); + max_rel_err.clear(); + + int cnt = 0; + + for ( i = 0 ; i < m ; ++i ) + if ( _alpha[i] ) { + + ++cnt; + + compute_model_error ( i , + error_i , + min_rel_err_i , + max_rel_err_i , + avg_rel_err_i ); + + if (error_i.is_defined()) + error += error_i; + if (avg_rel_err_i.is_defined()) + avg_rel_err += avg_rel_err_i; + if ( !min_rel_err.is_defined() || min_rel_err_i < min_rel_err ) + min_rel_err = min_rel_err_i; + if ( !max_rel_err.is_defined() || max_rel_err_i > max_rel_err ) + max_rel_err = max_rel_err_i; + + out << "output #" << i << ": error=" << error_i + << " min_rel_err=" << min_rel_err_i << " max_rel_err=" + << max_rel_err_i << " avg_rel_err=" << avg_rel_err_i << std::endl; + } + + out << std::endl << "global: error=" << error + << " min_rel_err=" << min_rel_err + << " max_rel_err=" << max_rel_err + << " avg_rel_err=" << avg_rel_err / cnt + << std::endl << NOMAD::close_block(); + } } /*-----------------------------------------------*/ @@ -1964,57 +1996,57 @@ void NOMAD::Quad_Model::display_Y_error ( const NOMAD::Display & out ) const /*-----------------------------------------------*/ void NOMAD::Quad_Model::display_lagrange_polynomials ( const std::vector<NOMAD::Point *> & l , - const std::vector<NOMAD::Eval_Point *> & Y ) const + const std::vector<NOMAD::Eval_Point *> & Y ) const { - int i , j , nY = static_cast<int> ( Y.size() ); - - // display Lagrange polynomials: - _out << std::endl << NOMAD::open_block ( "Lagrange polynomials" ); - for ( i = 0 ; i < _n_alpha ; ++i ) { - _out << "l["; - _out.display_int_w ( i , _n_alpha ); - _out << "] = [ "; - l[i]->NOMAD::Point::display ( _out , " " , 14 , -1 ); - _out << "]" << std::endl; - } - _out.close_block(); - - // display current set Y: - _out << std::endl << NOMAD::open_block ( "current set Y" ); - for ( i = 0 ; i < nY ; ++i ) { - _out << "Y["; - _out.display_int_w ( i , nY ); - _out << "] = "; - if ( Y[i] ) { - _out << "( "; - Y[i]->NOMAD::Point::display ( _out , " " , 6 , -1 ); - _out << " )"; + int i , j , nY = static_cast<int> ( Y.size() ); + + // display Lagrange polynomials: + _out << std::endl << NOMAD::open_block ( "Lagrange polynomials" ); + for ( i = 0 ; i < _n_alpha ; ++i ) { + _out << "l["; + _out.display_int_w ( i , _n_alpha ); + _out << "] = [ "; + l[i]->NOMAD::Point::display ( _out , " " , 14 , -1 ); + _out << "]" << std::endl; } - else - _out << "NULL"; - _out << std::endl; + _out.close_block(); + + // display current set Y: + _out << std::endl << NOMAD::open_block ( "current set Y" ); + for ( i = 0 ; i < nY ; ++i ) { + _out << "Y["; + _out.display_int_w ( i , nY ); + _out << "] = "; + if ( Y[i] ) { + _out << "( "; + Y[i]->NOMAD::Point::display ( _out , " " , 6 , -1 ); + _out << " )"; + } + else + _out << "NULL"; + _out << std::endl; } - - _out.close_block(); - - // display l(Y): should be the identity matrix: - NOMAD::Double tmp , err = 0.0; - _out << std::endl << NOMAD::open_block ( "l(Y)" ); - for ( i = 0 ; i < _n_alpha ; ++i ) { - _out << "l["; - _out.display_int_w ( i , _n_alpha ); - _out << "]: "; - for ( j = 0 ; j < _n_alpha ; ++j ) { - tmp.clear(); - if ( j < nY && Y[j] ) { - tmp = eval ( *Y[j] , *l[i] ); - err += (i==j) ? (tmp-1.0).abs() : tmp.abs(); - } - tmp.display ( _out , "%6.3f" ); - _out << " "; + + _out.close_block(); + + // display l(Y): should be the identity matrix: + NOMAD::Double tmp , err = 0.0; + _out << std::endl << NOMAD::open_block ( "l(Y)" ); + for ( i = 0 ; i < _n_alpha ; ++i ) { + _out << "l["; + _out.display_int_w ( i , _n_alpha ); + _out << "]: "; + for ( j = 0 ; j < _n_alpha ; ++j ) { + tmp.clear(); + if ( j < nY && Y[j] ) { + tmp = eval ( *Y[j] , *l[i] ); + err += (i==j) ? (tmp-1.0).abs() : tmp.abs(); + } + tmp.display ( _out , "%6.3f" ); + _out << " "; + } + _out << std::endl; } - _out << std::endl; - } - _out << std::endl << "error (with identity) = " - << err << std::endl << NOMAD::close_block() << std::endl; + _out << std::endl << "error (with identity) = " + << err << std::endl << NOMAD::close_block() << std::endl; } diff --git a/src/Quad_Model.hpp b/src/Quad_Model.hpp index 9197ea5..b9320c7 100644 --- a/src/Quad_Model.hpp +++ b/src/Quad_Model.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -387,7 +387,7 @@ namespace NOMAD { */ void define_scaling ( const NOMAD::Double & r ); - /// Define scaling based on directions. See paper: Reducing the number of function evaluations in Mesh Adaptive Direct Search algorithms, Audet, Ianni, LeDigabel, Tribes, 2012 + /// Define scaling based on directions. See paper: Reducing the number of function evaluations in Mesh Adaptive Direct Search algorithms, Audet, Ianni, LeDigabel, Tribes, 2014 /** - Looks also for fixed variables. \param dirP The \c dirP parameter corresponds to set of directions formin a hyper-cube centered on poll center -- \b IN. diff --git a/src/Quad_Model_Evaluator.cpp b/src/Quad_Model_Evaluator.cpp index 717ad9e..7a6d9f8 100644 --- a/src/Quad_Model_Evaluator.cpp +++ b/src/Quad_Model_Evaluator.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version (3.5.1).7.2 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -49,12 +49,12 @@ NOMAD::Quad_Model_Evaluator::Quad_Model_Evaluator ( const NOMAD::Parameters & p , const NOMAD::Quad_Model & model ) : - _n ( model.get_n() ) , - _nm1 ( _n-1 ) , - _m ( p.get_bb_nb_outputs() ) , - _x ( NULL ) , - _alpha ( NULL ) , - _model_ready ( model.check() ) + _n ( model.get_n() ) , + _nm1 ( _n-1 ) , + _m ( p.get_bb_nb_outputs() ) , + _x ( NULL ) , + _alpha ( NULL ) , + _model_ready ( model.check() ) { if ( _model_ready ) { @@ -116,7 +116,8 @@ NOMAD::Quad_Model_Evaluator::Quad_Model_Evaluator /*-----------------------------*/ NOMAD::Quad_Model_Evaluator::~Quad_Model_Evaluator ( void ) { - if ( _model_ready ) { + if ( _model_ready ) + { for ( int i = 0 ; i < _m ; ++i ) if ( _alpha[i] ) delete [] _alpha[i]; @@ -148,11 +149,13 @@ bool NOMAD::Quad_Model_Evaluator::eval_x for ( i = 0 ; i < _n ; ++i ) _x[i] = x[i].value() / 1000.0; - for ( int oi = 0 ; oi < _m ; ++oi ) { + for ( int oi = 0 ; oi < _m ; ++oi ) + { alpha = _alpha[oi]; - if ( alpha ) { + if ( alpha ) + { z = alpha[0]; p = _x; diff --git a/src/Quad_Model_Evaluator.hpp b/src/Quad_Model_Evaluator.hpp index b0d2f22..f3780a5 100644 --- a/src/Quad_Model_Evaluator.hpp +++ b/src/Quad_Model_Evaluator.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Quad_Model_Evaluator.hpp - \brief NOMAD::Evaluator subclass for quadratic model optimization (headers) - \author Sebastien Le Digabel - \date 2010-08-31 - \see Quad_Model_Evaluator.cpp -*/ + \file Quad_Model_Evaluator.hpp + \brief NOMAD::Evaluator subclass for quadratic model optimization (headers) + \author Sebastien Le Digabel + \date 2010-08-31 + \see Quad_Model_Evaluator.cpp + */ #ifndef __QUAD_MODEL_EVALUATOR__ #define __QUAD_MODEL_EVALUATOR__ @@ -47,60 +47,82 @@ namespace NOMAD { - - /// NOMAD::Evaluator subclass for quadratic model optimization. - class Quad_Model_Evaluator { - - private: - - int _n; ///< Number of variables. - int _nm1; ///< Number of variables minus one. - int _m; ///< Number of blackbox outputs. - double * _x; ///< An evaluation point. - double ** _alpha; ///< Model parameters. - bool _model_ready; ///< \c true if model ready to evaluate. - - public: - - /// Constructor. - /** - \param p Parameters -- \b IN. - \param model Model -- \b IN. - */ - Quad_Model_Evaluator ( const NOMAD::Parameters & p , - const NOMAD::Quad_Model & model ); - - /// Destructor. - virtual ~Quad_Model_Evaluator ( void ); - - /// Evaluate the blackboxes at a given trial point. - /** - \param x The trial point -- \b IN/OUT. - \param h_max Maximal feasibility value \c h_max -- \b IN. - \param count_eval Flag indicating if the evaluation has to be counted - or not -- \b OUT. - \return A boolean equal to \c false if the evaluation failed. - */ - virtual bool eval_x ( NOMAD::Eval_Point & x , - const NOMAD::Double & h_max , - bool & count_eval ) const; - - /// Evaluate the gradient of a blackboxe at a given trial point. - /** - \param x The trial point -- \b IN/OUT. - \param g The gradient of a bb model at the trial point \c x -- \b OUT. - \param output_index The index of the black box. -- \b IN. - \param count_eval Flag indicating if the evaluation has to be counted - or not -- \b OUT. - \return A boolean equal to \c false if the evaluation failed. - */ - - virtual bool evalGrad_x (const NOMAD::Point & x , - NOMAD::Point & g , - const int & output_index , - bool & count_eval ) const; - - }; + + /// NOMAD::Evaluator subclass for quadratic model optimization. + class Quad_Model_Evaluator { + + private: + + int _n; ///< Number of variables. + int _nm1; ///< Number of variables minus one. + int _m; ///< Number of blackbox outputs. + double * _x; ///< An evaluation point. + double ** _alpha; ///< Model parameters. + bool _model_ready; ///< \c true if model ready to evaluate. + + public: + + /// Constructor. + /** + \param p Parameters -- \b IN. + \param model Model -- \b IN. + */ + Quad_Model_Evaluator ( const NOMAD::Parameters & p , + const NOMAD::Quad_Model & model ); + + /// Destructor. + virtual ~Quad_Model_Evaluator ( void ); + + /// Evaluate the blackboxes at a given trial point. + /** + \param x The trial point -- \b IN/OUT. + \param h_max Maximal feasibility value \c h_max -- \b IN. + \param count_eval Flag indicating if the evaluation has to be counted + or not -- \b OUT. + \return A boolean equal to \c false if the evaluation failed. + */ + virtual bool eval_x ( NOMAD::Eval_Point & x , + const NOMAD::Double & h_max , + bool & count_eval ) const; + + /// Evaluate the blackbox functions at a given trial point (#2). + /** + - Non-const version. + - Calls the const version by default. + - May be user-defined. + - Surrogate or true evaluation depending on the value of \c x.is_surrogate(). + \param x The trial point -- \b IN/OUT. + \param h_max Maximal feasibility value \c h_max -- \b IN. + \param count_eval Flag indicating if the evaluation has to be counted + or not -- \b OUT. + \return A boolean equal to \c false if the evaluation failed. + */ + virtual bool eval_x ( NOMAD::Eval_Point & x , + const NOMAD::Double & h_max , + bool & count_eval ) + { + return static_cast<const NOMAD::Quad_Model_Evaluator *>(this)->eval_x ( x , h_max, count_eval ); + } + + + + + /// Evaluate the gradient of a blackboxe at a given trial point. + /** + \param x The trial point -- \b IN/OUT. + \param g The gradient of a bb model at the trial point \c x -- \b OUT. + \param output_index The index of the black box. -- \b IN. + \param count_eval Flag indicating if the evaluation has to be counted + or not -- \b OUT. + \return A boolean equal to \c false if the evaluation failed. + */ + + virtual bool evalGrad_x (const NOMAD::Point & x , + NOMAD::Point & g , + const int & output_index , + bool & count_eval ) const; + + }; } #endif diff --git a/src/Quad_Model_Search.cpp b/src/Quad_Model_Search.cpp index 5219d1d..ef61c01 100644 --- a/src/Quad_Model_Search.cpp +++ b/src/Quad_Model_Search.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -92,412 +92,426 @@ /* */ /*----------------------------------------------------------------*/ void NOMAD::Quad_Model_Search::search ( NOMAD::Mads & mads , - int & nb_search_pts , - bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::success_type & success , - bool & count_search , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc ) + int & nb_search_pts , + bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::success_type & success , + bool & count_search , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc ) { - new_feas_inc = new_infeas_inc = NULL; - nb_search_pts = 0; - success = NOMAD::UNSUCCESSFUL; - count_search = false; - - _one_search_stats.reset(); - - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_search_dd(); - - if ( stop ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "Quad_Model_Search::search(): not performed (stop flag is active)" - << std::endl; - return; - } - - // black-box output types: - const std::vector<NOMAD::bb_output_type> & bbot = _p.get_bb_output_type(); - const std::list<int> & index_obj_list = _p.get_index_obj(); - - if ( index_obj_list.empty() ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "Quad_Model_Search::search(): not performed with no objective function" - << std::endl; - return; - } - - - // initial displays: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << NOMAD::MODEL_SEARCH << " #" - << _all_searches_stats.get_MS_nb_searches(); - out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; - } - - // surrogate or truth model evaluations: - NOMAD::eval_type ev_type = + new_feas_inc = new_infeas_inc = NULL; + nb_search_pts = 0; + success = NOMAD::UNSUCCESSFUL; + count_search = false; + + _one_search_stats.reset(); + + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_search_dd(); + + if ( stop ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "Quad_Model_Search::search(): not performed (stop flag is active)" + << std::endl; + return; + } + + // black-box output types: + const std::vector<NOMAD::bb_output_type> & bbot = _p.get_bb_output_type(); + const std::list<int> & index_obj_list = _p.get_index_obj(); + + if ( index_obj_list.empty() ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "Quad_Model_Search::search(): not performed with no objective function" + << std::endl; + return; + } + + + // initial displays: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << NOMAD::MODEL_SEARCH << " #" + << _all_searches_stats.get_MS_nb_searches(); + out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; + } + + // surrogate or truth model evaluations: + NOMAD::eval_type ev_type = ( _p.get_opt_only_sgte() ) ? NOMAD::SGTE : NOMAD::TRUTH; - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "model construction for " << ev_type << std::endl; - - // active cache: - const NOMAD::Cache & cache = mads.get_cache(); - - // active barrier: - const NOMAD::Barrier & barrier = + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "model construction for " << ev_type << std::endl; + + // active cache: + const NOMAD::Cache & cache = mads.get_cache(); + + // active barrier: + const NOMAD::Barrier & barrier = ( ev_type == NOMAD::SGTE ) ? mads.get_sgte_barrier() : mads.get_true_barrier(); - - // current incumbents: xk[0]=best_feas and xk[1]=best_infeas: - const NOMAD::Eval_Point * xk[2]; - xk[0] = barrier.get_best_feasible (); - xk[1] = barrier.get_best_infeasible(); - - if ( !xk[0] && !xk[1] ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "end of " << NOMAD::MODEL_SEARCH << " (no incumbent)"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } - return; - } - - // from this point the search is counted: - count_search = true; - _one_search_stats.add_MS_nb_searches(); - - // display the number of cache points: - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << "number of points in cache: " - << cache.size() << std::endl; - - // stats: - NOMAD::Stats & stats = mads.get_stats(); - - // current mesh index: - int mesh_index = NOMAD::Mesh::get_mesh_index(); - - // number of interpolation points: - int nY[2]; - nY[0] = nY[1] = -1; - - int min_Y_size = _p.get_model_quad_min_Y_size(); - int max_Y_size = _p.get_model_quad_max_Y_size(); - - // use or not well-poisedness: - bool use_WP = _p.get_model_quad_use_WP(); - - // flag to detect model errors: - bool model_ok = false; - NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); - - // main loop on the two incumbents (feasible and infeasible): - // --------- - for ( int i_inc = 0 ; i_inc < 2 ; ++i_inc ) - { - - if ( xk[i_inc] ) - { - - // display the model center: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - out << std::endl << "model center"; - if ( xk[0] && xk[1] ) - out << " (" << i_inc+1 << "/2)"; - out << ": " << *xk[i_inc] << std::endl; - } - - // get and check the signature: - NOMAD::Signature * signature = xk[i_inc]->get_signature(); - if ( !signature ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "end of " << NOMAD::MODEL_SEARCH << " (no signature)"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } - stats.update_model_stats ( _one_search_stats ); - _all_searches_stats.update ( _one_search_stats ); - return; - } - - int n = signature->get_n(); - if ( n != xk[i_inc]->size() ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "end of " << NOMAD::MODEL_SEARCH << " (incompatible signature)"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } - stats.update_model_stats ( _one_search_stats ); - _all_searches_stats.update ( _one_search_stats ); - return; - } - - // compute the interpolation radius: points in Y must be at - // a max distance of ms_radius_factor times Delta^p_k: - NOMAD::Point delta_p , delta_m; - signature->get_mesh().get_delta_p ( delta_p , mesh_index ); - signature->get_mesh().get_delta_m ( delta_m , mesh_index ); - - NOMAD::Point interpolation_radius = delta_p; - interpolation_radius *= _p.get_model_quad_radius_factor(); - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "mesh index : " << mesh_index << std::endl - << "mesh size parameter : ( " << delta_m << " )" << std::endl - << "poll size parameter : ( " << delta_p << " )" << std::endl - << "interpolation radius : ( " << interpolation_radius - << " )" << std::endl; - - // creation of the model: - NOMAD::Quad_Model model ( out , bbot , cache , *signature ); - NOMAD::Clock clock; - - // construct interpolation set Y: - // ------------------------------ - model.construct_Y ( *xk[i_inc] , - interpolation_radius , - max_Y_size ); - - nY[i_inc] = model.get_nY(); - - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - out << "number of points in Y: " << nY[i_inc] - << " (p=" << nY[i_inc]-1; - if ( nY[i_inc] < 2 ) - out << ", not enough"; - out << ")" << std::endl; - } - - if ( nY[i_inc] < 2 ) - _one_search_stats.add_not_enough_pts(); - else - { - + + // current incumbents: xk[0]=best_feas and xk[1]=best_infeas: + const NOMAD::Eval_Point * xk[2]; + xk[0] = barrier.get_best_feasible (); + xk[1] = barrier.get_best_infeasible(); + + if ( !xk[0] && !xk[1] ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "end of " << NOMAD::MODEL_SEARCH << " (no incumbent)"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } + return; + } + + // from this point the search is counted: + count_search = true; + _one_search_stats.add_MS_nb_searches(); + + // display the number of cache points: + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << "number of points in cache: " + << cache.size() << std::endl; + + // stats: + NOMAD::Stats & stats = mads.get_stats(); + + // number of interpolation points: + int nY[2]; + nY[0] = nY[1] = -1; + + int min_Y_size = _p.get_model_quad_min_Y_size(); + int max_Y_size = _p.get_model_quad_max_Y_size(); + + // use or not well-poisedness: + bool use_WP = _p.get_model_quad_use_WP(); + + // flag to detect model errors: + bool model_ok = false; + NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); + + // main loop on the two incumbents (feasible and infeasible): + // --------- + for ( int i_inc = 0 ; i_inc < 2 ; ++i_inc ) + { + + if ( xk[i_inc] ) + { + + // display the model center: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + out << std::endl << "model center"; + if ( xk[0] && xk[1] ) + out << " (" << i_inc+1 << "/2)"; + out << ": " << *xk[i_inc] << std::endl; + } + + // get and check the signature: + NOMAD::Signature * signature = xk[i_inc]->get_signature(); + if ( !signature ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) { + std::ostringstream oss; + oss << "end of " << NOMAD::MODEL_SEARCH << " (no signature)"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } + stats.update_model_stats ( _one_search_stats ); + _all_searches_stats.update ( _one_search_stats ); + return; + } + + // current mesh index: + NOMAD::Point mesh_indices = signature->get_mesh()->get_mesh_indices(); + + + int n = signature->get_n(); + if ( n != xk[i_inc]->size() ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "end of " << NOMAD::MODEL_SEARCH << " (incompatible signature)"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } + stats.update_model_stats ( _one_search_stats ); + _all_searches_stats.update ( _one_search_stats ); + return; + } + + // compute the interpolation radius: points in Y must be at + // a max distance of ms_radius_factor times Delta^k: + NOMAD::Point Delta , delta; + signature->get_mesh()->get_Delta ( Delta ); + signature->get_mesh()->get_delta ( delta ); + + + NOMAD::Point interpolation_radius = Delta; + interpolation_radius *= _p.get_model_quad_radius_factor(); + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "mesh indices : (" << mesh_indices << ")" << std::endl + << "mesh size parameter : ( " << delta << " )" << std::endl + << "poll size parameter : ( " << Delta << " )" << std::endl + << "interpolation radius : ( " << interpolation_radius + << " )" << std::endl; + + // creation of the model: + NOMAD::Quad_Model model ( out , bbot , cache , *signature ); + + + + NOMAD::Clock clock; + + // construct interpolation set Y: + // ------------------------------ + model.construct_Y ( *xk[i_inc] , + interpolation_radius , + max_Y_size ); + + nY[i_inc] = model.get_nY(); + + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + out << "number of points in Y: " << nY[i_inc] + << " (p=" << nY[i_inc]-1; + if ( nY[i_inc] < 2 ) + out << ", not enough"; + out << ")" << std::endl; + } + + if ( nY[i_inc] < 2 ) + _one_search_stats.add_not_enough_pts(); + else + { + #ifdef DEBUG - out << std::endl; - model.display_Y ( out , "unscaled interpolation set Y" ); + out << std::endl; + model.display_Y ( out , "unscaled interpolation set Y" ); #endif - - // define scaling: - // --------------- - // The min box around the interpolation set Y - // is scaled to [-r;r] with r=MODEL_RADIUS_FACTOR. - model.define_scaling ( _p.get_model_quad_radius_factor() ); - + + // define scaling: + // --------------- + // The min box around the interpolation set Y + // is scaled to [-r;r] with r=MODEL_RADIUS_FACTOR. + model.define_scaling ( _p.get_model_quad_radius_factor() ); + #ifdef DEBUG - out << std::endl; - model.display_Y ( out , "scaled interpolation set Ys" ); + out << std::endl; + model.display_Y ( out , "scaled interpolation set Ys" ); #endif - - // error check: - if ( model.get_error_flag() ) - _one_search_stats.add_construction_error(); - - // not enough points (this is not counted as an error): - else if ( nY[i_inc] < 2 || - ( min_Y_size < 0 && nY[i_inc] <= model.get_nfree() ) ) - _one_search_stats.add_not_enough_pts(); - - // no error and enough points in Y: - else - { - - // construct model: - // ---------------- - model.construct ( use_WP , NOMAD::SVD_EPS , NOMAD::SVD_MAX_MPN , max_Y_size ); - _one_search_stats.add_construction_time ( clock.get_CPU_time() ); - _one_search_stats.update_nY ( model.get_nY() ); - - // display model characteristics: + + // error check: + if ( model.get_error_flag() ) + _one_search_stats.add_construction_error(); + + // not enough points (this is not counted as an error): + else if ( nY[i_inc] < 2 || + ( min_Y_size < 0 && nY[i_inc] <= model.get_nfree() ) ) + _one_search_stats.add_not_enough_pts(); + + // no error and enough points in Y: + else + { + + // construct model: + // ---------------- + model.construct ( use_WP , NOMAD::SVD_EPS , NOMAD::SVD_MAX_MPN , max_Y_size ); + _one_search_stats.add_construction_time ( clock.get_CPU_time() ); + _one_search_stats.update_nY ( model.get_nY() ); + + // display model characteristics: #ifdef DEBUG - out << std::endl; - model.display_model_coeffs ( out ); - out << std::endl; - model.display_Y_error ( out ); -#endif - // count model: - if ( ev_type == NOMAD::TRUTH ) - _one_search_stats.add_nb_truth(); - else - _one_search_stats.add_nb_sgte(); - - switch ( model.get_interpolation_type() ) - { - case NOMAD::MFN: - _one_search_stats.add_nb_MFN(); - break; - case NOMAD::WP_REGRESSION: - _one_search_stats.add_nb_WP_regression(); - break; - case NOMAD::REGRESSION: - _one_search_stats.add_nb_regression(); - break; - default: - break; - } - - // check model error flag: - const NOMAD::Double & cond = model.get_cond(); - if ( model.get_error_flag() || - !cond.is_defined() || - cond > NOMAD::SVD_MAX_COND ) - { - if ( model.get_error_flag() ) - _one_search_stats.add_construction_error(); - else - _one_search_stats.add_bad_cond(); - } - else - { - - model_ok = true; - - // optimize model: - // --------------- - NOMAD::Point xf , xi; - - clock.reset(); - - bool optimization_ok = optimize_model ( model , - xk , - i_inc , - display_degree , - out , - xf , - xi , - stop , - stop_reason ); - - _one_search_stats.add_optimization_time ( clock.get_CPU_time() ); - - if ( optimization_ok ) - { - - // get solution(s), project to mesh (+round for integers), and create trial points: - // ---------------------------------------------------------- - if ( xf.is_defined() ) - create_trial_point ( ev_control , - xf , - model , - *signature , - mesh_index , - delta_m , - display_degree , - out ); - - if ( xi.is_defined() ) - create_trial_point ( ev_control , - xi , - model , - *signature , - mesh_index , - delta_m , - display_degree , - out ); - } - else - _one_search_stats.add_MS_opt_error(); - } - } - } - } - } // end of main loop - - // check the number of times that not enough points could be considered: - if ( nY[0] <= 1 && nY[1] <= 1 ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "end of " << NOMAD::MODEL_SEARCH - << " (not enough points)"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } - stats.update_model_stats ( _one_search_stats ); - _all_searches_stats.update ( _one_search_stats ); - return; - } - - // check if no model has been computed: - if ( !model_ok ) - { - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "end of " << NOMAD::MODEL_SEARCH - << " (model computation or optimization error)"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } - stats.update_model_stats ( _one_search_stats ); - _all_searches_stats.update ( _one_search_stats ); - return; - } - - nb_search_pts = ev_control.get_nb_eval_points(); - - // reduce the list of trial points from a maximum - // of 4 points to MODEL_SEARCH_MAX_TRIAL_PTS points: - int max_trial_pts = _p.get_model_search_max_trial_pts(); - if ( max_trial_pts > 4 ) - max_trial_pts = 4; - if ( nb_search_pts > max_trial_pts ) - { - ev_control.reduce_eval_lop ( max_trial_pts ); - nb_search_pts = ev_control.get_nb_eval_points(); - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - out << "the list of trial points is reduced to " - << nb_search_pts << " point"; - if ( nb_search_pts > 1 ) - out << "s"; - out << std::endl; - } - } - - _one_search_stats.update_MS_max_search_pts ( nb_search_pts ); - - // evaluate the trial points: - // -------------------------- - int bbe = stats.get_bb_eval(); - int sgte_eval = stats.get_sgte_eval (); - int cache_hits = stats.get_cache_hits(); - - new_feas_inc = new_infeas_inc = NULL; - - ev_control.disable_model_eval_sort(); - - ev_control.eval_list_of_points ( _type , - mads.get_true_barrier() , - mads.get_sgte_barrier() , - mads.get_pareto_front() , - stop , - stop_reason , - new_feas_inc , - new_infeas_inc , - success ); - - ev_control.enable_model_eval_sort(); - - // update stats: - _one_search_stats.add_MS_bb_eval ( stats.get_bb_eval () - bbe ); - _one_search_stats.add_MS_sgte_eval ( stats.get_sgte_eval () - sgte_eval ); - _one_search_stats.add_MS_cache_hits ( stats.get_cache_hits() - cache_hits ); - - if ( success == NOMAD::FULL_SUCCESS ) - _one_search_stats.add_MS_success(); - - _one_search_stats.add_MS_pts ( nb_search_pts ); - - stats.update_model_stats ( _one_search_stats ); - _all_searches_stats.update ( _one_search_stats ); - - // final display: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "end of " << NOMAD::MODEL_SEARCH << " (" << success << ")"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } + out << std::endl; + model.display_model_coeffs ( out ); + out << std::endl; + model.display_Y_error ( out ); +#endif + // count model: + if ( ev_type == NOMAD::TRUTH ) + _one_search_stats.add_nb_truth(); + else + _one_search_stats.add_nb_sgte(); + + switch ( model.get_interpolation_type() ) + { + case NOMAD::MFN: + _one_search_stats.add_nb_MFN(); + break; + case NOMAD::WP_REGRESSION: + _one_search_stats.add_nb_WP_regression(); + break; + case NOMAD::REGRESSION: + _one_search_stats.add_nb_regression(); + break; + default: + break; + } + + // check model error flag: + const NOMAD::Double & cond = model.get_cond(); + if ( model.get_error_flag() || + !cond.is_defined() || + cond > NOMAD::SVD_MAX_COND ) + { + if ( model.get_error_flag() ) + _one_search_stats.add_construction_error(); + else + _one_search_stats.add_bad_cond(); + } + else + { + + model_ok = true; + + // optimize model: + // --------------- + NOMAD::Point xf , xi; + + clock.reset(); + + bool optimization_ok = optimize_model ( model , + xk , + i_inc , + display_degree , + out , + xf , + xi , + stop , + stop_reason ); + + _one_search_stats.add_optimization_time ( clock.get_CPU_time() ); + + if ( optimization_ok ) + { + + // get solution(s), project to mesh (+round for integers), and create trial points: + // ---------------------------------------------------------- + if ( xf.is_defined() ) + create_trial_point ( ev_control , + xf , + model , + *signature , + mesh_indices , + delta , + display_degree , + out ); + + if ( xi.is_defined() ) + create_trial_point ( ev_control , + xi , + model , + *signature , + mesh_indices , + delta , + display_degree , + out ); + } + else + _one_search_stats.add_MS_opt_error(); + } + } + } + } + } // end of main loop + + // check the number of times that not enough points could be considered: + if ( nY[0] <= 1 && nY[1] <= 1 ) { + if ( display_degree == NOMAD::FULL_DISPLAY ) { + std::ostringstream oss; + oss << "end of " << NOMAD::MODEL_SEARCH + << " (not enough points)"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } + stats.update_model_stats ( _one_search_stats ); + _all_searches_stats.update ( _one_search_stats ); + return; + } + + // check if no model has been computed: + if ( !model_ok ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) { + std::ostringstream oss; + oss << "end of " << NOMAD::MODEL_SEARCH + << " (model computation or optimization error)"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } + stats.update_model_stats ( _one_search_stats ); + _all_searches_stats.update ( _one_search_stats ); + return; + } + + nb_search_pts = ev_control.get_nb_eval_points(); + + // reduce the list of trial points from a maximum + // of 4 points to MODEL_SEARCH_MAX_TRIAL_PTS points: + int max_trial_pts = _p.get_model_search_max_trial_pts(); + if ( max_trial_pts > 4 ) + max_trial_pts = 4; + if ( nb_search_pts > max_trial_pts ) + { + ev_control.reduce_eval_lop ( max_trial_pts ); + nb_search_pts = ev_control.get_nb_eval_points(); + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + out << "the list of trial points is reduced to " + << nb_search_pts << " point"; + if ( nb_search_pts > 1 ) + out << "s"; + out << std::endl; + } + } + + _one_search_stats.update_MS_max_search_pts ( nb_search_pts ); + + // evaluate the trial points: + // -------------------------- + int bbe = stats.get_bb_eval(); + int sgte_eval = stats.get_sgte_eval (); + int cache_hits = stats.get_cache_hits(); + + new_feas_inc = new_infeas_inc = NULL; + + ev_control.disable_model_eval_sort(); + + ev_control.eval_list_of_points ( _type , + mads.get_true_barrier() , + mads.get_sgte_barrier() , + mads.get_pareto_front() , + stop , + stop_reason , + new_feas_inc , + new_infeas_inc , + success ); + + ev_control.enable_model_eval_sort(); + + // update stats: + _one_search_stats.add_MS_bb_eval ( stats.get_bb_eval () - bbe ); + _one_search_stats.add_MS_sgte_eval ( stats.get_sgte_eval () - sgte_eval ); + _one_search_stats.add_MS_cache_hits ( stats.get_cache_hits() - cache_hits ); + + if ( success == NOMAD::FULL_SUCCESS ) + _one_search_stats.add_MS_success(); + + _one_search_stats.add_MS_pts ( nb_search_pts ); + + stats.update_model_stats ( _one_search_stats ); + _all_searches_stats.update ( _one_search_stats ); + + // final display: + if ( display_degree == NOMAD::FULL_DISPLAY ) { + std::ostringstream oss; + oss << "end of " << NOMAD::MODEL_SEARCH << " (" << success << ")"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } } /*---------------------------------------------------------------*/ @@ -508,167 +522,168 @@ void NOMAD::Quad_Model_Search::create_trial_point NOMAD::Point x , const NOMAD::Quad_Model & model , NOMAD::Signature & signature , - int mesh_index , - const NOMAD::Point & delta_m , + const NOMAD::Point & mesh_indices , + const NOMAD::Point & delta , NOMAD::dd_type display_degree , const NOMAD::Display & out ) { - - bool proj_to_mesh = _p.get_model_search_proj_to_mesh(); - - if ( display_degree == NOMAD::FULL_DISPLAY ) { - out << "candidate"; - if ( proj_to_mesh ) - out << " (before projection)"; - out << ": ( " << x << " )" << std::endl; - } - - // model center: - NOMAD::Point center = model.get_center(); - - // model search point: - int n = x.size(); - - // projection to mesh: - if ( proj_to_mesh ) - { - x.project_to_mesh ( center , delta_m , _p.get_lb() , _p.get_ub() ); - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "candidate (after projection) : ( " - << x << " )" << std::endl; - } - - - // Round for integer and binary variables: - for (int i=0;i<n;i++) - { - if ( _p.get_bb_input_type()[i] == NOMAD::INTEGER ) - { - if ( x[i] >= 0.0 ) - x[i] = x[i].NOMAD::Double::ceil(); - else - x[i] = x[i].NOMAD::Double::floor(); - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "candidate (after rounding integer) : ( " - << x << " )" << std::endl; - } - // binary variables: - else if ( _p.get_bb_input_type()[i] == NOMAD::BINARY ) - { - if ( x[i]!= 0.0 ) - x[i] = 1.0; - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "candidate (after rounding binary) : ( " - << x << " )" << std::endl; - } - } - - - - // compare x and center: - if ( x == center ) - { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "candidate rejected (candidate==model center)" << std::endl; - return; - } - - - - NOMAD::Eval_Point * tk = new NOMAD::Eval_Point; - - // if the search is optimistic, a direction is computed (this - // will be used in case of success in the speculative search): - if ( _p.get_model_search_optimistic() ) - { - NOMAD::Direction dir ( n , 0.0 , NOMAD::MODEL_SEARCH_DIR ); - dir.Point::operator = ( x - center ); - tk->set_direction ( &dir ); - } - - tk->set ( n , _p.get_bb_nb_outputs() ); - tk->set_signature ( &signature ); - tk->set_mesh_index ( &mesh_index ); - - tk->Point::operator = ( x ); - - // compute model f and h in order to accept or reject the trial point: - - NOMAD::Double h0 , f0; // model values of f and h at the center - NOMAD::Double h1 , f1; // model values of f and h at the trial point - - const NOMAD::Double & h_min = _p.get_h_min(); - NOMAD::hnorm_type h_norm = _p.get_h_norm(); - - model.scale ( x ); - - model.eval_hf ( NOMAD::Point (n,0) , h_min , h_norm , h0 , f0 ); - model.eval_hf ( x , h_min , h_norm , h1 , f1 ); - - if ( display_degree == NOMAD::FULL_DISPLAY ) - { + + bool proj_to_mesh = _p.get_model_search_proj_to_mesh(); + + if ( display_degree == NOMAD::FULL_DISPLAY ) { + out << "candidate"; + if ( proj_to_mesh ) + out << " (before projection)"; + out << ": ( " << x << " )" << std::endl; + } + + // model center: + NOMAD::Point center = model.get_center(); + + // model search point: + int n = x.size(); + + // projection to mesh: + if ( proj_to_mesh ) + { + x.project_to_mesh ( center , delta , _p.get_lb() , _p.get_ub() ); + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "candidate (after projection) : ( " + << x << " )" << std::endl; + } + + + // Round for integer and binary variables: + bool has_integer=false; + bool has_binary=false; + for (int i=0;i<n;i++) + { + if ( _p.get_bb_input_type()[i] == NOMAD::INTEGER ) + { + has_integer=true; + if ( x[i] >= 0.0 ) + x[i] = x[i].NOMAD::Double::ceil(); + else + x[i] = x[i].NOMAD::Double::floor(); + } + // binary variables: + else if ( _p.get_bb_input_type()[i] == NOMAD::BINARY ) + { + has_binary=true; + if ( x[i]!= 0.0 ) + x[i] = 1.0; + } + } + if ( has_integer && display_degree == NOMAD::FULL_DISPLAY ) + out << "candidate (after rounding integer) : ( " + << x << " )" << std::endl; + + if ( has_binary && display_degree == NOMAD::FULL_DISPLAY ) + out << "candidate (after rounding binary) : ( " + << x << " )" << std::endl; + + + // compare x and center: + if ( x == center ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "candidate rejected (candidate==model center)" << std::endl; + return; + } + + + + NOMAD::Eval_Point * tk = new NOMAD::Eval_Point; + + // if the search is optimistic, a direction is computed (this + // will be used in case of success in the speculative search): + if ( _p.get_model_search_optimistic() ) + { + NOMAD::Direction dir ( n , 0.0 , NOMAD::MODEL_SEARCH_DIR ); + dir.Point::operator = ( x - center ); + tk->set_direction ( &dir ); + } + + tk->set ( n , _p.get_bb_nb_outputs() ); + tk->set_signature ( &signature ); + tk->Point::operator = ( x ); + + // compute model f and h in order to accept or reject the trial point: + NOMAD::Double h0 , f0; // model values of f and h at the center + NOMAD::Double h1 , f1; // model values of f and h at the trial point + + const NOMAD::Double & h_min = _p.get_h_min(); + NOMAD::hnorm_type h_norm = _p.get_h_norm(); + + model.scale ( x ); + + model.eval_hf ( NOMAD::Point (n,0) , h_min , h_norm , h0 , f0 ); + model.eval_hf ( x , h_min , h_norm , h1 , f1 ); + + if ( display_degree == NOMAD::FULL_DISPLAY ) + { #ifdef DEBUG - out << "model at center : h=" << h0 << " f=" << f0 << std::endl; + out << "model at center : h=" << h0 << " f=" << f0 << std::endl; #endif - out << "model at candidate: h=" << h1 << " f=" << f1 - << std::endl << std::endl; - } - - bool accept_point = true; - - if ( !f1.is_defined() || !h1.is_defined() ) - accept_point = false; - else - { - if ( !f0.is_defined() || !h0.is_defined() ) - accept_point = true; - else - accept_point = (f1 <= f0) || (h1 <= h0); - } - - // we check that the candidate does not correspond to another candidate: - if ( accept_point ) - { - const std::set<NOMAD::Priority_Eval_Point> & eval_lop - = ev_control.get_eval_lop(); - - std::set<NOMAD::Priority_Eval_Point>::const_iterator it , end = eval_lop.end(); - - for ( it = eval_lop.begin() ; it != end ; ++it ) - if ( it->get_point()->NOMAD::Point::operator == ( *tk ) ) - { - accept_point = false; - break; - } - } - - // add the new point to the list of search trial points: - if ( accept_point ) { - ev_control.add_eval_point ( tk , - display_degree , - _p.get_snap_to_bounds() , - NOMAD::Double() , - NOMAD::Double() , - f1 , - h1 ); + out << "model at candidate: h=" << h1 << " f=" << f1 + << std::endl << std::endl; + } + + bool accept_point = true; + + if ( !f1.is_defined() || !h1.is_defined() ) + accept_point = false; + else + { + if ( !f0.is_defined() || !h0.is_defined() ) + accept_point = true; + else + accept_point = (f1 <= f0) || (h1 <= h0); + } + + // we check that the candidate does not correspond to another candidate: + if ( accept_point ) + { + const std::set<NOMAD::Priority_Eval_Point> & eval_lop + = ev_control.get_eval_lop(); + + std::set<NOMAD::Priority_Eval_Point>::const_iterator it , end = eval_lop.end(); + + for ( it = eval_lop.begin() ; it != end ; ++it ) + if ( it->get_point()->NOMAD::Point::operator == ( *tk ) ) + { + accept_point = false; + break; + } + } + + // add the new point to the list of search trial points: + if ( accept_point ) { + ev_control.add_eval_point ( tk , + display_degree , + _p.get_snap_to_bounds() , + NOMAD::Double() , + NOMAD::Double() , + f1 , + h1 ); #ifdef MODEL_STATS - if ( tk ) { - tk->set_mod_use ( 1 ); // 1 for model search - tk->set_cond ( model.get_cond() ); - tk->set_Yw ( model.get_Yw () ); - tk->set_nY ( model.get_nY () ); - tk->set_mh ( h1 ); - tk->set_mf ( f1 ); - } + if ( tk ) { + tk->set_mod_use ( 1 ); // 1 for model search + tk->set_cond ( model.get_cond() ); + tk->set_Yw ( model.get_Yw () ); + tk->set_nY ( model.get_nY () ); + tk->set_mh ( h1 ); + tk->set_mf ( f1 ); + } #endif - - } - else { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "candidate rejected" << std::endl; - _one_search_stats.add_MS_rejected(); - delete tk; - } + + } + else { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "candidate rejected" << std::endl; + _one_search_stats.add_MS_rejected(); + delete tk; + } } /*---------------------------------------------------------------*/ @@ -690,302 +705,287 @@ bool NOMAD::Quad_Model_Search::optimize_model bool & stop , NOMAD::stop_type & stop_reason ) { - xf.clear(); - xi.clear(); - - int n = model.get_n(); - bool error = false; - std::string error_str; - int i; - - // initial displays: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "model optimization"; - if ( xk[0] && xk[1] ) - oss << " (" << i_inc+1 << "/2)"; - out << std::endl << NOMAD::open_block ( oss.str() ); - } - - // parameters creation: - NOMAD::Parameters model_param ( out ); - - // random seed: - model_param.set_SEED ( _p.get_seed() + 10*_all_searches_stats.get_MS_nb_searches() ); - - // number of variables: - model_param.set_DIMENSION ( n ); - - // blackbox outputs: - model_param.set_BB_OUTPUT_TYPE ( _p.get_bb_output_type() ); - - // blackbox inputs: - // Use defaults: all variables are treated as continuous (integer and binary. Categoricals disable models anyway). - - // barrier parameters: - model_param.set_H_MIN ( _p.get_h_min () ); - model_param.set_H_NORM ( _p.get_h_norm() ); - - // starting points: - { - // 1/2: point (0,...,0): - model_param.set_X0 ( NOMAD::Point ( n , 0.0 ) ); - - // 2/2: model center if different than (0,..,0) and if in [-1;1]: - NOMAD::Point x1 = model.get_center(); - - if ( x1.size() == n && x1.is_complete() ) { - - model.scale ( x1 ); - - bool diff = false; - bool bnd_ok = true; - - for ( i = 0 ; i < n ; ++i ) { - - if ( x1[i] != 0 ) - diff = true; - - if ( x1[i].abs() > 1.0 ) { - bnd_ok = false; - break; - } - - x1[i] *= 1000.0; - } - - if ( diff && bnd_ok ) - model_param.set_X0 ( x1 ); - } - } - - // fixed variables: - for ( i = 0 ; i < n ; ++i ) - if ( model.variable_is_fixed(i) || _p.variable_is_fixed(i) ) - model_param.set_FIXED_VARIABLE(i); - - // no model search and no model ordering: - model_param.set_MODEL_SEARCH ( false ); - model_param.set_MODEL_EVAL_SORT ( false ); - model_param.set_DIRECTION_TYPE(NOMAD::ORTHO_2N); - - - // display: - model_param.set_DISPLAY_DEGREE ( NOMAD::NO_DISPLAY ); - - - // mesh: - int mesh_index = NOMAD::Mesh::get_mesh_index(); - int min_mesh_index = NOMAD::Mesh::get_min_mesh_index(); - int max_mesh_index = NOMAD::Mesh::get_max_mesh_index(); - int max_halton_index = NOMAD::Mesh::get_max_halton_index(); - - NOMAD::Mesh::init ( 4.0 , 1 , -1 , 0 ); - - model_param.set_INITIAL_MESH_SIZE ( NOMAD::Point ( n , 100.0 ) ); - - // maximum number of evaluations: - if (_p.get_bb_nb_outputs()==2) - model_param.set_MULTI_OVERALL_BB_EVAL ( 50000 ); - else - model_param.set_MAX_BB_EVAL ( 50000 ); - - // min mesh size: - // model_param.set_MAX_MESH_INDEX ( 30 ); - // model_param.set_MIN_MESH_SIZE ( NOMAD::Double ( 1e-8 ) , false ); - - model_param.set_SNAP_TO_BOUNDS ( true ); - // model_param.set_SNAP_TO_BOUNDS ( false ); - // model_param.set_LH_SEARCH ( n*100 , n*10 ); - // model_param.set_OPPORTUNISTIC_LH ( true ); - - // disable user calls: - model_param.set_USER_CALLS_ENABLED ( false ); - - // set flags: - bool flag_check_bimads , flag_reset_mesh , flag_reset_barriers , flag_p1_active; - NOMAD::Mads::get_flags ( flag_check_bimads , - flag_reset_mesh , - flag_reset_barriers , - flag_p1_active ); - - NOMAD::Mads::set_flag_check_bimads (false ); - NOMAD::Mads::set_flag_reset_mesh ( true ); - NOMAD::Mads::set_flag_reset_barriers ( true ); - NOMAD::Mads::set_flag_p1_active ( false ); - - // bounds: - { - NOMAD::Point lb ( n , -1.0 ); - NOMAD::Point ub ( n , 1.0 ); - - const NOMAD::Point & LB = _p.get_lb(); - const NOMAD::Point & UB = _p.get_ub(); - - if ( LB.is_defined() || UB.is_defined() ) - { - - model.unscale ( lb ); - model.unscale ( ub ); - - for ( i = 0 ; i < n ; ++i ) - { - - if ( LB[i].is_defined() && LB[i] > lb[i] ) - lb[i] = LB[i]; - - if ( UB[i].is_defined() && UB[i] < ub[i] ) - ub[i] = UB[i]; - } - - model.scale ( lb ); - model.scale ( ub ); - - for ( i = 0 ; i < n ; ++i ) - { - if ( ub[i] < lb[i] || lb[i] > 0.0 || ub[i] < 0.0 ) - { - error = true; - error_str = "optimization error: problem with bounds"; - break; - } - lb[i] *= 1000.0; - ub[i] *= 1000.0; - } - } - else - { - lb *= 1000.0; - ub *= 1000.0; - } - - model_param.set_LOWER_BOUND ( lb ); - model_param.set_UPPER_BOUND ( ub ); - } - - if ( !error ) - { - - try - { - - // parameters validation: - model_param.check(); - - // model evaluator creation: - NOMAD::Evaluator *ev; - if (model_param.get_bb_nb_outputs()==2) - ev =new NOMAD::Multi_Obj_Quad_Model_Evaluator( model_param , model ); - else - ev=new NOMAD::Single_Obj_Quad_Model_Evaluator(model_param, model); - - // algorithm creation and execution: - NOMAD::Mads mads ( model_param , ev ); - NOMAD::stop_type st = mads.run(); - - delete ev; - - // check the stopping criterion: - if ( st == NOMAD::CTRL_C || st == NOMAD::MAX_CACHE_MEMORY_REACHED ) { - std::ostringstream oss; - oss << "model optimization: " << st; - error_str = oss.str(); - error = true; - stop = true; - stop_reason = st; - } - - else if ( st == NOMAD::MAX_BB_EVAL_REACHED ) - _one_search_stats.add_MS_max_bbe(); - - // display solution: + xf.clear(); + xi.clear(); + + int n = model.get_n(); + bool error = false; + std::string error_str; + int i; + + // initial displays: + if ( display_degree == NOMAD::FULL_DISPLAY ) { + std::ostringstream oss; + oss << "model optimization"; + if ( xk[0] && xk[1] ) + oss << " (" << i_inc+1 << "/2)"; + out << std::endl << NOMAD::open_block ( oss.str() ); + } + + // parameters creation: + NOMAD::Parameters model_param ( out ); + + // number of variables: + model_param.set_DIMENSION ( n ); + + // blackbox outputs: + model_param.set_BB_OUTPUT_TYPE ( _p.get_bb_output_type() ); + + // barrier parameters: + model_param.set_H_MIN ( _p.get_h_min () ); + model_param.set_H_NORM ( _p.get_h_norm() ); + + // starting points: + { + // 1/2: point (0,...,0): + model_param.set_X0 ( NOMAD::Point ( n , 0.0 ) ); + + // 2/2: model center if different than (0,..,0) and if in [-1;1]: + NOMAD::Point x1 = model.get_center(); + + if ( x1.size() == n && x1.is_complete() ) + { + + model.scale ( x1 ); + + bool diff = false; + bool bnd_ok = true; + + for ( i = 0 ; i < n ; ++i ) + { + + if ( x1[i] != 0 ) + diff = true; + + if ( x1[i].abs() > 1.0 ) + { + bnd_ok = false; + break; + } + + x1[i] *= 1000.0; + } + + if ( diff && bnd_ok ) + model_param.set_X0 ( x1 ); + } + } + + // fixed variables: + for ( i = 0 ; i < n ; ++i ) + if ( model.variable_is_fixed(i) || _p.variable_is_fixed(i) ) + model_param.set_FIXED_VARIABLE(i); + + // no model search and no model ordering: + model_param.set_MODEL_SEARCH ( false ); + model_param.set_MODEL_EVAL_SORT ( false ); + model_param.set_DIRECTION_TYPE(NOMAD::ORTHO_2N); + + + // display: + model_param.set_DISPLAY_DEGREE ( NOMAD::NO_DISPLAY ); + + // mesh: use isotropic mesh + model_param.set_ANISOTROPIC_MESH ( false ); + model_param.set_MESH_UPDATE_BASIS ( 4.0 ); + model_param.set_MESH_COARSENING_EXPONENT ( 1 ); + model_param.set_MESH_REFINING_EXPONENT ( -1 ); + model_param.set_INITIAL_MESH_INDEX ( 0 ); + model_param.set_INITIAL_MESH_SIZE ( NOMAD::Point ( n , 100.0 ) ); + + // maximum number of evaluations: + if (_p.get_nb_obj()==2) + model_param.set_MULTI_OVERALL_BB_EVAL ( 50000 ); + else + model_param.set_MAX_BB_EVAL ( 50000 ); + + + model_param.set_SNAP_TO_BOUNDS ( true ); + + // disable user calls: + model_param.set_USER_CALLS_ENABLED ( false ); + + // set flags: + bool flag_check_bimads , flag_reset_mesh , flag_reset_barriers , flag_p1_active; + NOMAD::Mads::get_flags ( flag_check_bimads , + flag_reset_mesh , + flag_reset_barriers , + flag_p1_active ); + + NOMAD::Mads::set_flag_check_bimads (false ); + NOMAD::Mads::set_flag_reset_mesh ( true ); + NOMAD::Mads::set_flag_reset_barriers ( true ); + NOMAD::Mads::set_flag_p1_active ( false ); + + // bounds: + { + NOMAD::Point lb ( n , -1.0 ); + NOMAD::Point ub ( n , 1.0 ); + + const NOMAD::Point & LB = _p.get_lb(); + const NOMAD::Point & UB = _p.get_ub(); + + if ( LB.is_defined() || UB.is_defined() ) + { + + model.unscale ( lb ); + model.unscale ( ub ); + + for ( i = 0 ; i < n ; ++i ) + { + + if ( LB[i].is_defined() && LB[i] > lb[i] ) + lb[i] = LB[i]; + + if ( UB[i].is_defined() && UB[i] < ub[i] ) + ub[i] = UB[i]; + } + + model.scale ( lb ); + model.scale ( ub ); + + for ( i = 0 ; i < n ; ++i ) + { + if ( ub[i] < lb[i] || lb[i] > 0.0 || ub[i] < 0.0 ) + { + error = true; + error_str = "optimization error: problem with bounds"; + break; + } + lb[i] *= 1000.0; + ub[i] *= 1000.0; + } + } + else + { + lb *= 1000.0; + ub *= 1000.0; + } + + model_param.set_LOWER_BOUND ( lb ); + model_param.set_UPPER_BOUND ( ub ); + } + + if ( !error ) + { + + try + { + + // parameters validation: + model_param.check(); + + // model evaluator creation: + NOMAD::Evaluator *ev; + if (model_param.get_nb_obj()==2) + ev =new NOMAD::Multi_Obj_Quad_Model_Evaluator( model_param , model ); + else + ev=new NOMAD::Single_Obj_Quad_Model_Evaluator(model_param, model); + + // algorithm creation and execution: + NOMAD::Mads mads ( model_param , ev ); + + // Handle the case where nb_bb_obj>=2 but no-bimads (case of PhaseOneSearch) ---> need Phase_One_Evaluator for compute_f + NOMAD::Phase_One_Evaluator * p1ev=NULL; + if ( model_param.get_nb_obj() >= 2 && ! flag_check_bimads ) + { + p1ev = new NOMAD::Phase_One_Evaluator ( model_param , *ev ); + mads.get_evaluator_control().set_evaluator ( p1ev ); + } + + NOMAD::stop_type st = mads.run(); + + delete ev; + if (p1ev) + delete p1ev; + + // check the stopping criterion: + if ( st == NOMAD::CTRL_C || st == NOMAD::MAX_CACHE_MEMORY_REACHED ) { + std::ostringstream oss; + oss << "model optimization: " << st; + error_str = oss.str(); + error = true; + stop = true; + stop_reason = st; + } + + else if ( st == NOMAD::MAX_BB_EVAL_REACHED ) + _one_search_stats.add_MS_max_bbe(); + + // display solution: #ifdef DEBUG - NOMAD::Display out_tmp = out; - out_tmp.set_degrees ( NOMAD::NORMAL_DISPLAY ); - mads.display ( out_tmp ); + NOMAD::Display out_tmp = out; + out_tmp.set_degrees ( NOMAD::NORMAL_DISPLAY ); + mads.display ( out_tmp ); #endif - - // update the stats on the number of model evaluations: - _one_search_stats.update_MS_model_opt ( mads.get_stats().get_bb_eval() ); - - // get the solution(s): - const NOMAD::Eval_Point * best_feas = mads.get_best_feasible (); - const NOMAD::Eval_Point * best_infeas = mads.get_best_infeasible(); - - if ( best_feas ) { - xf = *best_feas; - xf *= 0.001; - - if ( display_degree == NOMAD::FULL_DISPLAY ) { - out << "best feasible point after unscaling : ( "; - xf.NOMAD::Point::display ( out ); - out << " )" << std::endl; - } - - model.unscale ( xf ); - } - else if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "no feasible solution" << std::endl; - - if ( best_infeas ) { - xi = *best_infeas; - xi *= 0.001; - - if ( display_degree == NOMAD::FULL_DISPLAY ) { - out << "best infeasible point before unscaling: ( "; - xi.NOMAD::Point::display ( out ); - out << " )" << std::endl; - } - - model.unscale ( xi ); - } - else if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "no infeasible solution" << std::endl; - - if ( !xf.is_defined() && !xi.is_defined() ) { - error = true; - error_str = "optimization error: no solution"; - } - } - catch ( std::exception & e ) { - error = true; - error_str = std::string ( "optimization error: " ) + e.what(); - } - } - - // error before run: - else if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "error before run" << std::endl; - - // reset flags: - NOMAD::Mads::set_flag_check_bimads ( flag_check_bimads ); - NOMAD::Mads::set_flag_reset_mesh ( flag_reset_mesh ); - NOMAD::Mads::set_flag_reset_barriers ( flag_reset_barriers ); - NOMAD::Mads::set_flag_p1_active ( flag_p1_active ); - - // reset mesh to what it was before: - NOMAD::Mesh::init ( _p.get_mesh_update_basis().value() , - _p.get_mesh_coarsening_exponent() , - _p.get_mesh_refining_exponent() , - _p.get_initial_mesh_index() ); - - NOMAD::Mesh::set_max_halton_index ( max_halton_index ); - - NOMAD::Mesh::set_mesh_index ( mesh_index ); - NOMAD::Mesh::set_min_mesh_index ( min_mesh_index ); - NOMAD::Mesh::set_max_mesh_index ( max_mesh_index ); - - - - - // close display block: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - if ( error ) - out.close_block ( error_str ); - else - out.close_block(); - out << std::endl; - } - - return !error; + + // update the stats on the number of model evaluations: + _one_search_stats.update_MS_model_opt ( mads.get_stats().get_bb_eval() ); + + // get the solution(s): + const NOMAD::Eval_Point * best_feas = mads.get_best_feasible (); + const NOMAD::Eval_Point * best_infeas = mads.get_best_infeasible(); + + if ( best_feas ) { + xf = *best_feas; + xf *= 0.001; + + if ( display_degree == NOMAD::FULL_DISPLAY ) { + out << "best feasible point after unscaling : ( "; + xf.NOMAD::Point::display ( out ); + out << " )" << std::endl; + } + + model.unscale ( xf ); + } + else if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "no feasible solution" << std::endl; + + if ( best_infeas ) { + xi = *best_infeas; + xi *= 0.001; + + if ( display_degree == NOMAD::FULL_DISPLAY ) { + out << "best infeasible point before unscaling: ( "; + xi.NOMAD::Point::display ( out ); + out << " )" << std::endl; + } + + model.unscale ( xi ); + } + else if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "no infeasible solution" << std::endl; + + if ( !xf.is_defined() && !xi.is_defined() ) { + error = true; + error_str = "optimization error: no solution"; + } + } + catch ( std::exception & e ) { + error = true; + error_str = std::string ( "optimization error: " ) + e.what(); + } + } + + // error before run: + else if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "error before run" << std::endl; + + // reset flags: + NOMAD::Mads::set_flag_check_bimads ( flag_check_bimads ); + NOMAD::Mads::set_flag_reset_mesh ( flag_reset_mesh ); + NOMAD::Mads::set_flag_reset_barriers ( flag_reset_barriers ); + NOMAD::Mads::set_flag_p1_active ( flag_p1_active ); + + + // close display block: + if ( display_degree == NOMAD::FULL_DISPLAY ) { + if ( error ) + out.close_block ( error_str ); + else + out.close_block(); + out << std::endl; + } + + return !error; } diff --git a/src/Quad_Model_Search.hpp b/src/Quad_Model_Search.hpp index 92ec2e2..1f2d19e 100644 --- a/src/Quad_Model_Search.hpp +++ b/src/Quad_Model_Search.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -85,8 +85,8 @@ namespace NOMAD { \param x The point coordinates -- \b IN. \param model The model -- \b IN. \param signature Signature -- \b IN. - \param mesh_index Mesh index -- \b IN. - \param delta_m Mesh size parameter -- \b IN. + \param mesh_indices Mesh indic -- \b IN. + \param delta Mesh size parameter -- \b IN. \param display_degree Display degree -- \b IN. \param out The NOMAD::Display object -- \b IN. */ @@ -95,11 +95,11 @@ namespace NOMAD { NOMAD::Point x , const NOMAD::Quad_Model & model , NOMAD::Signature & signature , - int mesh_index , - const NOMAD::Point & delta_m , + const NOMAD::Point & mesh_indices , + const NOMAD::Point & delta , NOMAD::dd_type display_degree , const NOMAD::Display & out ); - + /*----------------------------------------------------------------------*/ public: diff --git a/src/RNG.cpp b/src/RNG.cpp index 42e70a6..c37391f 100644 --- a/src/RNG.cpp +++ b/src/RNG.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2010 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -39,38 +39,79 @@ */ #include "RNG.hpp" +#include <math.h> +//** Default values for the provided number seed */ +int NOMAD::RNG::_s = 0; -//** Default values for the random number seed */ -uint32_t NOMAD::RNG::x = 123456789; -uint32_t NOMAD::RNG::y = 362436069; -uint32_t NOMAD::RNG::z = 521288629; +uint32_t NOMAD::RNG::x_def = 123456789; +uint32_t NOMAD::RNG::y_def = 362436069; +uint32_t NOMAD::RNG::z_def = 521288629; +uint32_t NOMAD::RNG::_x = x_def; +uint32_t NOMAD::RNG::_y = y_def; +uint32_t NOMAD::RNG::_z = z_def; -bool NOMAD::RNG::set_seed(unsigned long s) + +void NOMAD::RNG::set_seed(int s) { - if(s<=UINT32_MAX) - { - x=s; - return true; - } - else - return false; + + if( s<=INT_MAX && s>=0 ) + _s=s; + else + throw NOMAD::Exception ( "RNG.cpp" , __LINE__ , + "NOMAD::RNG::set_seed(): invalid seed. Seed should be in [0,INT_MAX]" ); + + reset_seed_to_default(); + for ( int i=0 ; i<_s ; i++) + NOMAD::RNG::rand(); + + } uint32_t NOMAD::RNG::rand ( void ) -{ //period 2^96-1 +{ + // http://madrabbit.org/~ray/code/xorshf96.c //period 2^96-1 uint32_t t; - x ^= x << 16; - x ^= x >> 5; - x ^= x << 1; + _x ^= _x << 16; + _x ^= _x >> 5; + _x ^= _x << 1; - t = x; - x = y; - y = z; - z = t ^ x ^ y; + t = _x; + _x = _y; + _y = _z; + _z = t ^ _x ^ _y; - return z; + return _z; } + +/*----------------------------------------*/ +/* normal random generators */ +/*----------------------------------------*/ +double NOMAD::RNG::normal_rand( double mean , double var ) +{ + // Box-Muller transformation~\cite{BoMu58} + + double x1 , x2 , w; + + do + { + x1 = NOMAD::RNG::rand(-1.0,1.0); + x2 = NOMAD::RNG::rand(-1.0,1.0); + w = x1 * x1 + x2 * x2; + } while ( w >= 1.0 ); + + w = sqrt( (-2.0 * log( w ) ) / w ); + + return pow ( var,0.5) * x1 * w + mean; +} +double NOMAD::RNG::normal_rand_mean_0 ( double Var , int Nsample ) +{ + double sum = 0.0; + double a=pow( 3.0*Var,0.5 ); + for ( int i=0 ; i<Nsample ; i++ ) + sum+=NOMAD::RNG::rand(-a,a); + return sum / pow( Nsample,0.5 ); +} diff --git a/src/RNG.hpp b/src/RNG.hpp index e7e1ee4..c0f8714 100644 --- a/src/RNG.hpp +++ b/src/RNG.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonsmooth Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2010 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -43,45 +43,90 @@ #define __RNG__ #include "defines.hpp" +#include "Exception.hpp" using namespace std; namespace NOMAD { - - /// Class for random number generator + + /// Class for random number generator /** - This class is used to set a seed for the random number generator and - get a random integer or a random double between two values. + This class is used to set a seed for the random number generator and + get a random integer or a random double between two values. */ class RNG { public: - + + /// Get current seed + /* + /return An integer in [0,UINT32_MAX]. + */ + static int get_seed ( void ) + { + return static_cast<int>(_s); + } + + /// Reset seed to its default value + static void reset_seed_to_default ( void ) + { + _x=x_def; + _y=y_def; + _z=z_def; + } + /// Set seed /* /param s The seed -- \b IN. - /return A boolean if the seed is acceptable, that is in [0,UINT32_MAX]. */ - static bool set_seed(unsigned long s); + static void set_seed(int s); + /// Get a random integer as uint32 - /** This function serves to obtain a random number \c + /** This function serves to obtain a random number \c /return An integer in the interval [0,UINT32_MAX]. */ static uint32_t rand(); + + + /// Get a random number having a normal distribution as double + /* + /param a Lower bound -- \b IN. + /param b Upper bound -- \b IN. + /return A double in the interval [a,b]. + */ + static double rand(double a, double b) + { + return a+((b-a)*NOMAD::RNG::rand())/UINT32_MAX; + } - /// Get a random number as double + /// Get a random number approaching a normal distribution (N(0,Var)) as double + // A series of Nsample random numbers Xi in the interval [-sqrt(3*Var);+sqrt(3*Var)] is used -> E[Xi]=0, Var(Xi)=var + // see http://en.wikipedia.org/wiki/Central_limit_theorem + /* + /param Nsample Number of samples for averaging -- \b IN. + /param Var Variance of the target normal distribution -- \b IN. + /return A double in the interval [-sqrt(3*Var);+sqrt(3*Var)]. + */ + static double normal_rand_mean_0( double Var=1 , int Nsample=12 ) ; + + + /// Get a random number approaching a normal distribution ( N(Mean,Var) ) as double /* - /param a Lower bound -- \b IN. - /param b Upper bound -- \b IN. - /return A double in the interval [a,b]. - */ - static double rand(double a, double b){return a+((b-a)*NOMAD::RNG::rand())/UINT32_MAX;} + /param Mean Mean of the target normal distribution -- \b IN. + /param Var Variance of the target normal distribution -- \b IN. + /return A random number. + */ + static double normal_rand( double Mean=0 , double Var=1 ) ; + private: - static uint32_t x,y,z; ///< Default parameter value for the random seed generator. + + static uint32_t x_def,y_def,z_def,_x,_y,_z; ///< Default parameter value for the random number generator (_s used as the seed). + static int _s; }; } + #endif diff --git a/src/Random_Pickup.cpp b/src/Random_Pickup.cpp index e0208df..1770499 100644 --- a/src/Random_Pickup.cpp +++ b/src/Random_Pickup.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -71,7 +71,7 @@ int NOMAD::Random_Pickup::pickup ( void ) { if ( _n == 0 ) return 0; - int ind = NOMAD::RNG::rand()%_n; + int ind = NOMAD::RNG::rand()%_n; int tmp = _elts[ind]; if ( ind < _n - 1 ) { _elts[ind ] = _elts[_n-1]; diff --git a/src/Random_Pickup.hpp b/src/Random_Pickup.hpp index e17bc2a..b111a86 100644 --- a/src/Random_Pickup.hpp +++ b/src/Random_Pickup.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/SMesh.cpp b/src/SMesh.cpp new file mode 100644 index 0000000..0874614 --- /dev/null +++ b/src/SMesh.cpp @@ -0,0 +1,382 @@ +/*-------------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ +/* */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ +/* Charles Audet - Ecole Polytechnique, Montreal */ +/* Gilles Couture - Ecole Polytechnique, Montreal */ +/* John Dennis - Rice University, Houston */ +/* Sebastien Le Digabel - Ecole Polytechnique, Montreal */ +/* Christophe Tribes - Ecole Polytechnique, Montreal */ +/* */ +/* funded in part by AFOSR and Exxon Mobil */ +/* */ +/* Author: Sebastien Le Digabel */ +/* */ +/* Contact information: */ +/* Ecole Polytechnique de Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* phone : 1-514-340-6053 #6928 */ +/* fax : 1-514-340-5665 */ +/* */ +/* This program is free software: you can redistribute it and/or modify it under the */ +/* terms of the GNU Lesser General Public License as published by the Free Software */ +/* Foundation, either version 3 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 Lesser General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public License along */ +/* with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*-------------------------------------------------------------------------------------*/ +/** + \file SMesh.cpp + \brief Class for the MADS mesh (implementation) + \author Sebastien Le Digabel + \date 2010-04-06 + \see SMesh.hpp +*/ +#include "SMesh.hpp" + + + +/*-----------------------------------------------------------*/ +/* update the mesh */ +/*-----------------------------------------------------------*/ +void NOMAD::SMesh::update ( NOMAD::success_type success , const NOMAD::Direction *dir) // , const NOMAD::OrthogonalMesh * mesh ) +{ + // defaults: + // full success: lk = lk - 1 + // failure : lk = lk + 1 + + + if ( success == NOMAD::FULL_SUCCESS ) + { + _mesh_index -= _coarsening_step; + if ( _mesh_index < -NOMAD::L_LIMITS ) + _mesh_index = -NOMAD::L_LIMITS; + } + else if ( success == NOMAD::UNSUCCESSFUL ) + _mesh_index -= _refining_step; + + if ( _mesh_index > _max_mesh_index ) + _max_mesh_index = _mesh_index; + + + if ( _mesh_index < _min_mesh_index ) + _min_mesh_index = _mesh_index; +} + +/*-----------------------------------------------------------*/ +/* Update the provided mesh indices (the Mesh is unchanged). */ +/*-----------------------------------------------------------*/ +void NOMAD::SMesh::update ( NOMAD::success_type success , NOMAD::Point & mesh_indices, const NOMAD::Direction *dir ) const +{ + + if ( mesh_indices.is_defined() ) + { + for (int i=0; i < mesh_indices.size() ; i++) + { + if ( success == NOMAD::FULL_SUCCESS ) + { + mesh_indices[i] -= _coarsening_step; + if ( mesh_indices[i] < -NOMAD::L_LIMITS ) + mesh_indices[i] = -NOMAD::L_LIMITS; + } + else if ( success == NOMAD::UNSUCCESSFUL ) + mesh_indices[i] -= _refining_step; + } + } +} + + +/*-----------------------------------------------------------*/ +/* manually set the mesh index */ +/*-----------------------------------------------------------*/ +void NOMAD::SMesh::set_mesh_indices ( const NOMAD::Point & r ) +{ + if (!r.is_defined()) + _mesh_index=0; + else + _mesh_index=r[0].NOMAD::Double::round(); + + if ( _mesh_index > _max_mesh_index ) + _max_mesh_index = _mesh_index; + if ( _mesh_index < _min_mesh_index ) + _min_mesh_index = _mesh_index; +} + + + +/*-----------------------------------------------------------*/ +/* set the limit mesh index (max value) */ +/*-----------------------------------------------------------*/ +void NOMAD::SMesh::set_limit_mesh_index ( int l ) +{ + _limit_mesh_index=l; +} + + + +/*-----------------------------------------------------------*/ +/* display */ +/*-----------------------------------------------------------*/ +void NOMAD::SMesh::display ( const NOMAD::Display & out ) const +{ + out << "n : " << get_n() << std::endl + << "mesh update basis : " << _update_basis << std::endl + << "mesh coarsening step: " << _coarsening_step << std::endl + << "mesh refining step : " << _refining_step << std::endl + << "initial mesh size : " + << "(" << _delta_0 << " )" << std::endl; + out << "minimal mesh size : "; + if ( _delta_min.is_defined() ) + out << "(" << _delta_min << " )" << std::endl; + else + out << "none"; + out << std::endl + << "minimal poll size : "; + if ( _Delta_min_is_defined ) + out << "(" << _Delta_min << " )" << std::endl; + else + out << "none"; + out << std::endl; +} + +/*----------------------------------------------------------*/ +/* check the stopping conditions on the minimal poll size */ +/* and on the minimal mesh size */ +/*----------------------------------------------------------*/ +void NOMAD::SMesh::check_min_mesh_sizes ( bool & stop , + NOMAD::stop_type & stop_reason ) const +{ + if ( stop ) + return; + + // 1. mesh index tests: + if ( abs ( _mesh_index ) > NOMAD::L_LIMITS ) + { + stop = true; + stop_reason = NOMAD::L_LIMITS_REACHED; + } + + // 2. delta_k^p (poll size) tests: + if ( check_min_poll_size_criterion ( ) ) + { + stop = true; + stop_reason = NOMAD::DELTA_P_MIN_REACHED; + } + + // 3. delta_k^m (mesh size) tests: + if ( check_min_mesh_size_criterion ( ) ) + { + stop = true; + stop_reason = NOMAD::DELTA_M_MIN_REACHED; + } +} + +/*-----------------------------------------------------------*/ +/* check the minimal poll size (private) */ +/*-----------------------------------------------------------*/ +bool NOMAD::SMesh::check_min_poll_size_criterion ( ) const +{ + if ( !_Delta_min_is_defined ) + return false; + NOMAD::Point Delta; + return get_Delta ( Delta ); +} + +/*-----------------------------------------------------------*/ +/* check the minimal mesh size (private) */ +/*-----------------------------------------------------------*/ +bool NOMAD::SMesh::check_min_mesh_size_criterion ( ) const +{ + if ( !_delta_min.is_defined() ) + return false; + NOMAD::Point delta; + return get_delta ( delta ); +} + +/*----------------------------------------------------------------*/ +/* get delta (mesh size parameter) */ +/* delta^k = delta^0 \tau^{ell_0^+ - ell_k^+} */ +/*----------------------------------------------------------------*/ +/* the function also returns true if one value is < delta_min */ +/* (stopping criterion MIN_MESH_SIZE) */ +/*----------------------------------------------------------------*/ +bool NOMAD::SMesh::get_delta ( NOMAD::Point & delta ) const +{ + delta.reset ( _n ); + + bool delta_min_is_defined=_delta_min.is_defined(); + + + // power_of_tau = tau^{ max{0,l0} - max{0,lk} }: + NOMAD::Double power_of_tau + = pow ( _update_basis.value() , + ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) - + ( (_mesh_index > 0) ? _mesh_index : 0) ); + + bool stop = false; + + // delta^k = power_of_tau * delta^0: + for ( int i = 0 ; i < _n ; ++i ) + { + delta[i] = _delta_0[i] * power_of_tau; + if ( !stop && delta_min_is_defined && delta[i] < _delta_min[i] ) + stop = true; + + } + + return stop; +} + +/*----------------------------------------------------------------*/ +/* get delta (mesh size parameter) */ +/* delta^k = delta^0 \tau^{ell_0^+ - ell_k^+} */ +/*----------------------------------------------------------------*/ +NOMAD::Double NOMAD::SMesh::get_delta ( int i ) const +{ + + + // power_of_tau = tau^{ max{0,l0} - max{0,lk} }: + NOMAD::Double power_of_tau + = pow ( _update_basis.value() , + ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) - + ( (_mesh_index > 0) ? _mesh_index : 0) ); + + + NOMAD::Double delta = _delta_0[i] * power_of_tau; + + return delta; +} + + +/*----------------------------------------------------------------*/ +/* get delta_max (the larget mesh size) */ +/*----------------------------------------------------------------*/ +NOMAD::Point NOMAD::SMesh::get_delta_max ( ) const +{ + + NOMAD::Point delta_max ( _n ); + + // power_of_tau = tau^{ max{0,l0} - max{0,lk} }: + NOMAD::Double power_of_tau + = pow ( _update_basis.value() , + ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) - + ( (_min_mesh_index > 0) ? _min_mesh_index : 0) ); + + // delta^k = power_of_tau * delta^0: + for ( int i = 0 ; i < _n ; ++i ) + delta_max[i] = _delta_0[i] * power_of_tau; + + return delta_max; +} + + +/*-------------------------------------------------------------------*/ +/* get Delta (poll size parameter) */ +/* Delta^k = Delta^m_k \tau^{ |ell_k|/2 } */ +/* = delta^0 \tau^{ell_0^+ - ell_k^+ + |ell_k|/2} */ +/*-------------------------------------------------------------------*/ +/* the function also returns true if all values are < Delta_min */ +/*-------------------------------------------------------------------*/ +bool NOMAD::SMesh::get_Delta ( NOMAD::Point & Delta ) const +{ + + Delta.reset ( _n ); + + // power_of_tau = tau^{ max{0,l0} - max{0,lk} + |lk|/2}: + NOMAD::Double power_of_tau + = pow ( _update_basis.value() , abs(_mesh_index) / 2.0 + + ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) - + ( (_mesh_index > 0) ? _mesh_index : 0) ); + + bool stop = true; + + // Delta^k = power_of_tau * Delta^0: + for ( int i = 0 ; i < _n ; ++i ) + { + Delta[i] = _Delta_0[i] * power_of_tau; + if ( !_Delta_min_is_complete || Delta[i] >= _Delta_min[i] ) + stop = false; + + if ( _Delta_min_is_defined && _Delta_min[i].is_defined() && Delta[i] < _Delta_min[i] ) + Delta[i]=_Delta_min[i]; + } + + return stop; +} + +/*-------------------------------------------------------------------*/ +/* get Delta (poll size parameter) */ +/* Delta^k = Delta^m_k \tau^{ |ell_k|/2 } */ +/* = delta^0 \tau^{ell_0^+ - ell_k^+ + |ell_k|/2} */ +/*--------------------------------------------------------------*/ +/* the function returns Delta >= Delta_min */ +/*--------------------------------------------------------------*/ +NOMAD::Double NOMAD::SMesh::get_Delta ( int i ) const +{ + + // power_of_tau = tau^{ max{0,l0} - max{0,lk} + |lk|/2}: + NOMAD::Double power_of_tau + = pow ( _update_basis.value() , abs(_mesh_index) / 2.0 + + ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) - + ( (_mesh_index > 0) ? _mesh_index : 0) ); + + NOMAD::Double Delta = _Delta_0[i] * power_of_tau; + + if ( _Delta_min_is_defined && _Delta_min[i].is_defined() && Delta < _Delta_min[i] ) + Delta=_Delta_min[i]; + + return Delta; +} + + +NOMAD::Double NOMAD::SMesh::scale_and_project(int i, const NOMAD::Double & l) const +{ + NOMAD::Double delta = get_delta ( i ); + NOMAD::Double Delta = get_Delta ( i ); + + + if ( delta.is_defined() && Delta.is_defined() && i <= _n) + { + NOMAD::Double d= Delta / delta * l; + return d.NOMAD::Double::round()*delta; + } + else + throw NOMAD::Exception ( "SMesh.cpp" , __LINE__ , + "Mesh scaling and projection cannot be performed!" ); + +} + + + + +NOMAD::Point NOMAD::SMesh::get_mesh_ratio_if_success ( void ) const +{ + + NOMAD::Double power_of_tau + = pow ( _update_basis.value() , + ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) - + ( (_mesh_index > 0) ? _mesh_index : 0) ); + + NOMAD::Double power_of_tau_if_success + = pow ( _update_basis.value() , + ( (_initial_mesh_index > 0) ? _initial_mesh_index : 0) - + ( (_mesh_index - _coarsening_step > 0) ? _mesh_index - _coarsening_step : 0) ); + + try + { + NOMAD::Double ratio_scalaire = power_of_tau_if_success/power_of_tau; + return NOMAD::Point( _n , ratio_scalaire ); + } + catch ( NOMAD::Double::Invalid_Value & ) + { + return NOMAD::Point( _n,-1 ); + } +} diff --git a/src/SMesh.hpp b/src/SMesh.hpp new file mode 100644 index 0000000..00f0211 --- /dev/null +++ b/src/SMesh.hpp @@ -0,0 +1,309 @@ +/*-------------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ +/* */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ +/* Charles Audet - Ecole Polytechnique, Montreal */ +/* Gilles Couture - Ecole Polytechnique, Montreal */ +/* John Dennis - Rice University, Houston */ +/* Sebastien Le Digabel - Ecole Polytechnique, Montreal */ +/* Christophe Tribes - Ecole Polytechnique, Montreal */ +/* */ +/* funded in part by AFOSR and Exxon Mobil */ +/* */ +/* Author: Sebastien Le Digabel */ +/* */ +/* Contact information: */ +/* Ecole Polytechnique de Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* phone : 1-514-340-6053 #6928 */ +/* fax : 1-514-340-5665 */ +/* */ +/* This program is free software: you can redistribute it and/or modify it under the */ +/* terms of the GNU Lesser General Public License as published by the Free Software */ +/* Foundation, either version 3 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 Lesser General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public License along */ +/* with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*-------------------------------------------------------------------------------------*/ +/** + \file SMesh.hpp + \brief Class for the static orthogonal MADS mesh (headers) + \author Christophe Tribes + \date 2010-04-06 + \see OrthogonalMesh.cpp SMesh.cpp + */ +#ifndef __SMESH__ +#define __SMESH__ + +#include "Point.hpp" +#include "OrthogonalMesh.hpp" + +namespace NOMAD { + + /// Class for the MADS orthogonal static mesh. + /** + - The static mesh is defined with the basic directions and a + mesh size parameter delta^k. + - The mesh size parameter is defined with a single mesh index (the integer r^k) + and the initial mesh size delta^0 for all coordinates. + - The poll size parameter Delta^k (single value for all coordinates) is not + used to define the mesh but to define the poll trial points. + - At each MADS iteration the mesh is updated with + delta^k+1 = tau^w+ delta^k and w+ >= 0 (dominating iteration) + or with + delta^k+1 = tau^w- delta^k and w- < 0 (iteration failure). + The mesh is not changed after improving iterations. + - Mesh and poll size parameters are stored as NOMAD::Point objects + (one value for each variable). The scaling is done once based on initial mesh size. + - See the MADS papers for more details on the mesh. + */ + + class SMesh : public NOMAD::OrthogonalMesh { + + private: + + int _initial_mesh_index; + int _mesh_index; + int _min_mesh_index; ///< Minimal value reached by the mesh index + int _max_mesh_index; ///< Maximal value reached by the mesh index + + /*--------------------------------------------------------------*/ + + /// Private affectation operator. + /** + \param m The right-hand side object -- \b IN. + */ + const SMesh & operator = ( const SMesh & m ); + + /// Check the minimal poll size criterion. + bool check_min_poll_size_criterion ( ) const; + + /// Check the minimal mesh size criterion. + bool check_min_mesh_size_criterion ( ) const; + + /// Access to the mesh size parameter delta^k. + /** + \return delta The mesh size parameter delta^k -- \b OUT. + \param i The index of the mesh size + */ + NOMAD::Double get_delta ( int i ) const ; + + + /// Access to the poll size parameter Delta^k. + /** + \return Delta The poll size parameter Delta^k -- \b OUT. + \param i The index of the poll size + */ + NOMAD::Double get_Delta ( int i ) const ; + + + + /*--------------------------------------------------------------*/ + + public: + + /// Constructor. + /** + \param delta_0 Initial mesh size delta_0 -- \b IN. + \param Delta_min Minimal poll size Delta_min (may be undefined) -- \b IN. + \param delta_min Minimal mesh size delta_min (may be undefined) -- \b IN. + \param mesh_update_basis Mesh update basis (tau), default=4 -- \b IN. + \param mesh_coarsening_step Mesh coarsening step (w+), default=1 -- \b IN. + \param mesh_refining_step Mesh refining step (w-), default=-1 -- \b IN. + \param initial_mesh_index Initial mesh index ell_0, default=0 -- \b IN. + \param limit_max_mesh_index Limit max of the mesh index, default=L_LIMITS -- \b IN. + \param fixed_variables Fixed variables -- \b IN. + */ + SMesh ( const NOMAD::Point & delta_0 , + const NOMAD::Point & Delta_min , + const NOMAD::Point & delta_min , + const NOMAD::Point & fixed_variables , + NOMAD::Double mesh_update_basis=4.0, + int mesh_coarsening_step=1, + int mesh_refining_step=-1, + int initial_mesh_index=0, + int limit_max_mesh_index=NOMAD::L_LIMITS) + : NOMAD::OrthogonalMesh ( delta_0, + Delta_min, + delta_min, + fixed_variables, + mesh_update_basis, + mesh_coarsening_step, + mesh_refining_step , + limit_max_mesh_index ), + _initial_mesh_index ( initial_mesh_index ), + _mesh_index ( _initial_mesh_index ), + _min_mesh_index ( initial_mesh_index ), + _max_mesh_index ( initial_mesh_index ) {} + + + /// Copy constructor. + /** + \param m The copied object -- \b IN. + */ + SMesh ( const SMesh & m ) + : OrthogonalMesh(m) , + _initial_mesh_index ( m._initial_mesh_index ), + _mesh_index ( m._initial_mesh_index ), + _min_mesh_index( m._initial_mesh_index ), + _max_mesh_index ( m._initial_mesh_index ) {} + + /// Destructor. + virtual ~SMesh ( void ) + { + _delta_0.clear(); + _Delta_0.clear(); + _delta_min.clear(); + _Delta_min.clear(); + } + + + /// Access to the mesh index. + /** + \return A Point with the mesh index. + */ + const NOMAD::Point get_mesh_indices ( void ) const + { + return NOMAD::Point( 1 , NOMAD::Double(_mesh_index) ); + } + + /// Access to the min mesh index reached so far. + /** + \return A Point with the mesh index. + */ + const NOMAD::Point get_min_mesh_indices ( void ) const + { + return NOMAD::Point( 1 , NOMAD::Double(_min_mesh_index) ); + } + + + /// Access to the max mesh index reached so far. + /** + \return A Point with the mesh index. + */ + const NOMAD::Point get_max_mesh_indices ( void ) const + { + return NOMAD::Point( 1 , NOMAD::Double(_max_mesh_index) ); + } + + + /// Manually set the mesh index using a point. (set_mesh_indices for consistency with XMesh) + /** + \param r The mesh index provided as a point -- \b IN. + */ + void set_mesh_indices ( const NOMAD::Point & r ); + + + + /// Manually set the limit mesh index used for termination criterion (max value for SMesh). + /** + \param l The limit mesh index for all coordinates -- \b IN. + */ + void set_limit_mesh_index ( int l ); + + + + /// Test if finest mesh so far. + /** + \return True if mesh index greater or equal to the maximal mesh index; False otherwise. + */ + bool is_finest(void) const {return _mesh_index >= _max_mesh_index; } + + + /// Access to the mesh ratios after a success + /** + \return A point with the ratio for each coordinate + */ + NOMAD::Point get_mesh_ratio_if_success( void ) const; + + + /// Update the provided mesh indices (the Mesh is unchanged). + /** + \param success Type of success of the iteration -- \b IN. + \param mesh_indices The mesh indices before and after the update -- \b IN/OUT. + \param dir The direction that is considered (opt) -- \b IN. + */ + void update ( NOMAD::success_type success , NOMAD::Point & mesh_indices, const NOMAD::Direction *dir=NULL ) const ; + + + /// Update the Mesh. + /** + \param success Type of success of the iteration -- \b IN. + \param dir The direction that is considered (opt) -- \b IN. + */ + void update ( NOMAD::success_type success , const NOMAD::Direction *dir=NULL); + + + /// Reset the mesh to its original size (mesh indices). + void reset ( void ) + { + set_mesh_indices( NOMAD::Point(1,NOMAD::Double(_initial_mesh_index))) ; + _min_mesh_index=_initial_mesh_index ; + _max_mesh_index=_initial_mesh_index; + } + + /// Access to the mesh size parameter delta^k. + /** + \param delta The mesh size parameter delta^k -- \b OUT. + \return A boolean equal to \c true if all values are + strictly inferior than the associated minimal + mesh size delta_min + (stopping criterion MIN_MESH_SIZE). + */ + virtual bool get_delta ( NOMAD::Point & delta ) const ; + + + + + /// Access to the larget mesh size so far. + /** + \return delta_max The largest mesh size reached so far -- \b OUT. + */ + NOMAD::Point get_delta_max ( void ) const ; + + /// Access to the poll size parameter Delta^k. + /** + \param Delta The poll size parameter Delta^k -- \b OUT. + \return A boolean equal to \c true if all values are + strictly inferior than the associated minimal + mesh size Delta_min + (stopping criterion MIN_POLL_SIZE). + */ + virtual bool get_Delta ( NOMAD::Point & Delta ) const ; + + + /// Check the stopping conditions on the minimal poll and mesh sizes. + /** + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + */ + void check_min_mesh_sizes ( bool & stop , + NOMAD::stop_type & stop_reason ) const; + /// Display. + /** + \param out The NOMAD::Display object -- \b IN. + */ + void display ( const NOMAD::Display & out ) const; + + + /// Scale and project the ith component of a vector on the mesh + /** + \param i The vector component number -- \b IN. + \param l The vector component value -- \b IN. + \return The ith component of a vector after mesh scaling and projection + */ + NOMAD::Double scale_and_project(int i, const NOMAD::Double & l) const ; + + + }; +} + +#endif diff --git a/src/Search.hpp b/src/Search.hpp index 07ed31a..a7b6b2e 100644 --- a/src/Search.hpp +++ b/src/Search.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Set_Element.hpp b/src/Set_Element.hpp index def08a7..092346a 100644 --- a/src/Set_Element.hpp +++ b/src/Set_Element.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Signature.cpp b/src/Signature.cpp index ee7fa00..cba5d26 100644 --- a/src/Signature.cpp +++ b/src/Signature.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,13 +34,15 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Signature.cpp - \brief Evaluation point signature (implementation) - \author Sebastien Le Digabel - \date 2010-04-22 - \see Signature.hpp -*/ + \file Signature.cpp + \brief Evaluation point signature (implementation) + \author Sebastien Le Digabel + \date 2010-04-22 + \see Signature.hpp + */ #include "Signature.hpp" +#include "SMesh.hpp" +#include "XMesh.hpp" /*-----------------------------------*/ /* static members initialization */ @@ -56,38 +58,62 @@ bool NOMAD::Signature::_warning_has_been_displayed=false; /* constructor 1 */ /*--------------------------------------------------*/ NOMAD::Signature::Signature -( int n , - const std::vector<NOMAD::bb_input_type> & input_types , - const NOMAD::Point & initial_mesh_size , - const NOMAD::Point & min_mesh_size , - const NOMAD::Point & min_poll_size , - const NOMAD::Point & lb , - const NOMAD::Point & ub , - const NOMAD::Point & scaling , - const NOMAD::Point & fixed_variables , - const std::vector<bool> & periodic_variables , - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups , - const NOMAD::Display & out ) - : _mesh ( NULL ) , - _std ( false ) , - _out (out) +( int n , + const std::vector<NOMAD::bb_input_type> & input_types , + const NOMAD::Point & lb , + const NOMAD::Point & ub , + bool use_smesh , + bool anisotropic_mesh , + const NOMAD::Point & initial_poll_size , + const NOMAD::Point & min_poll_size , + const NOMAD::Point & min_mesh_size , + NOMAD::Double & mesh_update_basis , + NOMAD::Double & poll_update_basis , + int & mesh_coarsening_exponent, + int & mesh_refining_exponent, + int initial_mesh_index , + const NOMAD::Point & scaling , + const NOMAD::Point & fixed_variables , + const std::vector<bool> & periodic_variables, + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups , + const NOMAD::Display & out ) +: _std ( false ) , +_out ( out ) { - init ( n , - input_types , - initial_mesh_size , - min_mesh_size , - min_poll_size , - lb , - ub , - scaling , - fixed_variables , - periodic_variables , - var_groups ); - + // Mesh index starts at 0 for an xmesh and decreases as the mesh size decreases + // The mesh index is reset to 0 as the mesh is reset. + if ( ! use_smesh ) + _mesh=new NOMAD::XMesh(anisotropic_mesh, + initial_poll_size, + min_poll_size, + min_mesh_size, + fixed_variables, + poll_update_basis, // XMesh set poll update basis (default 2) + mesh_coarsening_exponent, + mesh_refining_exponent); + else // Mesh index can be provided for isotropic smesh and increases as the mesh size decreases + _mesh=new NOMAD::SMesh(initial_poll_size, // new initial_poll_size ~ old initial mesh size + min_poll_size, + min_mesh_size, + fixed_variables, + mesh_update_basis, // SMesh set mesh update basis (default 4) + mesh_coarsening_exponent, + mesh_refining_exponent, + initial_mesh_index ); + + init ( n , + input_types , + lb , + ub , + scaling , + fixed_variables , + periodic_variables , + var_groups ); + #ifdef MEMORY_DEBUG - ++NOMAD::Signature::_cardinality; - if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality ) - ++NOMAD::Signature::_max_cardinality; + ++NOMAD::Signature::_cardinality; + if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality ) + ++NOMAD::Signature::_max_cardinality; #endif } @@ -96,79 +122,81 @@ NOMAD::Signature::Signature /*--------------------------------------------------*/ NOMAD::Signature::Signature ( int n , - const std::vector<NOMAD::bb_input_type> & input_types , - const NOMAD::Point & initial_mesh_size , - const NOMAD::Point & lb , - const NOMAD::Point & ub , - const std::set<NOMAD::direction_type> & direction_types , - const std::set<NOMAD::direction_type> & sec_poll_dir_types , - int halton_seed , - const NOMAD::Display & out ) - : _mesh ( NULL ) , - _std ( false ) , - _out ( out ) + const std::vector<NOMAD::bb_input_type> & input_types , + const NOMAD::Point & initial_poll_size , + const NOMAD::Point & lb , + const NOMAD::Point & ub , + const std::set<NOMAD::direction_type> & direction_types , + const std::set<NOMAD::direction_type> & sec_poll_dir_types , + const NOMAD::Display & out ) +: _std ( false ) , +_out ( out ) { - if ( static_cast<int> ( input_types.size() ) != n ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::Signature(): bad argument: input_types" ); - - // automatic creation of groups of variables: - // ------------------------------------------ - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> var_groups; - - { - std::set<int> vi_cbi; // list of cont./bin./int. variables - std::set<int> vi_cat; // list of categorical variables - - for ( int i = 0 ; i < n ; ++i ) - if ( input_types[i] != NOMAD::CATEGORICAL ) - vi_cbi.insert(i); - else - vi_cat.insert(i); - - // creation of a group for cont./bin./int. variables: - if ( !vi_cbi.empty() ) - var_groups.insert ( new NOMAD::Variable_Group ( vi_cbi , - direction_types , - sec_poll_dir_types , - halton_seed++ , - out ) ); - - // creation of a group for categorical variables: - if ( !vi_cat.empty() ) - var_groups.insert ( new NOMAD::Variable_Group ( vi_cat , - direction_types , - sec_poll_dir_types, - -1 , // no Halton seed - out ) ); - - } - - // init: - // ----- - init ( n , - input_types , - initial_mesh_size , - NOMAD::Point() , - NOMAD::Point() , - lb , - ub , - NOMAD::Point() , - NOMAD::Point() , - std::vector<bool>() , - var_groups ); - - // delete the temporary groups of variables: - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::iterator + if ( static_cast<int> ( input_types.size() ) != n ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::Signature(): bad argument: input_types" ); + + // Default mesh is isotropic xmesh + //------------------------------------------ + _mesh=new NOMAD::XMesh (false, + initial_poll_size, + NOMAD::Point(), + NOMAD::Point(), + NOMAD::Point()); + + + // automatic creation of groups of variables: + // ------------------------------------------ + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> var_groups; + + { + std::set<int> vi_cbi; // list of cont./bin./int. variables + std::set<int> vi_cat; // list of categorical variables + + for ( int i = 0 ; i < n ; ++i ) + if ( input_types[i] != NOMAD::CATEGORICAL ) + vi_cbi.insert(i); + else + vi_cat.insert(i); + + // creation of a group for cont./bin./int. variables: + if ( !vi_cbi.empty() ) + var_groups.insert ( new NOMAD::Variable_Group ( vi_cbi , + direction_types , + sec_poll_dir_types , + out ) ); + + // creation of a group for categorical variables: + if ( !vi_cat.empty() ) + var_groups.insert ( new NOMAD::Variable_Group ( vi_cat , + direction_types , + sec_poll_dir_types, + out ) ); + + } + + // init: + // ----- + init ( n , + input_types , + lb , + ub , + NOMAD::Point() , + NOMAD::Point() , + std::vector<bool>() , + var_groups ); + + // delete the temporary groups of variables: + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::iterator it , end = var_groups.end(); - - for ( it = var_groups.begin() ; it != end ; ++it ) - delete *it; - + + for ( it = var_groups.begin() ; it != end ; ++it ) + delete *it; + #ifdef MEMORY_DEBUG - ++NOMAD::Signature::_cardinality; - if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality ) - ++NOMAD::Signature::_max_cardinality; + ++NOMAD::Signature::_cardinality; + if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality ) + ++NOMAD::Signature::_max_cardinality; #endif } @@ -176,29 +204,35 @@ NOMAD::Signature::Signature /* copy constructor */ /*--------------------------------------------------*/ NOMAD::Signature::Signature ( const NOMAD::Signature & s ) - : _lb ( s._lb ) , - _ub ( s._ub ) , - _scaling ( s._scaling ) , - _fixed_variables ( s._fixed_variables ) , - _input_types ( s._input_types ) , - _all_continuous ( s._all_continuous ) , - _has_categorical ( s._has_categorical ) , - _periodic_variables ( s._periodic_variables ) , - _mesh ( new NOMAD::Mesh(*s._mesh) ) , - _std ( false ) , - _feas_success_dir ( s._feas_success_dir ) , - _infeas_success_dir ( s._infeas_success_dir ) , - _out (s._out) +: _lb ( s._lb ) , +_ub ( s._ub ) , +_scaling ( s._scaling ) , +_fixed_variables ( s._fixed_variables ) , +_input_types ( s._input_types ) , +_all_continuous ( s._all_continuous ) , +_has_categorical ( s._has_categorical ) , +_periodic_variables ( s._periodic_variables ) , +_std ( false ) , +_feas_success_dir ( s._feas_success_dir ) , +_infeas_success_dir ( s._infeas_success_dir ) , +_out (s._out) { - std::list<NOMAD::Variable_Group *>::const_iterator it , end = s._var_groups.end(); - for ( it = s._var_groups.begin() ; it != end ; ++it ) - _var_groups.push_back ( new NOMAD::Variable_Group(**it) ); - + + + if (dynamic_cast<NOMAD::SMesh*> (s._mesh)) + _mesh = new NOMAD::SMesh (*(static_cast<NOMAD::SMesh*>(s._mesh))); + else + _mesh = new NOMAD::XMesh (*(static_cast<NOMAD::XMesh*>(s._mesh))); + + std::list<NOMAD::Variable_Group *>::const_iterator it , end = s._var_groups.end(); + for ( it = s._var_groups.begin() ; it != end ; ++it ) + _var_groups.push_back ( new NOMAD::Variable_Group(**it) ); + #ifdef MEMORY_DEBUG - ++NOMAD::Signature::_cardinality; - if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality ) - ++NOMAD::Signature::_max_cardinality; -#endif + ++NOMAD::Signature::_cardinality; + if ( NOMAD::Signature::_cardinality > NOMAD::Signature::_max_cardinality ) + ++NOMAD::Signature::_max_cardinality; +#endif } /*--------------------------------------------------*/ @@ -206,9 +240,9 @@ NOMAD::Signature::Signature ( const NOMAD::Signature & s ) /*--------------------------------------------------*/ NOMAD::Signature::~Signature ( void ) { - clear(); + clear(); #ifdef MEMORY_DEBUG - --NOMAD::Signature::_cardinality; + --NOMAD::Signature::_cardinality; #endif } @@ -217,20 +251,20 @@ NOMAD::Signature::~Signature ( void ) /*--------------------------------------------------------------------------------*/ void NOMAD::Signature::clear ( void ) { - delete _mesh; - _mesh = NULL; - _all_continuous = true; - _has_categorical = false; - _std = false; - reset_var_groups(); - _feas_success_dir.clear(); - _infeas_success_dir.clear(); - _lb.clear(); - _ub.clear(); - _scaling.clear(); - _fixed_variables.clear(); - _input_types.clear(); - _periodic_variables.clear(); + _all_continuous = true; + _has_categorical = false; + _std = false; + reset_var_groups(); + _feas_success_dir.clear(); + _infeas_success_dir.clear(); + _lb.clear(); + _ub.clear(); + _scaling.clear(); + _fixed_variables.clear(); + _input_types.clear(); + _periodic_variables.clear(); + delete _mesh; + } /*--------------------------------------------------*/ @@ -238,10 +272,10 @@ void NOMAD::Signature::clear ( void ) /*--------------------------------------------------*/ void NOMAD::Signature::set_feas_success_dir ( const NOMAD::Direction & d ) { - if ( d.size() != static_cast<int>(_input_types.size()) ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::set_feas_success_dir(): bad direction" ); - _feas_success_dir = d; + if ( d.size() != static_cast<int>(_input_types.size()) ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::set_feas_success_dir(): bad direction" ); + _feas_success_dir = d; } /*--------------------------------------------------*/ @@ -249,10 +283,10 @@ void NOMAD::Signature::set_feas_success_dir ( const NOMAD::Direction & d ) /*--------------------------------------------------*/ void NOMAD::Signature::set_infeas_success_dir ( const NOMAD::Direction & d ) { - if ( d.size() != static_cast<int>(_input_types.size()) ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::set_infeas_success_dir(): bad direction" ); - _infeas_success_dir = d; + if ( d.size() != static_cast<int>(_input_types.size()) ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::set_infeas_success_dir(): bad direction" ); + _infeas_success_dir = d; } @@ -261,198 +295,201 @@ void NOMAD::Signature::set_infeas_success_dir ( const NOMAD::Direction & d ) /*--------------------------------------------------*/ void NOMAD::Signature::init ( int n , - const std::vector<NOMAD::bb_input_type> & input_types , - const NOMAD::Point & initial_mesh_size , - const NOMAD::Point & min_mesh_size , - const NOMAD::Point & min_poll_size , - const NOMAD::Point & lb , - const NOMAD::Point & ub , - const NOMAD::Point & scaling , - const NOMAD::Point & fixed_variables , - const std::vector<bool> & periodic_variables , - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups ) + const std::vector<NOMAD::bb_input_type> & input_types , + const NOMAD::Point & lb , + const NOMAD::Point & ub , + const NOMAD::Point & scaling , + const NOMAD::Point & fixed_variables , + const std::vector<bool> & periodic_variables , + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups ) { - // reset directions: - _feas_success_dir.clear(); - _infeas_success_dir.clear(); - - // check the dimension (n): - if ( n <= 0 ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): bad argument: n" ); - - // bounds: - if ( lb.empty() ) - _lb.reset ( n ); - else if ( lb.size() == n ) - _lb = lb; - else - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): bad argument: lb" ); - if ( ub.empty() ) - _ub.reset ( n ); - else if ( ub.size() == n ) - _ub = ub; - else - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): bad argument: ub" ); - - // scaling: - if ( scaling.empty() ) - _scaling.reset ( n ); - else if ( scaling.size() == n ) - _scaling = scaling; - else - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): bad argument: scaling" ); - int i; - for ( i = 0 ; i < n ; ++i ) - if ( _scaling[i].is_defined() && _scaling[i] == 0.0 ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): bad argument: scaling (zero value)" ); - - // fixed variables: - if ( fixed_variables.empty() ) - _fixed_variables.reset ( n ); - else if ( fixed_variables.size() == n ) - _fixed_variables = fixed_variables; - else - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): bad argument: fixed_variables" ); - - // periodic variables: - _periodic_variables = periodic_variables; - if ( !_periodic_variables.empty() ) { - - if ( static_cast<int>(periodic_variables.size()) != n ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): bad argument: periodic_variables" ); - - for ( i = 0 ; i < n ; ++i ) - if ( _periodic_variables[i] && ( !_lb[i].is_defined() || !_ub[i].is_defined() ) ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): incompatible periodic variables" ); - } - - // input types: - if ( static_cast<int>(input_types.size()) != n ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): bad argument: input_types" ); - _input_types = input_types; - _all_continuous = true; - _has_categorical = false; - - for ( i = 0 ; i < n ; ++i ) - { - - if ( (_lb[i].is_defined() || _ub[i].is_defined() ) && _input_types[i] == NOMAD::CATEGORICAL && _out.get_gen_dd()>=NOMAD::NORMAL_DISPLAY && !_warning_has_been_displayed ) - { - _out << NOMAD::open_block("Warning:") - << "NOMAD::Signature::init(): Providing bounds for categorical variables is not recommended!" << std::endl - << NOMAD::close_block(); - _warning_has_been_displayed=true; - } - - if ( _fixed_variables[i].is_defined() && ((_lb[i].is_defined() && _fixed_variables[i] < _lb[i]) || (_ub[i].is_defined() && _fixed_variables[i] > _ub[i]) || - ( (_input_types[i] == NOMAD::INTEGER || _input_types[i] == NOMAD::CATEGORICAL ) - && !_fixed_variables[i].is_integer() ) || - ( _input_types[i] == NOMAD::BINARY && !_fixed_variables[i].is_binary() ) ) ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): bad argument: fixed variable inconsistent with bounds or input types" ); - - if ( _lb[i].is_defined() && _ub[i].is_defined() ) - { - if ( _lb[i].is_defined() && _ub[i].is_defined() && _lb[i].value()> ub[i].value() ) - { - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): bad argument: lower bound must be lower than upper bound!" ); - } - if ( _lb[i] == _ub[i] ) - _fixed_variables[i]=_lb[i]; - } - } - for ( i = 0 ; i < n ; ++i ) - { - if ( _input_types[i] == NOMAD::CATEGORICAL ) - { - _has_categorical = true; - _all_continuous = false; - break; - } - if ( _input_types[i] != NOMAD::CONTINUOUS ) - { - _all_continuous = false; - if ( _has_categorical ) - break; - } - - - } - - // variable groups: - reset_var_groups(); - - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::iterator + // reset directions: + _feas_success_dir.clear(); + _infeas_success_dir.clear(); + + // check the dimension (n): + if ( n <= 0 ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): bad argument: n" ); + + // bounds: + if ( lb.empty() ) + _lb.reset ( n ); + else if ( lb.size() == n ) + _lb = lb; + else + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): bad argument: lb" ); + if ( ub.empty() ) + _ub.reset ( n ); + else if ( ub.size() == n ) + _ub = ub; + else + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): bad argument: ub" ); + + // scaling: + if ( scaling.empty() ) + _scaling.reset ( n ); + else if ( scaling.size() == n ) + _scaling = scaling; + else + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): bad argument: scaling" ); + int i; + for ( i = 0 ; i < n ; ++i ) + if ( _scaling[i].is_defined() && _scaling[i] == 0.0 ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): bad argument: scaling (zero value)" ); + + // fixed variables: + if ( fixed_variables.empty() ) + _fixed_variables.reset ( n ); + else if ( fixed_variables.size() == n ) + _fixed_variables = fixed_variables; + else + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): bad argument: fixed_variables" ); + + // periodic variables: + _periodic_variables = periodic_variables; + if ( !_periodic_variables.empty() ) + { + + if ( static_cast<int>(periodic_variables.size()) != n ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): bad argument: periodic_variables" ); + + for ( i = 0 ; i < n ; ++i ) + if ( _periodic_variables[i] && ( !_lb[i].is_defined() || !_ub[i].is_defined() ) ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): incompatible periodic variables" ); + } + + // input types: + if ( static_cast<int>(input_types.size()) != n ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): bad argument: input_types" ); + _input_types = input_types; + _all_continuous = true; + _has_categorical = false; + + for ( i = 0 ; i < n ; ++i ) + { + + if ( (_lb[i].is_defined() || _ub[i].is_defined() ) && _input_types[i] == NOMAD::CATEGORICAL && _out.get_gen_dd()>=NOMAD::NORMAL_DISPLAY && !_warning_has_been_displayed ) + { + _out << NOMAD::open_block("Warning:") + << "NOMAD::Signature::init(): Providing explicit bounds for categorical variables is irrelevant. Bounds are provided implicitely by the neighbors function." << std::endl + << NOMAD::close_block(); + _warning_has_been_displayed=true; + } + + if ( _fixed_variables[i].is_defined() && ((_lb[i].is_defined() && _fixed_variables[i] < _lb[i]) || (_ub[i].is_defined() && _fixed_variables[i] > _ub[i]) || + ( (_input_types[i] == NOMAD::INTEGER || _input_types[i] == NOMAD::CATEGORICAL ) + && !_fixed_variables[i].is_integer() ) || + ( _input_types[i] == NOMAD::BINARY && !_fixed_variables[i].is_binary() ) ) ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): bad argument: fixed variable inconsistent with bounds or input types" ); + + if ( _lb[i].is_defined() && _ub[i].is_defined() ) + { + if ( _lb[i].is_defined() && _ub[i].is_defined() && _lb[i].value()> ub[i].value() ) + { + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): bad argument: lower bound must be lower than upper bound!" ); + } + if ( _lb[i] == _ub[i] ) + _fixed_variables[i]=_lb[i]; + } + } + for ( i = 0 ; i < n ; ++i ) + { + if ( _input_types[i] == NOMAD::CATEGORICAL ) + { + _has_categorical = true; + _all_continuous = false; + break; + } + if ( _input_types[i] != NOMAD::CONTINUOUS ) + { + _all_continuous = false; + if ( _has_categorical ) + break; + } + + + } + + // variable groups: + reset_var_groups(); + + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp>::iterator end = var_groups.end() , it; - bool mod=false; - for ( it = var_groups.begin() ; it != end ; ++it ) - { - - if ( !(*it)->check ( _fixed_variables , input_types , NULL, mod ) ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): incompatible variable group" ); - } - - if (mod) - { - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> tmp_var_groups; - for ( it = var_groups.begin() ; it != end ; ++it ) - { - tmp_var_groups.insert(*it); - } - var_groups.clear(); - var_groups=tmp_var_groups; - tmp_var_groups.clear(); - - } - - for ( it = var_groups.begin() ; it != end ; ++it ) - _var_groups.push_back( new NOMAD::Variable_Group (**it) ); - - - // mesh: - if ( initial_mesh_size.size() != n || - (min_mesh_size.is_defined() && min_mesh_size.size() != n) || - (min_poll_size.is_defined() && min_poll_size.size() != n) ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::init(): mesh arguments with different sizes" ); - delete _mesh; - - try { - _mesh = new NOMAD::Mesh ( initial_mesh_size , min_mesh_size , min_poll_size ); - } - catch ( NOMAD::Exception & e ) - { - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , - *this , e.what() ); - } - + bool mod=false; + for ( it = var_groups.begin() ; it != end ; ++it ) + { + + + if ( !(*it)->check ( _fixed_variables , input_types , NULL, mod ) ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): incompatible variable group" ); + + } + + // if the indices in var_groups have been modified than var_groups is reconstructed to ensure proper ordering + if ( mod ) + { + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> tmp_var_groups; + for ( it = var_groups.begin() ; it != end ; ++it ) + { + tmp_var_groups.insert(*it); + } + var_groups.clear(); + var_groups=tmp_var_groups; + tmp_var_groups.clear(); + + } + + for ( it = var_groups.begin() ; it != end ; ++it ) + _var_groups.push_back( new NOMAD::Variable_Group (**it) ); + + // mesh: + if ( _mesh->get_initial_poll_size().size() != n || + ( _mesh->get_min_mesh_size().is_defined() && _mesh->get_min_mesh_size().size() != n) || + ( _mesh->get_min_poll_size().is_defined() && _mesh->get_min_poll_size().size() != n) ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::init(): mesh arguments with different sizes" ); + + + } /*--------------------------------------------------*/ /* Access to the number of categorical variables */ /*--------------------------------------------------*/ int NOMAD::Signature::get_n_categorical ( void ) const -{ - int n_cat=0; - for (int i = 0 ; i < get_n() ; ++i ) { - if ( _input_types[i] == NOMAD::CATEGORICAL ) - n_cat++; - } - - return n_cat; +{ + int n_cat=0; + for (int i = 0 ; i < get_n() ; ++i ) + if ( _input_types[i] == NOMAD::CATEGORICAL ) + n_cat++; + + return n_cat; +} + +/*--------------------------------------------------*/ +/* Access to the number of categorical variables */ +/*--------------------------------------------------*/ +int NOMAD::Signature::get_nb_fixed_variables ( void ) const +{ + int n_fixed=0; + for (int i = 0 ; i < get_n() ; ++i ) + if ( _fixed_variables[i].is_defined() ) + n_fixed++; + + return n_fixed; } - @@ -461,29 +498,24 @@ int NOMAD::Signature::get_n_categorical ( void ) const /*--------------------------------------------------*/ void NOMAD::Signature::reset ( int n , - const std::vector<NOMAD::bb_input_type> & input_types , - const NOMAD::Point & initial_mesh_size , - const NOMAD::Point & min_mesh_size , - const NOMAD::Point & min_poll_size , - const NOMAD::Point & lb , - const NOMAD::Point & ub , - const NOMAD::Point & scaling , - const NOMAD::Point & fixed_variables , - const std::vector<bool> & periodic_variables , - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups ) + const std::vector<NOMAD::bb_input_type> & input_types , + const NOMAD::Point & lb , + const NOMAD::Point & ub , + const NOMAD::Point & scaling , + const NOMAD::Point & fixed_variables , + const std::vector<bool> & periodic_variables , + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups ) { - reset_var_groups(); - init ( n , - input_types , - initial_mesh_size , - min_mesh_size , - min_poll_size , - lb , - ub , - scaling , - fixed_variables , - periodic_variables , - var_groups ); + reset_mesh(); + reset_var_groups(); + init ( n , + input_types , + lb , + ub , + scaling , + fixed_variables , + periodic_variables , + var_groups ); } /*--------------------------------------------------*/ @@ -491,11 +523,11 @@ void NOMAD::Signature::reset /*--------------------------------------------------*/ void NOMAD::Signature::reset_var_groups ( void ) { - std::list<NOMAD::Variable_Group *>::const_iterator + std::list<NOMAD::Variable_Group *>::const_iterator end = _var_groups.end() , it; - for ( it = _var_groups.begin() ; it != end ; ++it ) - delete *it; - _var_groups.clear(); + for ( it = _var_groups.begin() ; it != end ; ++it ) + delete *it; + _var_groups.clear(); } /*----------------------------------------------------------*/ @@ -506,160 +538,167 @@ void NOMAD::Signature::reset_var_groups ( void ) /*----------------------------------------------------------*/ bool NOMAD::Signature::is_compatible ( const NOMAD::Point & x ) const { - if ( get_n() != x.size() || !_mesh || _var_groups.empty() ) - return false; - return true; + if ( get_n() != x.size() || _var_groups.empty() ) + return false; + return true; } /*-----------------------------------------------------*/ -/* compute the directions (they include delta_m) */ +/* compute the directions */ /*-----------------------------------------------------*/ -void NOMAD::Signature::get_directions ( std::list<NOMAD::Direction> & dirs , - NOMAD::poll_type poll , - const NOMAD::Point & poll_center , - int mesh_index ) +void NOMAD::Signature::get_directions ( std::list<NOMAD::Direction> & dirs , + NOMAD::poll_type poll , + const NOMAD::Point & poll_center ) { - - - NOMAD::Direction * pd; - int i; - std::list<NOMAD::Direction>::const_iterator it_dir , end_dir; - std::set<int>::const_iterator it_vi , end_vi; - - // get delta_m (mesh size parameter): - int n = get_n(); - NOMAD::Point delta_m (n); - NOMAD::Point delta_p (n); - _mesh->get_delta_m ( delta_m , mesh_index ); - _mesh->get_delta_p ( delta_p , mesh_index ); - - - // Reset dir_group_index. - // For each signature, a variable_group has a unique set of directions generated and a unique dir_group_index starting by zero (-1 if no dirs) - _dir_group_index=-1; - - // loop on variable groups: - std::list<NOMAD::Variable_Group*>::const_iterator end_vg = _var_groups.end() , it_vg; - for ( it_vg = _var_groups.begin() ; it_vg != end_vg ; ++it_vg ) - { - - const std::set<int> & var_indexes = (*it_vg)->get_var_indexes(); - - // get the directions for the current group of variables: - std::list<NOMAD::Direction> dirs_nc; - (*it_vg)->get_directions ( dirs_nc, - poll , - poll_center , - mesh_index , - _feas_success_dir , - _infeas_success_dir ); - - // scale with delta_m and resize the directions to size n; - // also round integer and binary variables: - end_dir = dirs_nc.end(); - if (static_cast<int>(dirs_nc.size())!=0) - ++_dir_group_index; - for ( it_dir = dirs_nc.begin() ; it_dir != end_dir ; ++it_dir ) - { - - dirs.push_back ( NOMAD::Direction ( n , 0.0 , it_dir->get_type(),_dir_group_index) ); - - pd = &(*(--dirs.end())); - - end_vi = var_indexes.end(); - i = 0; - for ( it_vi = var_indexes.begin() ; it_vi != end_vi ; ++it_vi ) { - - (*pd)[*it_vi] = delta_m[*it_vi] * (*it_dir)[i++]; - - // integer variables: - if ( _input_types[*it_vi] == NOMAD::INTEGER ) - { - if ( (*pd)[*it_vi] >= delta_p[*it_vi]/3.0 ) - (*pd)[*it_vi] = (*pd)[*it_vi].ceil(); - else if ( (*pd)[*it_vi] <= -delta_p[*it_vi]/3.0 ) - (*pd)[*it_vi] = (*pd)[*it_vi].floor(); - else - (*pd)[*it_vi] = (*pd)[*it_vi].round(); - } - - // binary variables: - else if ( _input_types[*it_vi] == NOMAD::BINARY ) { - if ( (*pd)[*it_vi] != 0.0 ) - (*pd)[*it_vi] = 1.0; - } - - // categorical variables: set direction=0: - else if ( _input_types[*it_vi] == NOMAD::CATEGORICAL ) - (*pd)[*it_vi] = 0.0; - } - } - } + + NOMAD::Direction * pd; + int i; + std::list<NOMAD::Direction>::const_iterator it_dir , end_dir; + std::set<int>::const_iterator it_vi , end_vi; + + int n = get_n(); + NOMAD::Point delta=_mesh->get_delta ( ); + NOMAD::Point Delta=_mesh->get_Delta ( ); + + + // Reset dir_group_index. + // For each signature, a variable_group has a unique set of directions generated and a unique dir_group_index starting by zero (-1 if no dirs) + _dir_group_index=-1; + + // loop on variable groups: + std::list<NOMAD::Variable_Group*>::const_iterator end_vg = _var_groups.end() , it_vg; + for ( it_vg = _var_groups.begin() ; it_vg != end_vg ; ++it_vg ) + { + + const std::set<int> & var_indexes = (*it_vg)->get_var_indexes(); + + // get the directions on a unit nc-sphere for the current group of variables: + std::list<NOMAD::Direction> dirs_nc; + (*it_vg)->get_directions ( dirs_nc , poll , *_mesh ); // _mesh of all directions + + + // scale with delta and resize the directions to size n; + // also round integer and binary variables: + end_dir = dirs_nc.end(); + if (static_cast<int>(dirs_nc.size())!=0) + ++_dir_group_index; + for ( it_dir = dirs_nc.begin() ; it_dir != end_dir ; ++it_dir ) + { + + dirs.push_back ( NOMAD::Direction ( n , 0.0 , it_dir->get_type(),_dir_group_index) ); + + pd = &(*(--dirs.end())); + + end_vi = var_indexes.end(); + i = 0; + + + for ( it_vi = var_indexes.begin() ; it_vi != end_vi ; ++it_vi ,++i) + { + // Scaling and projection on the mesh + (*pd)[*it_vi] = _mesh->scale_and_project(*it_vi,(*it_dir)[i]); + + // integer variables: + if ( _input_types[*it_vi] == NOMAD::INTEGER ) + { + if ( (*pd)[*it_vi] >= Delta[*it_vi]/3.0 ) + (*pd)[*it_vi] = (*pd)[*it_vi].ceil(); + else if ( (*pd)[*it_vi] <= -Delta[*it_vi]/3.0 ) + (*pd)[*it_vi] = (*pd)[*it_vi].floor(); + else + (*pd)[*it_vi] = (*pd)[*it_vi].round(); + } + + // binary variables: + else if ( _input_types[*it_vi] == NOMAD::BINARY ) + { + if ( (*pd)[*it_vi] != 0.0 ) + (*pd)[*it_vi] = 1.0; + } + + // categorical variables: set direction=0: + else if ( _input_types[*it_vi] == NOMAD::CATEGORICAL ) + (*pd)[*it_vi] = 0.0; + } + + } + } } /*----------------------------------------------------------------*/ /* get just one direction for a given mesh (used by VNS search) */ /*----------------------------------------------------------------*/ -void NOMAD::Signature::get_one_direction ( NOMAD::Direction & dir, - int mesh_index, - int halton_index ) const +void NOMAD::Signature::get_one_direction ( NOMAD::Direction & dir , int ell) const { - int i; - std::set<int>::const_iterator it_vi , end_vi; - - // get delta_m (mesh size parameter): - int n = get_n(); - NOMAD::Point delta_m (n); - _mesh->get_delta_m ( delta_m , mesh_index ); - NOMAD::Point delta_p (n); - _mesh->get_delta_p( delta_p , mesh_index ); - - dir.reset ( n , 0.0 ); - dir.set_type ( NOMAD::UNDEFINED_DIRECTION ); - - // loop on variable groups: - std::list<NOMAD::Variable_Group*>::const_iterator end_vg = _var_groups.end() , it_vg; - for ( it_vg = _var_groups.begin() ; it_vg != end_vg ; ++it_vg ) { - - const std::set<int> & var_indexes = (*it_vg)->get_var_indexes(); - - // get the direction for the current group of variables: - NOMAD::Direction dir_nc; - - if ( (*it_vg)->get_one_direction ( dir_nc , mesh_index , halton_index++ ) ) { - - // scale with delta_m and round integer and binary variables: - end_vi = var_indexes.end(); - i = 0; - for ( it_vi = var_indexes.begin() ; it_vi != end_vi ; ++it_vi ) { - - dir[*it_vi] = delta_m[*it_vi] * dir_nc[i++]; - - // integer variables: - if ( _input_types[*it_vi] == NOMAD::INTEGER ) { - if ( dir[*it_vi] >= delta_p[*it_vi]/3.0 ) - dir[*it_vi] = ceil ( dir[*it_vi].value() ); - else if ( dir [*it_vi] <= -delta_p[*it_vi]/3.0 ) - dir[*it_vi] = floor ( dir[*it_vi].value() ); - else - { - double x=dir[*it_vi].value(); - dir[*it_vi] = (x>0)? floor(x+0.5): ceil(x-0.5); - } - } - - // binary variables: - else if ( _input_types[*it_vi] == NOMAD::BINARY ) { - if ( dir[*it_vi] != 0.0 ) - dir[*it_vi] = 1.0; - } - - // categorical variables: set direction=0: - else if ( _input_types[*it_vi] == NOMAD::CATEGORICAL ) - dir[*it_vi] = 0.0; - } - } - } + int i; + std::set<int>::const_iterator it_vi , end_vi; + + // get delta_m (mesh size parameter): + int n = get_n(); + NOMAD::Point delta=_mesh->get_delta ( ); + NOMAD::Point Delta=_mesh->get_Delta ( ); + + dir.reset ( n , 0.0 ); + dir.set_type ( NOMAD::UNDEFINED_DIRECTION ); + + // The mesh indices are modified and must be reset properly once the one direction is obtained + const NOMAD::Point old_mesh_indices=_mesh->get_mesh_indices(); + NOMAD::Point modified_mesh_indices(n,NOMAD::Double(ell)); + _mesh->set_mesh_indices(modified_mesh_indices); + + // loop on variable groups: + std::list<NOMAD::Variable_Group*>::const_iterator end_vg = _var_groups.end() , it_vg; + for ( it_vg = _var_groups.begin() ; it_vg != end_vg ; ++it_vg ) + { + + const std::set<int> & var_indexes = (*it_vg)->get_var_indexes(); + + // get the direction for the current group of variables: + NOMAD::Direction dir_nc ( static_cast<int>(var_indexes.size()) , 0.0 , NOMAD::UNDEFINED_DIRECTION ); + + // get a direction on a unit nc-sphere + if ( (*it_vg)->get_one_direction ( dir_nc ) ) + { + + // scale with delta_m and round integer and binary variables: + end_vi = var_indexes.end(); + i = 0; + for ( it_vi = var_indexes.begin() ; it_vi != end_vi ; ++it_vi ) + { + + dir[*it_vi]=_mesh->scale_and_project(*it_vi,dir_nc[i++]); + + + // integer variables: + if ( _input_types[*it_vi] == NOMAD::INTEGER ) + { + if ( dir[*it_vi] >= Delta[*it_vi]/3.0 ) + dir[*it_vi] = ceil ( dir[*it_vi].value() ); + else if ( dir [*it_vi] <= -Delta[*it_vi]/3.0 ) + dir[*it_vi] = floor ( dir[*it_vi].value() ); + else + { + double x=dir[*it_vi].value(); + dir[*it_vi] = (x>0)? floor(x+0.5): ceil(x-0.5); + } + } + + // binary variables: + else if ( _input_types[*it_vi] == NOMAD::BINARY ) + { + if ( dir[*it_vi] != 0.0 ) + dir[*it_vi] = 1.0; + } + + // categorical variables: set direction=0: + else if ( _input_types[*it_vi] == NOMAD::CATEGORICAL ) + dir[*it_vi] = 0.0; + } + } + } + + // Reset the mesh indices to their previous values + _mesh->set_mesh_indices(old_mesh_indices); } /*----------------------------------*/ @@ -668,16 +707,17 @@ void NOMAD::Signature::get_one_direction ( NOMAD::Direction & dir, /*----------------------------------*/ void NOMAD::Signature::scale ( NOMAD::Point & x ) { - int n = get_n(); - if ( n != x.size() ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::scale(x): x.size() != signature.size()" ); - NOMAD::Double sci; - for ( int i = 0 ; i < n ; ++i ) { - sci = _scaling[i]; - if ( sci.is_defined() ) - x[i] *= sci; - } + int n = get_n(); + if ( n != x.size() ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::scale(x): x.size() != signature.size()" ); + NOMAD::Double sci; + for ( int i = 0 ; i < n ; ++i ) + { + sci = _scaling[i]; + if ( sci.is_defined() ) + x[i] *= sci; + } } /*----------------------------------*/ @@ -686,16 +726,17 @@ void NOMAD::Signature::scale ( NOMAD::Point & x ) /*----------------------------------*/ void NOMAD::Signature::unscale ( NOMAD::Point & x ) { - int n = get_n(); - if ( n != x.size() ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::unscale(x): x.size() != signature.size()" ); - NOMAD::Double sci; - for ( int i = 0 ; i < n ; ++i ) { - sci = _scaling[i]; - if ( sci.is_defined() ) - x[i] /= sci; - } + int n = get_n(); + if ( n != x.size() ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::unscale(x): x.size() != signature.size()" ); + NOMAD::Double sci; + for ( int i = 0 ; i < n ; ++i ) + { + sci = _scaling[i]; + if ( sci.is_defined() ) + x[i] /= sci; + } } /*-----------------------------------------------------------------------*/ @@ -708,36 +749,39 @@ void NOMAD::Signature::unscale ( NOMAD::Point & x ) /*-----------------------------------------------------------------------*/ bool NOMAD::Signature::snap_to_bounds ( NOMAD::Point & x , NOMAD::Direction * direction ) { - int n = get_n(); - if ( n != x.size() ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::snap_to_bounds(x): x.size() != signature.size()" ); - - bool modified = false; - bool no_periodic_var = _periodic_variables.empty(); - - for ( int i = 0 ; i < n ; ++i ) + int n = get_n(); + if ( n != x.size() ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::snap_to_bounds(x): x.size() != signature.size()" ); - if ( no_periodic_var || !_periodic_variables[i] ) { - - const NOMAD::Double & ubi = _ub[i]; - NOMAD::Double & xi = x[i]; - if ( ubi.is_defined() && xi > ubi ) { - if (direction) - (*direction)[i] += ubi - xi; - xi = ubi; - modified = true; - } - const NOMAD::Double & lbi = _lb[i]; - if ( lbi.is_defined() && xi < lbi ) { - if (direction) - (*direction)[i] += (lbi - xi); - xi = lbi; - modified = true; - } - } - - return modified; + bool modified = false; + bool no_periodic_var = _periodic_variables.empty(); + + for ( int i = 0 ; i < n ; ++i ) + + if ( no_periodic_var || !_periodic_variables[i] ) + { + + const NOMAD::Double & ubi = _ub[i]; + NOMAD::Double & xi = x[i]; + if ( ubi.is_defined() && xi > ubi ) + { + if (direction) + (*direction)[i] += ubi - xi; + xi = ubi; + modified = true; + } + const NOMAD::Double & lbi = _lb[i]; + if ( lbi.is_defined() && xi < lbi ) + { + if (direction) + (*direction)[i] += (lbi - xi); + xi = lbi; + modified = true; + } + } + + return modified; } /*--------------------------------------------------*/ @@ -745,62 +789,69 @@ bool NOMAD::Signature::snap_to_bounds ( NOMAD::Point & x , NOMAD::Direction * di /* returns true if x has been modified */ /*--------------------------------------------------*/ bool NOMAD::Signature::treat_periodic_variables ( NOMAD::Point & x , - const NOMAD::Direction * old_dir , - NOMAD::Direction *& new_dir ) + const NOMAD::Direction * old_dir , + NOMAD::Direction *& new_dir ) { - if ( _periodic_variables.empty() ) - return false; - - int n = get_n(); - if ( n != x.size() ) - throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , - "NOMAD::Signature::treat_periodic_variables(x): x.size() != signature.size()" ); - - new_dir = ( old_dir ) ? new NOMAD::Direction (*old_dir) : NULL; - - bool modified = false; - - for ( int i = 0 ; i < n ; ++i ) { - - NOMAD::bb_input_type bbit = _input_types[i]; + if ( _periodic_variables.empty() ) + return false; - if ( _periodic_variables[i] && !_fixed_variables[i].is_defined() && - ( bbit == NOMAD::CONTINUOUS || bbit == NOMAD::INTEGER ) ) { - - const NOMAD::Double & ubi = _ub[i]; - const NOMAD::Double & lbi = _lb[i]; - NOMAD::Double & xi = x[i]; - - bool chk = false; - - NOMAD::Double new_x = xi; - while ( new_x > ubi ) { - new_x += lbi - ubi; - chk = true; - } - - if ( !chk ) { - while ( new_x < lbi ) { - new_x += ubi - lbi; - chk = true; - } - } - - if ( chk ) { - - if ( bbit == NOMAD::INTEGER ) - new_x.round(); - - if (new_dir) - (*new_dir)[i] += new_x - xi; - - x[i] = new_x; - modified = true; - } + int n = get_n(); + if ( n != x.size() ) + throw NOMAD::Signature::Signature_Error ( "Signature.cpp" , __LINE__ , *this , + "NOMAD::Signature::treat_periodic_variables(x): x.size() != signature.size()" ); + + new_dir = ( old_dir ) ? new NOMAD::Direction (*old_dir) : NULL; + + bool modified = false; + + for ( int i = 0 ; i < n ; ++i ) + { + + NOMAD::bb_input_type bbit = _input_types[i]; + + + if ( _periodic_variables[i] && !_fixed_variables[i].is_defined() && + ( bbit == NOMAD::CONTINUOUS || bbit == NOMAD::INTEGER ) ) + { + + const NOMAD::Double & ubi = _ub[i]; + const NOMAD::Double & lbi = _lb[i]; + NOMAD::Double & xi = x[i]; + + bool chk = false; + + NOMAD::Double new_x = xi; + while ( new_x > ubi ) + { + new_x += lbi - ubi; + chk = true; + } + + if ( !chk ) + { + while ( new_x < lbi ) + { + new_x += ubi - lbi; + chk = true; + } + } + + if ( chk ) + { + + if ( bbit == NOMAD::INTEGER ) + new_x.round(); + + if (new_dir) + (*new_dir)[i] += new_x - xi; + + x[i] = new_x; + modified = true; + } + } } - } - - return modified; + + return modified; } /*--------------------------------------------------*/ @@ -808,84 +859,90 @@ bool NOMAD::Signature::treat_periodic_variables ( NOMAD::Point & x /*--------------------------------------------------*/ void NOMAD::Signature::display ( const NOMAD::Display & out ) const { - if ( _std ) - out << "(standard signature)" << std::endl; - - // dimension: - out << "n : " << get_n() << std::endl; - - // bounds: - out << "lb : "; - if ( _lb.is_defined() ) - out << "( " << _lb << ")"; - else - out << "none"; - out << std::endl; - out << "ub : "; - if ( _ub.is_defined() ) - out << "( " << _ub << ")"; - else - out << "none"; - out << std::endl; - - // scaling: - out << "scaling : "; - if ( _scaling.is_defined() ) - out << "( " << _scaling << ")"; - else - out << "none"; - out << std::endl; - - // fixed variables: - out << "fixed variables : "; - if ( _fixed_variables.is_defined() ) - out << "( " << _fixed_variables << ")"; - else - out << "none"; - out << std::endl; - - // input types: - out << "input types : (" << _input_types << " )" << std::endl; - - // periodic variables: - out << "periodic variables: "; - if ( _periodic_variables.empty() ) - out << "none" << std::endl; - else { - size_t pvs = _periodic_variables.size(); - out << "{"; - for ( size_t k = 0 ; k < pvs ; ++k ) - out << _periodic_variables[k] << " "; - out << "}" << std::endl; - } - - // success directions: - out << "feas. succ. dir. : "; - if ( _feas_success_dir.is_defined() ) - out << _feas_success_dir << std::endl; - else - out << "none"; - out << std::endl - << "infeas. succ. dir.: "; - if ( _infeas_success_dir.is_defined() ) - out << _infeas_success_dir; - else - out << "none"; - out << std::endl; - - // variable groups: - out << NOMAD::open_block ( "variable groups" ); - int i = 0; - std::list<NOMAD::Variable_Group *>::const_iterator end = _var_groups.end() , it; - for ( it = _var_groups.begin() ; it != end ; ++it ) { - out << NOMAD::open_block ( "group #" + NOMAD::itos(i++) ) - << **it << NOMAD::close_block(); - } - out.close_block(); - - // mesh: - out << NOMAD::open_block ( "mesh" ) << *_mesh - << NOMAD::close_block(); + if ( _std ) + out << "(standard signature)" << std::endl; + + // dimension: + out << "n : " << get_n() << std::endl; + + // bounds: + out << "lb : "; + if ( _lb.is_defined() ) + out << "( " << _lb << ")"; + else + out << "none"; + out << std::endl; + out << "ub : "; + if ( _ub.is_defined() ) + out << "( " << _ub << ")"; + else + out << "none"; + out << std::endl; + + // scaling: + out << "scaling : "; + if ( _scaling.is_defined() ) + out << "( " << _scaling << ")"; + else + out << "none"; + out << std::endl; + + // fixed variables: + out << "fixed variables : "; + if ( _fixed_variables.is_defined() ) + out << "( " << _fixed_variables << ")"; + else + out << "none"; + out << std::endl; + + // input types: + out << "input types : (" << _input_types << " )" << std::endl; + + // periodic variables: + out << "periodic variables: "; + if ( _periodic_variables.empty() ) + out << "none" << std::endl; + else + { + size_t pvs = _periodic_variables.size(); + out << "{"; + for ( size_t k = 0 ; k < pvs ; ++k ) + out << _periodic_variables[k] << " "; + out << "}" << std::endl; + } + + // success directions: + out << "feas. succ. dir. : "; + if ( _feas_success_dir.is_defined() ) + out << _feas_success_dir << std::endl; + else + out << "none"; + out << std::endl + << "infeas. succ. dir.: "; + if ( _infeas_success_dir.is_defined() ) + out << _infeas_success_dir; + else + out << "none"; + out << std::endl; + + // variable groups: + out << NOMAD::open_block ( "variable groups" ); + int i = 0; + std::list<NOMAD::Variable_Group *>::const_iterator end = _var_groups.end() , it; + for ( it = _var_groups.begin() ; it != end ; ++it ) + { + out << NOMAD::open_block ( "group #" + NOMAD::itos(i++) ) + << **it << NOMAD::close_block(); + } + out.close_block(); + + // mesh: + out << NOMAD::open_block ( "mesh" ) ; + out << "initial poll size: ( " << _mesh->get_initial_poll_size() << " )" << std::endl; + out << "initial mesh size: ( " << _mesh->get_initial_mesh_size() << " )" << std::endl; + out << "minimum mesh size: ( " << _mesh->get_min_mesh_size() << " )" << std::endl; + out << "minimum poll size: ( " << _mesh->get_min_poll_size() << " )" << std::endl; + out << NOMAD::close_block(); } /*-------------------------------------------*/ @@ -895,138 +952,141 @@ void NOMAD::Signature::display ( const NOMAD::Display & out ) const /*-------------------------------------------*/ bool NOMAD::Signature::operator < ( const NOMAD::Signature & s ) const { - if ( this == &s ) - return false; - - // standard signature: not checked: standard and non-standard signatures can be == - // ( this is tested in Parameters::check() ) - - // dimension: - // ---------- - int n = _lb.size(); - int sn = s._lb.size(); - - if ( n < sn ) - return true; - if ( sn < n ) - return false; - - // variable groups: - // ---------------- - int nvg1 = _var_groups.size(); - int nvg2 = s._var_groups.size(); - if ( nvg1 != nvg2 ) - return (nvg1 < nvg2); - - std::list<NOMAD::Variable_Group*>::const_iterator + if ( this == &s ) + return false; + + // standard signature: not checked: standard and non-standard signatures can be == + // ( this is tested in Parameters::check() ) + + // dimension: + // ---------- + int n = static_cast<int>(_lb.size()); + int sn = static_cast<int>(s._lb.size()); + + if ( n < sn ) + return true; + if ( sn < n ) + return false; + + // variable groups: + // ---------------- + size_t nvg1 = _var_groups.size(); + size_t nvg2 = s._var_groups.size(); + if ( nvg1 != nvg2 ) + return (nvg1 < nvg2); + + std::list<NOMAD::Variable_Group*>::const_iterator it1 = _var_groups.begin() , it2 = s._var_groups.begin() , end = _var_groups.end(); - - while ( it1 != end ) { - if ( **it1 < **it2 ) - return true; - if ( **it2 < **it1 ) - return false; - ++it1; - ++it2; - } - - // first check on the periodic variables: - // -------------------------------------- - bool p1_empty = _periodic_variables.empty(); - bool p2_empty = s._periodic_variables.empty(); - if ( p1_empty != p2_empty ) - return p1_empty; - - // first check on the mesh: - // ------------------------ - const NOMAD::Point & delta_m_0 = _mesh->get_initial_mesh_size(); - const NOMAD::Point & delta_m_min = _mesh->get_min_mesh_size(); - const NOMAD::Point & delta_p_min = _mesh->get_min_poll_size(); - bool chkm = delta_m_min.is_defined(); - bool chkp = delta_p_min.is_defined(); - - const NOMAD::Point & s_delta_m_0 = s._mesh->get_initial_mesh_size(); - const NOMAD::Point & s_delta_m_min = s._mesh->get_min_mesh_size(); - const NOMAD::Point & s_delta_p_min = s._mesh->get_min_poll_size(); - bool s_chkm = s_delta_m_min.is_defined(); - bool s_chkp = s_delta_p_min.is_defined(); - - if ( _mesh != s._mesh ) { - if ( chkm != s_chkm ) - return !chkm; - if ( chkp != s_chkp ) - return !chkp; - } - - /*---------------------------*/ - /* loop on all coordinates */ - /*---------------------------*/ - for ( int i = 0 ; i < n ; ++i ) { - // input types: - // ------------ - if ( _input_types[i] < s._input_types[i] ) - return true; - if ( s._input_types[i] < _input_types[i] ) - return false; + while ( it1 != end ) + { + if ( **it1 < **it2 ) + return true; + if ( **it2 < **it1 ) + return false; + ++it1; + ++it2; + } - // bounds: - // ------- - if ( _lb[i].comp_with_undef ( s._lb[i] ) ) - return true; - if ( s._lb[i].comp_with_undef ( _lb[i] ) ) - return false; - if ( _ub[i].comp_with_undef ( s._ub[i] ) ) - return true; - if ( s._ub[i].comp_with_undef ( _ub[i] ) ) - return false; - - // scaling: - // -------- - if ( _scaling[i].comp_with_undef ( s._scaling[i] ) ) - return true; - if ( s._scaling[i].comp_with_undef ( _scaling[i] ) ) - return false; - - // fixed variables: - // ---------------- - if ( _fixed_variables[i].comp_with_undef ( s._fixed_variables[i] ) ) - return true; - if ( s._fixed_variables[i].comp_with_undef ( _fixed_variables[i] ) ) - return false; - - // periodic variables: - // ------------------- - if ( !p1_empty && _periodic_variables[i] != s._periodic_variables[i] ) - return _periodic_variables[i]; - - // mesh: - // ----- - if ( _mesh != s._mesh ) - { - if ( delta_m_0[i].comp_with_undef ( s_delta_m_0[i] ) ) - return true; - if ( s_delta_m_0[i].comp_with_undef ( delta_m_0[i] ) ) - return false; - if ( chkm ) - { - if ( delta_m_min[i].comp_with_undef ( s_delta_m_min[i] ) ) - return true; - if ( s_delta_m_min[i].comp_with_undef ( delta_m_min[i] ) ) - return false; - } - if ( chkp ) - { - if ( delta_p_min[i].comp_with_undef ( s_delta_p_min[i] ) ) - return true; - if ( s_delta_p_min[i].comp_with_undef ( delta_p_min[i] ) ) - return false; - } + // first check on the periodic variables: + // -------------------------------------- + bool p1_empty = _periodic_variables.empty(); + bool p2_empty = s._periodic_variables.empty(); + if ( p1_empty != p2_empty ) + return p1_empty; + + // first check on the mesh: + // ------------------------ + bool chkm = _mesh->get_min_mesh_size().is_defined(); + bool chkp = _mesh->get_min_poll_size().is_defined(); + + bool s_chkm = s._mesh->get_min_mesh_size().is_defined(); + bool s_chkp = s._mesh->get_min_poll_size().is_defined(); + + if ( _mesh->get_initial_mesh_size() != s._mesh->get_initial_mesh_size() && + _mesh->get_min_mesh_size() != s._mesh->get_min_mesh_size() && + _mesh->get_min_poll_size() != s._mesh->get_min_poll_size() ) + { + if ( chkm != s_chkm ) + return !chkm; + if ( chkp != s_chkp ) + return !chkp; } - } - - // both signatures are equal: - return false; + + /*---------------------------*/ + /* loop on all coordinates */ + /*---------------------------*/ + for ( int i = 0 ; i < n ; ++i ) + { + + // input types: + // ------------ + if ( _input_types[i] < s._input_types[i] ) + return true; + if ( s._input_types[i] < _input_types[i] ) + return false; + + // bounds: + // ------- + if ( _lb[i].comp_with_undef ( s._lb[i] ) ) + return true; + if ( s._lb[i].comp_with_undef ( _lb[i] ) ) + return false; + if ( _ub[i].comp_with_undef ( s._ub[i] ) ) + return true; + if ( s._ub[i].comp_with_undef ( _ub[i] ) ) + return false; + + // scaling: + // -------- + if ( _scaling[i].comp_with_undef ( s._scaling[i] ) ) + return true; + if ( s._scaling[i].comp_with_undef ( _scaling[i] ) ) + return false; + + // fixed variables: + // ---------------- + if ( _fixed_variables[i].comp_with_undef ( s._fixed_variables[i] ) ) + return true; + if ( s._fixed_variables[i].comp_with_undef ( _fixed_variables[i] ) ) + return false; + + // periodic variables: + // ------------------- + if ( !p1_empty && _periodic_variables[i] != s._periodic_variables[i] ) + return _periodic_variables[i]; + + // mesh: + // ----- + if ( _mesh->get_initial_mesh_size() != s._mesh->get_initial_mesh_size() && + _mesh->get_min_mesh_size() != s._mesh->get_min_mesh_size() && + _mesh->get_min_poll_size() != s._mesh->get_min_poll_size() ) + { + if ( _mesh->get_initial_mesh_size()[i].comp_with_undef ( s._mesh->get_initial_mesh_size()[i] ) ) + return true; + if ( s._mesh->get_initial_mesh_size()[i].comp_with_undef ( _mesh->get_initial_mesh_size()[i] ) ) + return false; + + + if ( chkm ) + { + if ( _mesh->get_min_mesh_size()[i].comp_with_undef ( s._mesh->get_min_mesh_size()[i] ) ) + return true; + if ( s._mesh->get_min_mesh_size()[i].comp_with_undef ( _mesh->get_min_mesh_size()[i] ) ) + return false; + } + if ( chkp ) + { + if ( _mesh->get_min_poll_size()[i].comp_with_undef ( s._mesh->get_min_poll_size()[i] ) ) + return true; + if ( s._mesh->get_min_poll_size()[i].comp_with_undef ( _mesh->get_min_poll_size()[i] ) ) + return false; + } + } + } + + // both signatures are equal: + return false; } diff --git a/src/Signature.hpp b/src/Signature.hpp index 3eb9f95..44dcd32 100644 --- a/src/Signature.hpp +++ b/src/Signature.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,489 +34,519 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Signature.hpp - \brief Evaluation point signature (headers) - \author Sebastien Le Digabel - \date 2010-04-22 - \see Signature.cpp -*/ + \file Signature.hpp + \brief Evaluation point signature (headers) + \author Sebastien Le Digabel + \date 2010-04-22 + \see Signature.cpp + */ #ifndef __SIGNATURE__ #define __SIGNATURE__ #include "Variable_Group.hpp" namespace NOMAD { - - /// Evaluation point signature. - class Signature { - - private: + /// Evaluation point signature. + class Signature { + + private: + #ifdef MEMORY_DEBUG - static int _cardinality; ///< Number of NOMAD::Signature objects in memory. - static int _max_cardinality; ///< Max number of NOMAD::Signature objects in memory. + static int _cardinality; ///< Number of NOMAD::Signature objects in memory. + static int _max_cardinality; ///< Max number of NOMAD::Signature objects in memory. #endif - - NOMAD::Point _lb; ///< Lower bounds. - NOMAD::Point _ub; ///< Upper bounds. - NOMAD::Point _scaling; ///< Scaling. - NOMAD::Point _fixed_variables; ///< Fixed variables. - - std::vector<NOMAD::bb_input_type> _input_types; ///< Input types. - - bool _all_continuous; ///< Flag equal to \c true if all variables are continuous. - bool _has_categorical; ///< Flag equal to \c true if there are categorical variables. - - static bool _warning_has_been_displayed; ///< Flag equal to \c true if the warning has already been displayed - - std::vector<bool> _periodic_variables; ///< Periodic variables. - - /// Groups of variables. - /** - Include the directions/ - */ - std::list<NOMAD::Variable_Group*> _var_groups; - - /// Mesh associated to this signature. - NOMAD::Mesh * _mesh; - - /** - Flag equal to \c true if the signature is standard - (i.e created in Parameters class). - */ - bool _std; - - // Feasible successful direction. - /** - Mutable since it is not used in - \c operator \c < and have to be often changed. - */ - mutable NOMAD::Direction _feas_success_dir; - - // Infeasible successful direction. - /** - Mutable since it is not used in - \c operator \c < and have to be often changed. - */ - mutable NOMAD::Direction _infeas_success_dir; - - // Direction group index - int _dir_group_index; - - // Display - NOMAD::Display _out; - - /*---------------------------------------------------------------------------*/ - - /// Initializations. - /** - \param n Number of variables -- \b IN. - \param input_types Types of the variables -- \b IN. - \param initial_mesh_size Initial mesh size -- \b IN. - \param min_mesh_size Minimum mesh size -- \b IN. - \param min_poll_size Minimum poll size -- \b IN. - \param lb Lower bounds -- \b IN. - \param ub Upper bounds -- \b IN. - \param scaling Scaling -- \b IN. - \param fixed_variables Fixed variables -- \b IN. - \param periodic_variables Periodic variables -- \b IN. - \param var_groups Groups of variables -- \b IN. - */ - void init - ( int n , - const std::vector<NOMAD::bb_input_type> & input_types , - const NOMAD::Point & initial_mesh_size , - const NOMAD::Point & min_mesh_size , - const NOMAD::Point & min_poll_size , - const NOMAD::Point & lb , - const NOMAD::Point & ub , - const NOMAD::Point & scaling , - const NOMAD::Point & fixed_variables , - const std::vector<bool> & periodic_variables , - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups ); - - /// Reset groups of variables. - void reset_var_groups ( void ); - - /// Clear. - /** - Private method called by the destructor and after an exception is thrown. - */ - void clear ( void ); - - /// Affectation operator. - /** - \param s The right-hand side object. - */ - const Signature & operator = ( const Signature & s ); - - public: - - /*---------------------------------------------------------------------------*/ - - /// Exception class for an invalid signature. - class Signature_Error : public NOMAD::Exception { + + NOMAD::Point _lb; ///< Lower bounds. + NOMAD::Point _ub; ///< Upper bounds. + NOMAD::Point _scaling; ///< Scaling. + NOMAD::Point _fixed_variables; ///< Fixed variables. + + std::vector<NOMAD::bb_input_type> _input_types; ///< Input types. + + bool _all_continuous; ///< Flag equal to \c true if all variables are continuous. + bool _has_categorical; ///< Flag equal to \c true if there are categorical variables. + + static bool _warning_has_been_displayed; ///< Flag equal to \c true if the warning has already been displayed + + std::vector<bool> _periodic_variables; ///< Periodic variables. + + /// Groups of variables. + /** + Include the directions/ + */ + std::list<NOMAD::Variable_Group*> _var_groups; + + /// Mesh associated to this signature. + NOMAD::OrthogonalMesh *_mesh; ///< Orthogonal mesh + + /** + Flag equal to \c true if the signature is standard + (i.e created in Parameters class). + */ + bool _std; + + // Feasible successful direction. + /** + Mutable since it is not used in + \c operator \c < and have to be often changed. + */ + mutable NOMAD::Direction _feas_success_dir; + + // Infeasible successful direction. + /** + Mutable since it is not used in + \c operator \c < and have to be often changed. + */ + mutable NOMAD::Direction _infeas_success_dir; + + + // Direction group index + int _dir_group_index; + + // Display + NOMAD::Display _out; + + /*---------------------------------------------------------------------------*/ + + /// Initializations. + /** + \param n Number of variables -- \b IN. + \param input_types Types of the variables -- \b IN. + \param lb Lower bounds -- \b IN. + \param ub Upper bounds -- \b IN. + \param scaling Scaling -- \b IN. + \param fixed_variables Fixed variables -- \b IN. + \param periodic_variables Periodic variables -- \b IN. + \param var_groups Groups of variables -- \b IN. + */ + void init + ( int n , + const std::vector<NOMAD::bb_input_type> & input_types , + const NOMAD::Point & lb , + const NOMAD::Point & ub , + const NOMAD::Point & scaling , + const NOMAD::Point & fixed_variables , + const std::vector<bool> & periodic_variables , + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups ); + + /// Reset groups of variables. + void reset_var_groups ( void ); + + /// Clear. + /** + Private method called by the destructor and after an exception is thrown. + */ + void clear ( void ); + + /// Affectation operator. + /** + \param s The right-hand side object. + */ + const Signature & operator = ( const Signature & s ); + public: - /// Constructor. - Signature_Error ( const std::string & file , - int line , - Signature & s , - const std::string & msg ) - : NOMAD::Exception ( file , line , msg ) { s.clear(); } - }; - - /*---------------------------------------------------------------------------*/ - - /// Constructor #1. - /** - Advanced version. - \param n Number of variables -- \b IN. - \param input_types Types of the variables -- \b IN. - \param initial_mesh_size Initial mesh size -- \b IN. - \param min_mesh_size Minimum mesh size -- \b IN. - \param min_poll_size Minimum poll size -- \b IN. - \param lb Lower bounds -- \b IN. - \param ub Upper bounds -- \b IN. - \param scaling Scaling -- \b IN. - \param fixed_variables Fixed variables -- \b IN. - \param periodic_variables Periodic variables -- \b IN. - \param var_groups Groups of variables -- \b IN. - \param out Display -- \b IN. - */ - Signature - ( int n , - const std::vector<NOMAD::bb_input_type> & input_types , - const NOMAD::Point & initial_mesh_size , - const NOMAD::Point & min_mesh_size , - const NOMAD::Point & min_poll_size , - const NOMAD::Point & lb , - const NOMAD::Point & ub , - const NOMAD::Point & scaling , - const NOMAD::Point & fixed_variables , - const std::vector<bool> & periodic_variables , - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups , - const NOMAD::Display & out=NOMAD::Display() - ); - - /// Constructor #2. - /** - Basic version that will automatically construct groups of variables. - \param n Number of variables -- \b IN. - \param input_types Types of the variables -- \b IN. - \param initial_mesh_size Initial mesh size -- \b IN. - \param lb Lower bounds -- \b IN. - \param ub Upper bounds -- \b IN. - \param direction_types Types of directions -- \b IN. - \param sec_poll_dir_types Types of directions for secondary poll -- \b IN. - \param halton_seed Halton seed -- \b IN. - \param out Display -- \b IN. - */ - Signature ( int n , - const std::vector<NOMAD::bb_input_type> & input_types , - const NOMAD::Point & initial_mesh_size , - const NOMAD::Point & lb , - const NOMAD::Point & ub , - const std::set<NOMAD::direction_type> & direction_types , - const std::set<NOMAD::direction_type> & sec_poll_dir_types , - int halton_seed , - const NOMAD::Display & out = NOMAD::Display() - ); - - /// Copy constructor. - /** - \param s The copied object. - */ - Signature ( const Signature & s ); - - /// Destructor. - virtual ~Signature ( void ); - - /// Reset. - /** - \param n Number of variables -- \b IN. - \param input_types Types of the variables -- \b IN. - \param initial_mesh_size Initial mesh size -- \b IN. - \param min_mesh_size Minimum mesh size -- \b IN. - \param min_poll_size Minimum poll size -- \b IN. - \param lb Lower bounds -- \b IN. - \param ub Upper bounds -- \b IN. - \param scaling Scaling -- \b IN. - \param fixed_variables Fixed variables -- \b IN. - \param periodic_variables Periodic variables -- \b IN. - \param var_groups Groups of variables -- \b IN. - */ - void reset - ( int n , - const std::vector<NOMAD::bb_input_type> & input_types , - const NOMAD::Point & initial_mesh_size , - const NOMAD::Point & min_mesh_size , - const NOMAD::Point & min_poll_size , - const NOMAD::Point & lb , - const NOMAD::Point & ub , - const NOMAD::Point & scaling , - const NOMAD::Point & fixed_variables , - const std::vector<bool> & periodic_variables , - std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups ); - - /// Define a signature to be standard. - void set_std ( void ) { _std = true; } - - /// Set a feasible successful direction. - /** - \param dir The direction -- \b IN. - */ - void set_feas_success_dir ( const NOMAD::Direction & dir ); - - /// Set an infeasible successful direction. - /** - \param dir The direction -- \b IN. - */ - void set_infeas_success_dir ( const NOMAD::Direction & dir ); - - /// Reset the feasible successful direction. - void reset_feas_success_dir ( void ) const { _feas_success_dir.clear(); } - - /// Reset the infeasible successful direction. - void reset_infeas_success_dir ( void ) const { _infeas_success_dir.clear(); } - - /// Scaling. - /** - Performed before an evaluation. - \param x The scaled point -- \b IN/OUT. - */ - void scale ( NOMAD::Point & x ); - - /// Unscaling. - /** - Performed after an evaluation. - \param x The unscaled point -- \b IN/OUT. - */ - void unscale ( NOMAD::Point & x ); - - /// Snap to bounds. - /** - - Supposes that \c this->treat_periodic_variables() has already been invoked. - - If periodic variables have been treated, then bounds are + + /*---------------------------------------------------------------------------*/ + + /// Exception class for an invalid signature. + class Signature_Error : public NOMAD::Exception { + public: + /// Constructor. + Signature_Error ( const std::string & file , + int line , + Signature & s , + const std::string & msg ) + : NOMAD::Exception ( file , line , msg ) { s.clear(); } + }; + + /*---------------------------------------------------------------------------*/ + + /// Constructor #1. + /** + Advanced version. + \param n Number of variables -- \b IN. + \param input_types Types of the variables -- \b IN. + \param use_smesh Type of mesh (SMesh, XMesh) -- \b IN. + \param anisotropic_mesh Anisotropy of mesh (XMesh) -- \b IN. + \param initial_poll_size Initial poll size -- \b IN. + \param min_poll_size Minimum poll size -- \b IN. + \param min_mesh_size Minimim mesh size -- \b IN. + \param mesh_update_basis Mesh update basis -- \b IN. + \param poll_update_basis Poll update basis -- \b IN. + \param mesh_coarsening_exponent Mesh coarsening exponent -- \b IN. + \param mesh_refining_exponent Mesh refining exponent -- \b IN. + \param initial_mesh_index Initial mesh index -- \b IN. + \param lb Lower bounds -- \b IN. + \param ub Upper bounds -- \b IN. + \param scaling Scaling -- \b IN. + \param fixed_variables Fixed variables -- \b IN. + \param periodic_variables Periodic variables -- \b IN. + \param var_groups Groups of variables -- \b IN. + \param out Display -- \b IN. + */ + Signature + ( int n , + const std::vector<NOMAD::bb_input_type> & input_types , + const NOMAD::Point & lb , + const NOMAD::Point & ub , + bool use_smesh , + bool anisotropic_mesh , + const NOMAD::Point & initial_poll_size , + const NOMAD::Point & min_poll_size , + const NOMAD::Point & min_mesh_size , + NOMAD::Double & mesh_update_basis , + NOMAD::Double & poll_update_basis , + int & mesh_coarsening_exponent, + int & mesh_refining_exponent, + int initial_mesh_index , + const NOMAD::Point & scaling , + const NOMAD::Point & fixed_variables , + const std::vector<bool> & periodic_variables, + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups , + const NOMAD::Display & out=NOMAD::Display() + ); + + /// Constructor #2. + /** + Basic version that will automatically construct groups of variables. + \param n Number of variables -- \b IN. + \param input_types Types of the variables -- \b IN. + \param initial_poll_size Initial poll size -- \b IN. + \param lb Lower bounds -- \b IN. + \param ub Upper bounds -- \b IN. + \param direction_types Types of directions -- \b IN. + \param sec_poll_dir_types Types of directions for secondary poll -- \b IN. + \param out Display -- \b IN. + */ + Signature ( int n , + const std::vector<NOMAD::bb_input_type> & input_types , + const NOMAD::Point & initial_poll_size , + const NOMAD::Point & lb , + const NOMAD::Point & ub , + const std::set<NOMAD::direction_type> & direction_types , + const std::set<NOMAD::direction_type> & sec_poll_dir_types , + const NOMAD::Display & out = NOMAD::Display() + ); + + /// Copy constructor. + /** + \param s The copied object. + */ + Signature ( const Signature & s ); + + /// Destructor. + virtual ~Signature ( void ); + + /// Reset. + /** + \param n Number of variables -- \b IN. + \param input_types Types of the variables -- \b IN. + \param lb Lower bounds -- \b IN. + \param ub Upper bounds -- \b IN. + \param scaling Scaling -- \b IN. + \param fixed_variables Fixed variables -- \b IN. + \param periodic_variables Periodic variables -- \b IN. + \param var_groups Groups of variables -- \b IN. + */ + void reset + ( int n , + const std::vector<NOMAD::bb_input_type> & input_types , + const NOMAD::Point & lb , + const NOMAD::Point & ub , + const NOMAD::Point & scaling , + const NOMAD::Point & fixed_variables , + const std::vector<bool> & periodic_variables , + std::set<NOMAD::Variable_Group*,NOMAD::VG_Comp> & var_groups ); + + /// Define a signature to be standard. + void set_std ( void ) { _std = true; } + + /// Set a feasible successful direction. + /** + \param dir The direction -- \b IN. + */ + void set_feas_success_dir ( const NOMAD::Direction & dir ); + + /// Set an infeasible successful direction. + /** + \param dir The direction -- \b IN. + */ + void set_infeas_success_dir ( const NOMAD::Direction & dir ); + + /// Reset the feasible successful direction. + void reset_feas_success_dir ( void ) const { _feas_success_dir.clear(); } + + /// Reset the infeasible successful direction. + void reset_infeas_success_dir ( void ) const { _infeas_success_dir.clear(); } + + /// Scaling. + /** + Performed before an evaluation. + \param x The scaled point -- \b IN/OUT. + */ + void scale ( NOMAD::Point & x ); + + /// Unscaling. + /** + Performed after an evaluation. + \param x The unscaled point -- \b IN/OUT. + */ + void unscale ( NOMAD::Point & x ); + + /// Snap to bounds. + /** + - Supposes that \c this->treat_periodic_variables() has already been invoked. + - If periodic variables have been treated, then bounds are satisfied and there is no need to snap anymore. - \param x The point to snap -- \b IN/OUT. - \param direction A pointer to the direction associated to this point - (may be \c NULL) -- \b IN/OUT. - \return A Boolean equal to \c true if \c x has been modified. - */ - bool snap_to_bounds ( NOMAD::Point & x , NOMAD::Direction * direction ); - - /// Treat the periodic variables. - /** - \param x The point to treat -- \b IN/OUT. - \param old_dir A pointer to the direction associated to this point - (before the treatment; may be \c NULL) -- \b IN. - \param new_dir A pointer to the direction associated to this point - (after the treatment; may be \c NULL) -- \b OUT. - \return A boolean equal to \c true if \c x has been modified. - */ - bool treat_periodic_variables ( NOMAD::Point & x , - const NOMAD::Direction * old_dir , - NOMAD::Direction *& new_dir ); - - /// Access to the lower bounds. - /** - \return The lower bounds. - */ - const NOMAD::Point & get_lb ( void ) const { return _lb; } - - /// Access to the upper bounds. - /** - \return The upper bounds. - */ - const NOMAD::Point & get_ub ( void ) const { return _ub; } - - /// Access to the scaling. - /** - \return The scaling. - */ - const NOMAD::Point & get_scaling ( void ) const { return _scaling; } - - /// Access to the fixed variables. - /** - \return The fixed variables. - */ - const NOMAD::Point & get_fixed_variables ( void ) const { return _fixed_variables; } - - /// Access to the feasible successful direction. - /** - \return The feasible successful direction - (may be undefined). - */ - const NOMAD::Direction & get_feas_success_dir ( void ) const - { - return _feas_success_dir; - } - - /// Access to the infeasible successful direction. - /** - \return The infeasible successful direction - (may be undefined). - */ - const NOMAD::Direction & get_infeas_success_dir ( void ) const - { - return _infeas_success_dir; - } - - /// Access to the periodic variables. - /** - \return The periodic variables. - */ - const std::vector<bool> & get_periodic_variables ( void ) const - { - return _periodic_variables; - } - - /// Check if all variables are continuous. - /** - \return A boolean equal to \c true if all variables are continuous. - */ - bool all_continuous ( void ) const { return _all_continuous; } - - /// Check if there are categorical variables. - /** - \return A boolean equal to \c true if there are categorical variables. - */ - bool has_categorical ( void ) const { return _has_categorical; } - - /// Access to the number of categorical variables. - /** - \return Integer equal to the number of categorical variables. - */ - int get_n_categorical ( void ) const ; - - /// Access to the number of variables. - /** - \return The number of variables. - */ - int get_n ( void ) const { return static_cast<int> ( _input_types.size() ); } - - /// Access to the input types. - /** - \return The input types. - */ - const std::vector<NOMAD::bb_input_type> & get_input_types ( void ) const - { - return _input_types; - } - - /// Access to the input types. - /** - \return The input types. - */ - const std::vector<NOMAD::bb_input_type> & get_input_type ( void ) const - { - return _input_types; - } - - /// Access to the groups of variables. - /** - \return The groups of variables. - */ - const std::list<NOMAD::Variable_Group*> & get_var_groups ( void ) const - { - return _var_groups; - } - - /// Access to the mesh. - /** - \return A pointer to the mesh. - */ - const NOMAD::Mesh & get_mesh ( void ) const { return *_mesh; } - - /// Check the compatibility of a point. - /** - - Only the number of variables is checked. - - Other criteria (fixed variables, binary variables,...) + \param x The point to snap -- \b IN/OUT. + \param direction A pointer to the direction associated to this point + (may be \c NULL) -- \b IN/OUT. + \return A Boolean equal to \c true if \c x has been modified. + */ + bool snap_to_bounds ( NOMAD::Point & x , NOMAD::Direction * direction ); + + /// Treat the periodic variables. + /** + \param x The point to treat -- \b IN/OUT. + \param old_dir A pointer to the direction associated to this point + (before the treatment; may be \c NULL) -- \b IN. + \param new_dir A pointer to the direction associated to this point + (after the treatment; may be \c NULL) -- \b OUT. + \return A boolean equal to \c true if \c x has been modified. + */ + bool treat_periodic_variables ( NOMAD::Point & x , + const NOMAD::Direction * old_dir , + NOMAD::Direction *& new_dir ); + + /// Access to the lower bounds. + /** + \return The lower bounds. + */ + const NOMAD::Point & get_lb ( void ) const { return _lb; } + + /// Access to the upper bounds. + /** + \return The upper bounds. + */ + const NOMAD::Point & get_ub ( void ) const { return _ub; } + + /// Access to the mesh. + /** + \return The orthogonal mesh. + */ + NOMAD::OrthogonalMesh * get_mesh ( void ) const { return _mesh; } + + + /// Update the Mesh (poll and mesh sizes). + /** + \param success Type of success of the iteration -- \b IN. + \param dir Direction of the iteration (optional) -- \b IN. + */ + void update_mesh ( NOMAD::success_type success, const NOMAD::Direction * dir=NULL ) + { + _mesh->update ( success, dir ); + } + + /// Complete reset of the mesh. + /** + */ + void reset_mesh ( void ) { _mesh->reset(); } + + /// Reset of the mesh indices. + /** + /param mesh_indices + */ + void reset_mesh ( NOMAD::Point & mesh_indices ) { _mesh->set_mesh_indices( mesh_indices); } + + + /// Access to the scaling. + /** + \return The scaling. + */ + const NOMAD::Point & get_scaling ( void ) const { return _scaling; } + + /// Access to the fixed variables. + /** + \return The fixed variables. + */ + const NOMAD::Point & get_fixed_variables ( void ) const { return _fixed_variables; } + + + /// Access to the number of fixed variables. + /** + \return The number of fixed variables. + */ + int get_nb_fixed_variables ( void ) const; + + + + /// Access to the feasible successful direction. + /** + \return The feasible successful direction + (may be undefined). + */ + const NOMAD::Direction & get_feas_success_dir ( void ) const + { + return _feas_success_dir; + } + + /// Access to the infeasible successful direction. + /** + \return The infeasible successful direction + (may be undefined). + */ + const NOMAD::Direction & get_infeas_success_dir ( void ) const + { + return _infeas_success_dir; + } + + /// Access to the periodic variables. + /** + \return The periodic variables. + */ + const std::vector<bool> & get_periodic_variables ( void ) const + { + return _periodic_variables; + } + + /// Check if all variables are continuous. + /** + \return A boolean equal to \c true if all variables are continuous. + */ + bool all_continuous ( void ) const { return _all_continuous; } + + /// Check if there are categorical variables. + /** + \return A boolean equal to \c true if there are categorical variables. + */ + bool has_categorical ( void ) const { return _has_categorical; } + + /// Access to the number of categorical variables. + /** + \return Integer equal to the number of categorical variables. + */ + int get_n_categorical ( void ) const ; + + /// Access to the number of variables. + /** + \return The number of variables. + */ + int get_n ( void ) const { return static_cast<int> ( _input_types.size() ); } + + /// Access to the input types. + /** + \return The input types. + */ + const std::vector<NOMAD::bb_input_type> & get_input_types ( void ) const + { + return _input_types; + } + + /// Access to the input types. + /** + \return The input types. + */ + const std::vector<NOMAD::bb_input_type> & get_input_type ( void ) const + { + return _input_types; + } + + /// Access to the groups of variables. + /** + \return The groups of variables. + */ + const std::list<NOMAD::Variable_Group*> & get_var_groups ( void ) const + { + return _var_groups; + } + + + /// Check the compatibility of a point. + /** + - Only the number of variables is checked. + - Other criteria (fixed variables, binary variables,...) are checked by NOMAD::Eval_Point::check(). - \param x The point to check -- \b IN. - \return A boolean equal to \c true if the point is compatible - with the signature. - */ - bool is_compatible ( const NOMAD::Point & x ) const; - - /// Access to the directions. - /** - - The computed directions already include Delta^k_m. - \param dirs List of directions -- \b OUT. - \param poll Type of poll (primary or secondary) -- \b IN. - \param poll_center Poll center -- \b IN. - \param mesh_index Mesh index ell -- \b IN. - */ - void get_directions ( std::list<NOMAD::Direction> & dirs , - NOMAD::poll_type poll , - const NOMAD::Point & poll_center , - int mesh_index ); - - - /// Access to one direction for a given mesh. - /** - Used for example in the VNS search. - \param dir The direction -- \b OUT. - \param mesh_index Mesh index ell -- \b IN. - \param halton_index Halton index -- \b IN. - */ - void get_one_direction ( NOMAD::Direction & dir , - int mesh_index , - int halton_index ) const; - - - /// Comparison operator \c < . - /** - Successful directions are not considered. - \param s The right-hand side object -- \b IN. - \return A boolean equal to \c true if \c *this \c < \c s. - */ - bool operator < ( const Signature & s ) const; - - /// Comparison operator \c != . - /** - \param s The right-hand side object -- \b IN. - \return A boolean equal to \c true if \c *this \c != \c s. - */ - bool operator != ( const Signature & s ) const - { - return ( (*this < s) || (s < *this) ); - } - + \param x The point to check -- \b IN. + \return A boolean equal to \c true if the point is compatible + with the signature. + */ + bool is_compatible ( const NOMAD::Point & x ) const; + + /// Access to the directions. + /** + - The computed directions already include Delta^k_m. + \param dirs List of directions -- \b OUT. + \param poll Type of poll (primary or secondary) -- \b IN. + \param poll_center Poll center -- \b IN. + */ + void get_directions ( std::list<NOMAD::Direction> & dirs , + NOMAD::poll_type poll , + const NOMAD::Point & poll_center ); + + + /// Access to one direction for a given mesh. + /** + Used for example in the VNS search. + \param dir The direction -- \b OUT. + \param mesh_index Mesh index ell -- \b IN. + */ + void get_one_direction ( NOMAD::Direction & dir , + int mesh_index ) const; + + + /// Comparison operator \c < . + /** + Successful directions are not considered. + \param s The right-hand side object -- \b IN. + \return A boolean equal to \c true if \c *this \c < \c s. + */ + bool operator < ( const Signature & s ) const; + + /// Comparison operator \c != . + /** + \param s The right-hand side object -- \b IN. + \return A boolean equal to \c true if \c *this \c != \c s. + */ + bool operator != ( const Signature & s ) const + { + return ( (*this < s) || (s < *this) ); + } + #ifdef MEMORY_DEBUG - - /// Access to the number of NOMAD::Signature objects in memory. - /** - \return Number of NOMAD::Signature objects in memory. - */ - static int get_cardinality ( void ) { return Signature::_cardinality; } - - /// Access to the max number of NOMAD::Signature objects in memory. - /** - \return Max number of NOMAD::Signature objects in memory. - */ - static int get_max_cardinality ( void ) { return Signature::_max_cardinality; } + + /// Access to the number of NOMAD::Signature objects in memory. + /** + \return Number of NOMAD::Signature objects in memory. + */ + static int get_cardinality ( void ) { return Signature::_cardinality; } + + /// Access to the max number of NOMAD::Signature objects in memory. + /** + \return Max number of NOMAD::Signature objects in memory. + */ + static int get_max_cardinality ( void ) { return Signature::_max_cardinality; } #endif - - /// Display. + + /// Display. + /** + \param out The NOMAD::Display object -- \b IN. + */ + void display ( const NOMAD::Display & out ) const; + + }; + + /// Display a NOMAD::Signature object. /** - \param out The NOMAD::Display object -- \b IN. - */ - void display ( const NOMAD::Display & out ) const; - - }; - - /// Display a NOMAD::Signature object. - /** \param out The NOMAD::Display object -- \b IN. \param s The NOMAD::Signature object to be displayed -- \b IN. \return The NOMAD::Display object. - */ - inline const NOMAD::Display & operator << ( const NOMAD::Display & out , - const NOMAD::Signature & s ) { - s.display ( out ); - return out; - } + */ + inline const NOMAD::Display & operator << ( const NOMAD::Display & out , + const NOMAD::Signature & s ) { + s.display ( out ); + return out; + } } #endif diff --git a/src/Signature_Element.hpp b/src/Signature_Element.hpp index e9f0a5f..fa0357d 100644 --- a/src/Signature_Element.hpp +++ b/src/Signature_Element.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Single_Obj_Quad_Model_Evaluator.hpp b/src/Single_Obj_Quad_Model_Evaluator.hpp index e6c6782..7580717 100644 --- a/src/Single_Obj_Quad_Model_Evaluator.hpp +++ b/src/Single_Obj_Quad_Model_Evaluator.hpp @@ -1,8 +1,8 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version (3.5.1).7.2 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -38,7 +38,7 @@ \file Single_Obj_Quad_Model_Evaluator.hpp \brief NOMAD::Evaluator subclass for quadratic model optimization (headers) \author Christophe Tribes - \date 2012-06-19 + \date 2014-06-19 \see Single_Obj_Quad_Model_Evaluator.cpp */ #ifndef __SINGLE_OBJ_QUAD_MODEL_EVALUATOR__ @@ -60,11 +60,12 @@ namespace NOMAD { \param model Model -- \b IN. */ Single_Obj_Quad_Model_Evaluator ( const NOMAD::Parameters & p , - const NOMAD::Quad_Model & model ) : NOMAD::Quad_Model_Evaluator(p,model),NOMAD::Evaluator(p){;} + const NOMAD::Quad_Model & model ) : NOMAD::Quad_Model_Evaluator(p,model),NOMAD::Evaluator(p){_is_model_evaluator=true;} /// Destructor. virtual ~Single_Obj_Quad_Model_Evaluator ( void ){;} + /// Evaluate the blackboxes quad model at a given trial point /** \param x point to evaluate -- \b IN/OUT. @@ -75,6 +76,7 @@ namespace NOMAD { const NOMAD::Double & h_max , bool & count_eval ) const {return Quad_Model_Evaluator::eval_x(x,h_max,count_eval);} + }; } diff --git a/src/Slave.cpp b/src/Slave.cpp index 1986ce5..cb73ff5 100644 --- a/src/Slave.cpp +++ b/src/Slave.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Slave.cpp - \brief Slave process (implementation) - \author Sebastien Le Digabel - \date 2010-04-22 - \see Slave.hpp -*/ + \file Slave.cpp + \brief Slave process (implementation) + \author Sebastien Le Digabel + \date 2010-04-22 + \see Slave.hpp + */ #include "Slave.hpp" /*-----------------------------------*/ @@ -58,24 +58,24 @@ bool NOMAD::Slave::_stop_ok = false; void NOMAD::Slave::init ( void ) const { #ifdef USE_MPI - MPI_Comm_rank ( MPI_COMM_WORLD, &NOMAD::Slave::_rank ); - MPI_Comm_size ( MPI_COMM_WORLD, &NOMAD::Slave::_np ); + MPI_Comm_rank ( MPI_COMM_WORLD, &NOMAD::Slave::_rank ); + MPI_Comm_size ( MPI_COMM_WORLD, &NOMAD::Slave::_np ); #else - NOMAD::Slave::_rank = 0; - NOMAD::Slave::_np = 1; + NOMAD::Slave::_rank = 0; + NOMAD::Slave::_np = 1; #endif - - // Slave::force_quit() will be called if ctrl-c is pressed: - if ( !NOMAD::Slave::is_master() ) { - - NOMAD::Evaluator::force_quit(); - - signal ( SIGTERM , NOMAD::Slave::force_quit ); - signal ( SIGINT , NOMAD::Slave::force_quit ); + + // Slave::force_quit() will be called if ctrl-c is pressed: + if ( !NOMAD::Slave::is_master() ) { + + NOMAD::Evaluator::force_quit(); + + signal ( SIGTERM , NOMAD::Slave::force_quit ); + signal ( SIGINT , NOMAD::Slave::force_quit ); #ifndef WINDOWS - signal ( SIGPIPE , NOMAD::Slave::force_quit ); // (ctrl-c during a "| more") + signal ( SIGPIPE , NOMAD::Slave::force_quit ); // (ctrl-c during a "| more") #endif - } + } } /*----------------------------------------*/ @@ -84,14 +84,14 @@ void NOMAD::Slave::init ( void ) const /*----------------------------------------*/ int NOMAD::Slave::get_rank ( void ) { - if ( NOMAD::Slave::_rank < 0 ) { + if ( NOMAD::Slave::_rank < 0 ) { #ifdef USE_MPI - MPI_Comm_rank ( MPI_COMM_WORLD, &NOMAD::Slave::_rank ); + MPI_Comm_rank ( MPI_COMM_WORLD, &NOMAD::Slave::_rank ); #else - NOMAD::Slave::_rank = 0; + NOMAD::Slave::_rank = 0; #endif - } - return NOMAD::Slave::_rank; + } + return NOMAD::Slave::_rank; } /*----------------------------------------*/ @@ -100,14 +100,14 @@ int NOMAD::Slave::get_rank ( void ) /*----------------------------------------*/ int NOMAD::Slave::get_nb_processes ( void ) { - if ( NOMAD::Slave::_np < 0 ) { + if ( NOMAD::Slave::_np < 0 ) { #ifdef USE_MPI - MPI_Comm_size ( MPI_COMM_WORLD, &NOMAD::Slave::_np ); + MPI_Comm_size ( MPI_COMM_WORLD, &NOMAD::Slave::_np ); #else - NOMAD::Slave::_np = 1; + NOMAD::Slave::_np = 1; #endif - } - return NOMAD::Slave::_np; + } + return NOMAD::Slave::_np; } /*----------------------*/ @@ -116,58 +116,58 @@ int NOMAD::Slave::get_nb_processes ( void ) void NOMAD::Slave::run ( void ) const { #ifdef USE_MPI - - MPI_Request req; - char signal = 0; - NOMAD::Eval_Point * x = NULL; - bool count_eval = false; - - while ( true ) { - - // receive signal from master: - // --------------------------- - NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , 0 , &req ); - - // slave is ready or not initialized: - NOMAD::Slave::send_data ( &NOMAD::READY_SIGNAL , 1 , MPI_CHAR , 0 , false ); - - NOMAD::Slave::wait_request ( req ); - // EVAL signal: - // ------------ - if ( signal == NOMAD::EVAL_SIGNAL ) { - - // receive and evaluate the point: - x = eval_point ( count_eval ); - - } - - // RESULT signal: - // -------------- - else if ( signal == NOMAD::RESULT_SIGNAL ) - { - - // send the evaluation result to the master: - send_eval_result ( x , count_eval ); - - delete x; - x = NULL; + MPI_Request req; + char signal = 0; + NOMAD::Eval_Point * x = NULL; + bool count_eval = false; + + while ( true ) { + + // receive signal from master: + // --------------------------- + NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , 0 , &req ); + + // slave is ready or not initialized: + NOMAD::Slave::send_data ( &NOMAD::READY_SIGNAL , 1 , MPI_CHAR , 0 , false ); + + NOMAD::Slave::wait_request ( req ); + + // EVAL signal: + // ------------ + if ( signal == NOMAD::EVAL_SIGNAL ) { + + // receive and evaluate the point: + x = eval_point ( count_eval ); + + } + + // RESULT signal: + // -------------- + else if ( signal == NOMAD::RESULT_SIGNAL ) + { + + // send the evaluation result to the master: + send_eval_result ( x , count_eval ); + + delete x; + x = NULL; + } + + // STOP signal: + // ------------ + else if ( signal == NOMAD::STOP_SIGNAL ) + break; + + // WAIT signal: + // ------------ + // else if ( signal == NOMAD::WAIT_SIGNAL ) { + // } } - - // STOP signal: - // ------------ - else if ( signal == NOMAD::STOP_SIGNAL ) - break; - - // WAIT signal: - // ------------ - // else if ( signal == NOMAD::WAIT_SIGNAL ) { - // } - } - - if ( x ) - delete x; - + + if ( x ) + delete x; + #endif } @@ -178,93 +178,101 @@ void NOMAD::Slave::run ( void ) const void NOMAD::Slave::init_slaves ( const NOMAD::Display & out ) { #ifdef USE_MPI - - if ( !NOMAD::Slave::is_master() || NOMAD::Slave::_are_running ) - return; - - NOMAD::dd_type display_degree = out.get_gen_dd(); - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::open_block ( "initializing slaves" ); - - MPI_Status status; - MPI_Request ** req = new MPI_Request * [ NOMAD::Slave::_np ]; - int nb_initialized = 0; - int nb_slaves = NOMAD::Slave::_np - 1; - int source; - char signal; - NOMAD::Clock clk; - - // 1. launch requests: - for ( source = 1 ; source < NOMAD::Slave::_np ; ++source ) { - req[source] = new MPI_Request; - NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , source , req[source] ); + + if ( !NOMAD::Slave::is_master() || NOMAD::Slave::_are_running ) + return; + + NOMAD::dd_type display_degree = out.get_gen_dd(); if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "." << std::endl; - } - - // 2. test requests (with a maximal delay of MAX_REQ_WAIT): - int cnt = 0 , flag; - while ( nb_initialized < nb_slaves && clk.get_real_time() < NOMAD::MAX_REQ_WAIT ) { - + out << std::endl << NOMAD::open_block ( "initializing slaves" ); + + MPI_Status status; + MPI_Request ** req = new MPI_Request * [ NOMAD::Slave::_np ]; + int nb_initialized = 0; + int nb_slaves = NOMAD::Slave::_np - 1; + int source; + char signal; + NOMAD::Clock clk; + + // 1. launch requests: for ( source = 1 ; source < NOMAD::Slave::_np ; ++source ) { + req[source] = new MPI_Request; + NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , source , req[source] ); + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "." << std::endl; + } - if ( req[source] ) { - - MPI_Test ( req[source] , &flag , &status ); - - if ( flag ) { - - MPI_Wait ( req[source] , &status ); - - // send the WAIT signal: - NOMAD::Slave::send_data ( &NOMAD::WAIT_SIGNAL , 1 , MPI_CHAR , source , true ); - - delete req[source]; - req[source] = NULL; - ++nb_initialized; - } - } + // 2. test requests (with a maximal delay of MAX_REQ_WAIT): + int cnt = 0 , flag; + while ( nb_initialized < nb_slaves && clk.get_real_time() < NOMAD::MAX_REQ_WAIT ) + { + + for ( source = 1 ; source < NOMAD::Slave::_np ; ++source ) + { + + if ( req[source] ) + { + + MPI_Test ( req[source] , &flag , &status ); + + if ( flag ) + { + + MPI_Wait ( req[source] , &status ); + + // send the WAIT signal: + NOMAD::Slave::send_data ( &NOMAD::WAIT_SIGNAL , 1 , MPI_CHAR , source , true ); + + delete req[source]; + req[source] = NULL; + ++nb_initialized; + } + } + } + // a constant is used in order to display only a few '.' : + if ( display_degree == NOMAD::FULL_DISPLAY && cnt%1000000==0 ) + out << "." << std::endl; + + ++cnt; } - // a constant is used in order to display only a few '.' : - if ( display_degree == NOMAD::FULL_DISPLAY && cnt%1000000==0 ) - out << "." << std::endl; - - ++cnt; - } - - // 3. delete requests: - std::list<int> err_list; - for ( source = 1 ; source < NOMAD::Slave::_np ; ++source ) { - if ( req[source] ) { - err_list.push_back ( source ); - MPI_Cancel ( req[source] ); - delete req[source]; + + // 3. delete requests: + std::list<int> err_list; + for ( source = 1 ; source < NOMAD::Slave::_np ; ++source ) + { + if ( req[source] ) + { + err_list.push_back ( source ); + MPI_Cancel ( req[source] ); + delete req[source]; + } } - } - delete [] req; - - NOMAD::Slave::_are_running = true; - NOMAD::Slave::_stop_ok = false; - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << NOMAD::close_block() << std::endl; - - if ( !err_list.empty() ) { - - std::ostringstream oss; - oss << "could not initialize slave"; - if ( err_list.size() > 1 ) { - oss << "s"; - std::list<int>::const_iterator it , end = err_list.end(); - for ( it = err_list.begin() ; it != end ; ++it ) - oss << " #" << *it; + delete [] req; + + NOMAD::Slave::_are_running = true; + NOMAD::Slave::_stop_ok = false; + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << NOMAD::close_block() << std::endl; + + if ( !err_list.empty() ) + { + + std::ostringstream oss; + oss << "could not initialize slave"; + if ( err_list.size() > 1 ) + { + oss << "s"; + std::list<int>::const_iterator it , end = err_list.end(); + for ( it = err_list.begin() ; it != end ; ++it ) + oss << " #" << *it; + } + else + oss << " #" << *err_list.begin(); + + throw NOMAD::Exception ( "Slave.cpp" , __LINE__ , oss.str() ); } - else - oss << " #" << *err_list.begin(); - - throw NOMAD::Exception ( "Slave.cpp" , __LINE__ , oss.str() ); - } - + #endif } @@ -275,78 +283,78 @@ void NOMAD::Slave::init_slaves ( const NOMAD::Display & out ) void NOMAD::Slave::stop_slaves ( const NOMAD::Display & out ) { #ifdef USE_MPI - - if ( !NOMAD::Slave::is_master() || NOMAD::Slave::_stop_ok ) - return; - - NOMAD::dd_type display_degree = out.get_gen_dd(); - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << NOMAD::open_block ( "stopping slaves" ); - - int nb_stopped = 0; - int nb_slaves = NOMAD::Slave::_np - 1; - int source; - char signal; - - NOMAD::Clock clk; - - MPI_Status status; - MPI_Request ** req = new MPI_Request * [ NOMAD::Slave::_np ]; - - // 1. launch requests: - for ( source = 1 ; source < NOMAD::Slave::_np ; ++source ) { - req[source] = new MPI_Request; - NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , source , req[source] ); + + if ( !NOMAD::Slave::is_master() || NOMAD::Slave::_stop_ok ) + return; + + NOMAD::dd_type display_degree = out.get_gen_dd(); if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "." << std::endl; - } - - // 2. test requests (with a maximal delay of MAX_REQ_WAIT): - int cnt = 0 , flag; - while ( nb_stopped < nb_slaves && clk.get_real_time() < NOMAD::MAX_REQ_WAIT ) { - + out << std::endl << NOMAD::open_block ( "stopping slaves" ); + + int nb_stopped = 0; + int nb_slaves = NOMAD::Slave::_np - 1; + int source; + char signal; + + NOMAD::Clock clk; + + MPI_Status status; + MPI_Request ** req = new MPI_Request * [ NOMAD::Slave::_np ]; + + // 1. launch requests: for ( source = 1 ; source < NOMAD::Slave::_np ; ++source ) { + req[source] = new MPI_Request; + NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , source , req[source] ); + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "." << std::endl; + } - if ( req[source] ) { - - MPI_Test ( req[source] , &flag , &status ); - - if ( flag ) { - - MPI_Wait ( req[source] , &status ); - - // send the STOP signal: - NOMAD::Slave::send_data ( &NOMAD::STOP_SIGNAL , 1 , MPI_CHAR , source , true ); - - delete req[source]; - req[source] = NULL; - ++nb_stopped; - } - } + // 2. test requests (with a maximal delay of MAX_REQ_WAIT): + int cnt = 0 , flag; + while ( nb_stopped < nb_slaves && clk.get_real_time() < NOMAD::MAX_REQ_WAIT ) { + + for ( source = 1 ; source < NOMAD::Slave::_np ; ++source ) { + + if ( req[source] ) { + + MPI_Test ( req[source] , &flag , &status ); + + if ( flag ) { + + MPI_Wait ( req[source] , &status ); + + // send the STOP signal: + NOMAD::Slave::send_data ( &NOMAD::STOP_SIGNAL , 1 , MPI_CHAR , source , true ); + + delete req[source]; + req[source] = NULL; + ++nb_stopped; + } + } + } + // a constant is used in order to display only a few '.' : + if ( display_degree == NOMAD::FULL_DISPLAY && cnt%1000000==0 ) + out << "." << std::endl; + ++cnt; } - // a constant is used in order to display only a few '.' : - if ( display_degree == NOMAD::FULL_DISPLAY && cnt%1000000==0 ) - out << "." << std::endl; - ++cnt; - } - - NOMAD::Slave::_are_running = false; - NOMAD::Slave::_stop_ok = true; - - // 3. delete requests: - for ( source = 1 ; source < NOMAD::Slave::_np ; ++source ) { - if ( req[source] ) { - MPI_Cancel ( req[source] ); - delete req[source]; - NOMAD::Slave::_stop_ok = false; + + NOMAD::Slave::_are_running = false; + NOMAD::Slave::_stop_ok = true; + + // 3. delete requests: + for ( source = 1 ; source < NOMAD::Slave::_np ; ++source ) { + if ( req[source] ) { + MPI_Cancel ( req[source] ); + delete req[source]; + NOMAD::Slave::_stop_ok = false; + } } - } - delete [] req; - - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << NOMAD::close_block() << std::endl; - - #endif + delete [] req; + + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << NOMAD::close_block() << std::endl; + +#endif } #ifdef USE_MPI @@ -355,63 +363,63 @@ void NOMAD::Slave::stop_slaves ( const NOMAD::Display & out ) /* receive data (static, private) */ /*------------------------------------------------------*/ int NOMAD::Slave::receive_data ( void * buf , - int count , - MPI_Datatype datatype , - int source , // may be MPI_ANY_SOURCE - MPI_Request * req ) + int count , + MPI_Datatype datatype , + int source , // may be MPI_ANY_SOURCE + MPI_Request * req ) { - int tag = ( NOMAD::Slave::is_master() ) ? source : NOMAD::Slave::get_rank(); - - // immediate receive: - if ( req ) { - if ( source == MPI_ANY_SOURCE ) - throw NOMAD::Exception ( "Slave.cpp" , __LINE__ , - "Slave::receive_data(): immediate receive with no source" ); - MPI_Irecv ( buf , count , datatype , source , tag , MPI_COMM_WORLD , req ); - } - - // normal receive: - else { - MPI_Status status; - if ( source == MPI_ANY_SOURCE ) - tag = MPI_ANY_TAG; - MPI_Recv ( buf , count , datatype , source , tag , MPI_COMM_WORLD , &status ); - source = status.MPI_SOURCE; - } - - // stats: - int size; - MPI_Type_size ( datatype , &size ); - NOMAD::Slave::_data_rcvd += count * size; - - return source; + int tag = ( NOMAD::Slave::is_master() ) ? source : NOMAD::Slave::get_rank(); + + // immediate receive: + if ( req ) { + if ( source == MPI_ANY_SOURCE ) + throw NOMAD::Exception ( "Slave.cpp" , __LINE__ , + "Slave::receive_data(): immediate receive with no source" ); + MPI_Irecv ( buf , count , datatype , source , tag , MPI_COMM_WORLD , req ); + } + + // normal receive: + else { + MPI_Status status; + if ( source == MPI_ANY_SOURCE ) + tag = MPI_ANY_TAG; + MPI_Recv ( buf , count , datatype , source , tag , MPI_COMM_WORLD , &status ); + source = status.MPI_SOURCE; + } + + // stats: + int size; + MPI_Type_size ( datatype , &size ); + NOMAD::Slave::_data_rcvd += count * size; + + return source; } /*------------------------------------------------------*/ /* send data (static, private) */ /*------------------------------------------------------*/ void NOMAD::Slave::send_data ( const void * buf , - int count , - MPI_Datatype datatype , - int dest , - bool ready_send ) + int count , + MPI_Datatype datatype , + int dest , + bool ready_send ) { - int tag = ( NOMAD::Slave::is_master() ) ? dest : NOMAD::Slave::get_rank(); - - // ready send: - if ( ready_send ) - MPI_Rsend ( const_cast<void*>(buf) , count , datatype , - dest , tag , MPI_COMM_WORLD ); - - // normal send: - else - MPI_Send ( const_cast<void*>(buf) , count , datatype , - dest , tag , MPI_COMM_WORLD ); - - // stats: - int size; - MPI_Type_size ( datatype , &size ); - NOMAD::Slave::_data_sent += count * size; + int tag = ( NOMAD::Slave::is_master() ) ? dest : NOMAD::Slave::get_rank(); + + // ready send: + if ( ready_send ) + MPI_Rsend ( const_cast<void*>(buf) , count , datatype , + dest , tag , MPI_COMM_WORLD ); + + // normal send: + else + MPI_Send ( const_cast<void*>(buf) , count , datatype , + dest , tag , MPI_COMM_WORLD ); + + // stats: + int size; + MPI_Type_size ( datatype , &size ); + NOMAD::Slave::_data_sent += count * size; } /*------------------------------------------------------*/ @@ -420,158 +428,159 @@ void NOMAD::Slave::send_data ( const void * buf , /*------------------------------------------------------*/ NOMAD::Eval_Point * NOMAD::Slave::eval_point ( bool & count_eval ) const { - // 1. receive the point: - int itab[3]; - MPI_Request req; - NOMAD::Slave::receive_data ( itab , 3 , MPI_INT , 0 , &req ); - NOMAD::Slave::send_data ( &NOMAD::READY_SIGNAL , 1 , MPI_CHAR , 0 , false ); - NOMAD::Slave::wait_request ( req ); - - int n = itab[0]; - double * dtab = new double[n+1]; - - NOMAD::Slave::receive_data ( dtab , n+1 , MPI_DOUBLE , 0 , &req ); - NOMAD::Slave::send_data ( &NOMAD::READY_SIGNAL , 1 , MPI_CHAR , 0 , false ); - NOMAD::Slave::wait_request ( req ); - - // 2. create the Eval_Point: - NOMAD::Eval_Point * x = new NOMAD::Eval_Point ( n , _p->get_bb_nb_outputs() ); - for ( int i = 0 ; i < n ; ++i ) - (*x)[i] = dtab[i]; - NOMAD::Double h_max = dtab[n]; - - x->set_tag ( itab[2] ); - x->set_eval_type ( ( itab[1] > 0 ) ? NOMAD::SGTE : NOMAD::TRUTH ); - - delete [] dtab; - - // 3. evaluate the point: - bool eval_ok; - try { - eval_ok = _ev->eval_x ( *x , h_max , count_eval ); - } - catch ( ... ) { - eval_ok = false; - } - - x->set_eval_status ( ( eval_ok ) ? NOMAD::EVAL_OK : NOMAD::EVAL_FAIL ); - - return x; + // 1. receive the point: + int itab[3]; + MPI_Request req; + NOMAD::Slave::receive_data ( itab , 3 , MPI_INT , 0 , &req ); + NOMAD::Slave::send_data ( &NOMAD::READY_SIGNAL , 1 , MPI_CHAR , 0 , false ); + NOMAD::Slave::wait_request ( req ); + + int n = itab[0]; + double * dtab = new double[n+1]; + + NOMAD::Slave::receive_data ( dtab , n+1 , MPI_DOUBLE , 0 , &req ); + NOMAD::Slave::send_data ( &NOMAD::READY_SIGNAL , 1 , MPI_CHAR , 0 , false ); + NOMAD::Slave::wait_request ( req ); + + // 2. create the Eval_Point: + int bb_nb_outputs=_p->get_bb_nb_outputs(); + NOMAD::Eval_Point * x = new NOMAD::Eval_Point ( n , bb_nb_outputs ); + for ( int i = 0 ; i < n ; ++i ) + (*x)[i] = dtab[i]; + NOMAD::Double h_max = dtab[n]; + + x->set_tag ( itab[2] ); + x->set_eval_type ( ( itab[1] > 0 ) ? NOMAD::SGTE : NOMAD::TRUTH ); + + delete [] dtab; + + // 3. evaluate the point: + bool eval_ok; + try { + eval_ok = _ev->eval_x ( *x , h_max , count_eval ); + } + catch ( ... ) { + eval_ok = false; + } + + x->set_eval_status ( ( eval_ok ) ? NOMAD::EVAL_OK : NOMAD::EVAL_FAIL ); + + return x; } /*-----------------------------------------------------*/ /* send an evaluation result to the master (private) */ /*-----------------------------------------------------*/ void NOMAD::Slave::send_eval_result ( const NOMAD::Eval_Point * x , - bool count_eval ) const + bool count_eval ) const { - // receive a signal from the master: - char signal; - NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , 0 , NULL ); - - // send the evaluation result: - int m = _p->get_bb_nb_outputs(); - int s = 2*m+2; - double * dtab = new double [s]; - const NOMAD::Point & bbo = x->get_bb_outputs(); - - // bb_outputs (m values): - for ( int i = 0 ; i < m ; ++i ) { - if ( bbo[i].is_defined() ) { - dtab[i ] = bbo[i].value(); - dtab[i+m] = 1.0; - } - else { - dtab[i ] = NOMAD::INF; - dtab[i+m] = -1.0; + // receive a signal from the master: + char signal; + NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , 0 , NULL ); + + // send the evaluation result: + int m = _p->get_bb_nb_outputs(); + int s = 2*m+2; + double * dtab = new double [s]; + const NOMAD::Point & bbo = x->get_bb_outputs(); + + // bb_outputs (m values): + for ( int i = 0 ; i < m ; ++i ) { + if ( bbo[i].is_defined() ) { + dtab[i ] = bbo[i].value(); + dtab[i+m] = 1.0; + } + else { + dtab[i ] = NOMAD::INF; + dtab[i+m] = -1.0; + } } - } - - // evaluation status: - dtab[2*m] = ( x->get_eval_status() == NOMAD::EVAL_OK ) ? 1.0 : -1.0; - - // count_eval: - dtab[s-1] = ( count_eval ) ? 1.0 : -1.0; - - // send the array: - NOMAD::Slave::send_data ( dtab , s , MPI_DOUBLE , 0 , true ); - - delete [] dtab; + + // evaluation status: + dtab[2*m] = ( x->get_eval_status() == NOMAD::EVAL_OK ) ? 1.0 : -1.0; + + // count_eval: + dtab[s-1] = ( count_eval ) ? 1.0 : -1.0; + + // send the array: + NOMAD::Slave::send_data ( dtab , s , MPI_DOUBLE , 0 , true ); + + delete [] dtab; } /*---------------------------------------------*/ /* receive an evaluation result from a slave */ /*---------------------------------------------*/ void NOMAD::Slave::receive_eval_result ( int slave_rank , - NOMAD::Eval_Point * x , - bool & eval_ok , - bool & count_eval ) const + NOMAD::Eval_Point * x , + bool & eval_ok , + bool & count_eval ) const { - // send the RESULT signal to the slave: - NOMAD::Slave::send_data ( &NOMAD::RESULT_SIGNAL , 1 , MPI_CHAR , slave_rank , true ); - - // receive the evaluation result as a double array: - int m = _p->get_bb_nb_outputs(); - int s = 2*m+2; - double * dtab = new double [s]; - - MPI_Request req; - NOMAD::Slave::receive_data ( dtab , s , MPI_DOUBLE , slave_rank , &req ); - NOMAD::Slave::send_data ( &NOMAD::READY_SIGNAL , 1 , MPI_CHAR , slave_rank , false ); - NOMAD::Slave::wait_request ( req ); - - // interpret the array: - for ( int i = 0 ; i < m ; ++i ) - x->set_bb_output ( i , ( dtab[i+m] > 0.0 ) ? dtab[i] : NOMAD::Double() ); - - eval_ok = ( dtab[2*m] > 0.0 ); - - x->set_eval_status ( eval_ok ? NOMAD::EVAL_OK : NOMAD::EVAL_FAIL ); - - count_eval = ( dtab[s-1] > 0.0 ); - - delete [] dtab; + // send the RESULT signal to the slave: + NOMAD::Slave::send_data ( &NOMAD::RESULT_SIGNAL , 1 , MPI_CHAR , slave_rank , true ); + + // receive the evaluation result as a double array: + int m = _p->get_bb_nb_outputs(); + int s = 2*m+2; + double * dtab = new double [s]; + + MPI_Request req; + NOMAD::Slave::receive_data ( dtab , s , MPI_DOUBLE , slave_rank , &req ); + NOMAD::Slave::send_data ( &NOMAD::READY_SIGNAL , 1 , MPI_CHAR , slave_rank , false ); + NOMAD::Slave::wait_request ( req ); + + // interpret the array: + for ( int i = 0 ; i < m ; ++i ) + x->set_bb_output ( i , ( dtab[i+m] > 0.0 ) ? dtab[i] : NOMAD::Double() ); + + eval_ok = ( dtab[2*m] > 0.0 ); + + x->set_eval_status ( eval_ok ? NOMAD::EVAL_OK : NOMAD::EVAL_FAIL ); + + count_eval = ( dtab[s-1] > 0.0 ); + + delete [] dtab; } /*-----------------------------------------------------*/ /* send an Eval_Point to a slave */ /*-----------------------------------------------------*/ void NOMAD::Slave::send_eval_point ( const NOMAD::Eval_Point * x , - int slave_rank , - const NOMAD::Double & h_max ) const + int slave_rank , + const NOMAD::Double & h_max ) const { - char signal; - int itab[3]; - int n = x->size(); + char signal; + int itab[3]; + int n = x->size(); - // n: - itab[0] = n; - - // evaluation type (+1: sgte eval; -1: true eval): - itab[1] = ( x->get_eval_type() == NOMAD::SGTE ) ? 1 : -1; - - // tag of the point: - itab[2] = x->get_tag(); - - // point coordinates: - double * dtab = new double[n+1]; - for ( int i = 0 ; i < n ; ++i ) - dtab[i] = (*x)[i].value(); - dtab[n] = h_max.value(); - - // wait for the slave signal: - NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , slave_rank , NULL ); - - // send n and evaluation type: - NOMAD::Slave::send_data ( itab , 3 , MPI_INT , slave_rank , true ); - - // wait for the slave signal: - NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , slave_rank , NULL ); - - // send the point coordinates: - NOMAD::Slave::send_data ( dtab , n+1 , MPI_DOUBLE , slave_rank , true ); - - delete [] dtab; + // n: + itab[0] = n; + + // evaluation type (+1: sgte eval; -1: true eval): + itab[1] = ( x->get_eval_type() == NOMAD::SGTE ) ? 1 : -1; + + // tag of the point: + itab[2] = x->get_tag(); + + // point coordinates: + double * dtab = new double[n+1]; + for ( int i = 0 ; i < n ; ++i ) + dtab[i] = (*x)[i].value(); + dtab[n] = h_max.value(); + + // wait for the slave signal: + NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , slave_rank , NULL ); + + // send n and evaluation type: + NOMAD::Slave::send_data ( itab , 3 , MPI_INT , slave_rank , true ); + + // wait for the slave signal: + NOMAD::Slave::receive_data ( &signal , 1 , MPI_CHAR , slave_rank , NULL ); + + // send the point coordinates: + NOMAD::Slave::send_data ( dtab , n+1 , MPI_DOUBLE , slave_rank , true ); + + delete [] dtab; } /*-----------------------------------------*/ @@ -580,8 +589,8 @@ void NOMAD::Slave::send_eval_point ( const NOMAD::Eval_Point * x , /*-----------------------------------------*/ void NOMAD::Slave::wait_request ( MPI_Request & req ) { - MPI_Status status; - MPI_Wait ( &req , &status ); + MPI_Status status; + MPI_Wait ( &req , &status ); } #endif diff --git a/src/Slave.hpp b/src/Slave.hpp index a460c43..03ae58a 100644 --- a/src/Slave.hpp +++ b/src/Slave.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -82,10 +82,8 @@ namespace NOMAD { \param p Parameters -- \b IN. \param ev A pointer to an evaluator -- \b IN. */ - Slave ( const NOMAD::Parameters & p , - NOMAD::Evaluator * ev ) - : _p ( &p ) , - _ev ( ev ) { init(); } + Slave ( const NOMAD::Parameters & p , NOMAD::Evaluator * ev ) + { _p=&p; _ev=ev; init(); } /// Destructor. virtual ~Slave ( void ) {} diff --git a/src/Speculative_Search.cpp b/src/Speculative_Search.cpp index c4bb03c..468e97d 100644 --- a/src/Speculative_Search.cpp +++ b/src/Speculative_Search.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,12 +34,12 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Speculative_Search.cpp - \brief Speculative search (implementation) - \author Sebastien Le Digabel - \date 2010-04-12 - \see Speculative.hpp -*/ + \file Speculative_Search.cpp + \brief Speculative search (implementation) + \author Sebastien Le Digabel + \date 2010-04-12 + \see Speculative.hpp + */ #include "Speculative_Search.hpp" /*-------------------------------------------------------------*/ @@ -56,148 +56,146 @@ /* and has already been made in Mads.cpp */ /*-------------------------------------------------------------*/ void NOMAD::Speculative_Search::search ( NOMAD::Mads & mads , - int & nb_search_pts , - bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::success_type & success , - bool & count_search , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc ) + int & nb_search_pts , + bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::success_type & success , + bool & count_search , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc ) { - // new_feas_inc and new_infeas_inc are used as inputs, - // so do not initialize them to NULL here - - nb_search_pts = 0; - success = NOMAD::UNSUCCESSFUL; - count_search = !stop; - - if ( stop ) - return; - - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_search_dd(); - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << NOMAD::SPEC_SEARCH; - out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; - } - - int lkm1; // l_{k-1} - int lk; // l_k - int n; - NOMAD::Signature * signature; - NOMAD::Point delta_m_k; - NOMAD::Point delta_m_km1; - NOMAD::Point factor; - NOMAD::Point xkm1; - NOMAD::Eval_Point * sk; - const NOMAD::Eval_Point * x[2]; - x[0] = new_feas_inc; - x[1] = new_infeas_inc; - - // Evaluator_Control: - NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); - - for ( int i = 0 ; i < 2 ; ++i ) { - if ( x[i] && x[i]->get_mesh_index() ) { - - const NOMAD::Direction * dir = x[i]->get_direction(); - if ( dir && ( dir->is_mads() || dir->get_type()==NOMAD::MODEL_SEARCH_DIR ) ) { - - // get the x_k's signature: - signature = x[i]->get_signature(); - if ( !signature ) - throw NOMAD::Exception ( "Speculative_Search.cpp" , __LINE__ , - "Speculative_Search::search(): could not get the signature" ); - - xkm1 = *x[i] - *dir; - - lk = lkm1 = *x[i]->get_mesh_index(); - NOMAD::Mesh::update ( NOMAD::FULL_SUCCESS , lk ); - - n = signature->get_n(); - delta_m_k = NOMAD::Point ( n ); - delta_m_km1 = NOMAD::Point ( n ); - factor = NOMAD::Point ( n ); - - signature->get_mesh().get_delta_m ( delta_m_k , lk ); - signature->get_mesh().get_delta_m ( delta_m_km1 , lkm1 ); - - // multiplicative factor: takes into account the fact that - // the direction contains \Delta^m_k: - try { - - // factor = delta_m_k / delta_m_km1 : - for ( int k = 0 ; k < n ; ++k ) { - if ( delta_m_k[k].is_defined() && delta_m_km1[k].is_defined() && - delta_m_k[k].value() != 0.0 && delta_m_km1[k].value() != 0.0 ) - factor[k] = delta_m_k[k] / delta_m_km1[k]; - else - factor[k] = 0.0; - } - } - catch ( NOMAD::Double::Invalid_Value & ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << "could not compute " << _type << " point: stop" << std::endl - << NOMAD::close_block ( "end of speculative search" ); - stop = true; - stop_reason = NOMAD::MESH_PREC_REACHED; - return; - } - - if ( lkm1 <= 0 ) - factor *= NOMAD::Mesh::get_mesh_update_basis(); - - // speculative search point: - NOMAD::Direction new_dir ( n , 0.0 , dir->get_type() ); - new_dir.Point::operator = ( factor * *dir ); - - sk = new NOMAD::Eval_Point; - sk->set ( n , _p.get_bb_nb_outputs() ); - sk->set_signature ( signature ); - sk->set_direction ( &new_dir ); - sk->set_mesh_index ( &lk ); - - sk->Point::operator = ( xkm1 + new_dir ); - - if ( display_degree == NOMAD::FULL_DISPLAY ) { - out << "trial point #" << sk->get_tag() - << ": ( "; - sk->Point::display ( out ," " , 2 , NOMAD::Point::get_display_limit() ); - out << " )" << std::endl; - } - - // add the new point to the list of search trial points: - ev_control.add_eval_point ( sk , - display_degree , - _p.get_snap_to_bounds() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() ); - } + // new_feas_inc and new_infeas_inc are used as inputs, + // so do not initialize them to NULL here + + nb_search_pts = 0; + success = NOMAD::UNSUCCESSFUL; + count_search = !stop; + + if ( stop ) + return; + + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_search_dd(); + if ( display_degree == NOMAD::FULL_DISPLAY ) { + std::ostringstream oss; + oss << NOMAD::SPEC_SEARCH; + out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; + } + + //int lkm1; // l_{k-1} + // int lk; // l_k + int n; + NOMAD::Signature * signature; + NOMAD::Point delta_m_k; + NOMAD::Point delta_m_km1; + NOMAD::Point factor; + NOMAD::Point xkm1; + NOMAD::Eval_Point * sk; + const NOMAD::Eval_Point * x[2]; + x[0] = new_feas_inc; + x[1] = new_infeas_inc; + + // Evaluator_Control: + NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); + + for ( int i = 0 ; i < 2 ; ++i ) + { + if ( x[i] && x[i]->get_signature() ) + { + + const NOMAD::Direction * dir = x[i]->get_direction(); + if ( dir && ( dir->is_mads() || dir->get_type()==NOMAD::MODEL_SEARCH_DIR ) ) { + + // get the x_k's signature: + signature = x[i]->get_signature(); + if ( !signature ) + throw NOMAD::Exception ( "Speculative_Search.cpp" , __LINE__ , + "Speculative_Search::search(): could not get the signature" ); + + xkm1 = *x[i] - *dir; + + factor = signature->get_mesh()->get_mesh_ratio_if_success(); + n=signature->get_n(); + for ( int k = 0 ; k < n ; ++k ) + { + if ( factor[k].is_defined() ) + { + if ( factor[k] == 1 ) + { + // factor determined based on mesh type ( default is 4 = mesh_update_basis = 2* poll_update_basis ) + if ( dynamic_cast<NOMAD::XMesh *> (signature->get_mesh()) ) + factor[k] = signature->get_mesh()->get_update_basis()*2.0; + else + factor[k] = signature->get_mesh()->get_update_basis(); + + } + else if ( factor[k] == 0 ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << "could not compute " << _type << " point: stop" << std::endl + << NOMAD::close_block ( "end of speculative search" ); + stop = true; + stop_reason = NOMAD::MESH_PREC_REACHED; + return; + } + + } + else + factor[k]=0; + + } + NOMAD::Point mesh_indices_k( x[i]->get_signature()->get_mesh()->get_mesh_indices() ); + signature->get_mesh()->update( NOMAD::FULL_SUCCESS, mesh_indices_k , dir ); + + // speculative search point: + NOMAD::Direction new_dir ( n , 0.0 , dir->get_type() ); + new_dir.Point::operator = ( factor * *dir ); + + sk = new NOMAD::Eval_Point; + sk->set ( n , _p.get_bb_nb_outputs() ); + sk->set_signature ( signature ); + sk->set_direction ( &new_dir ); + + sk->Point::operator = ( xkm1 + new_dir ); + + if ( display_degree == NOMAD::FULL_DISPLAY ) { + out << "trial point #" << sk->get_tag() + << ": ( "; + sk->Point::display ( out ," " , 2 , NOMAD::Point::get_display_limit() ); + out << " )" << std::endl; + } + + // add the new point to the list of search trial points: + ev_control.add_eval_point ( sk , + display_degree , + _p.get_snap_to_bounds() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() ); + } + } + } + + nb_search_pts = ev_control.get_nb_eval_points(); + + // eval_list_of_points:s + // -------------------- + new_feas_inc = new_infeas_inc = NULL; + + ev_control.eval_list_of_points ( _type , + mads.get_true_barrier() , + mads.get_sgte_barrier() , + mads.get_pareto_front() , + stop , + stop_reason , + new_feas_inc , + new_infeas_inc , + success ); + + if ( display_degree == NOMAD::FULL_DISPLAY ) { + std::ostringstream oss; + oss << "end of speculative search (" << success << ")"; + out << NOMAD::close_block ( oss.str() ) << std::endl; } - } - - nb_search_pts = ev_control.get_nb_eval_points(); - - // eval_list_of_points: - // -------------------- - new_feas_inc = new_infeas_inc = NULL; - - ev_control.eval_list_of_points ( _type , - mads.get_true_barrier() , - mads.get_sgte_barrier() , - mads.get_pareto_front() , - stop , - stop_reason , - new_feas_inc , - new_infeas_inc , - success ); - - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << "end of speculative search (" << success << ")"; - out << NOMAD::close_block ( oss.str() ) << std::endl; - } } diff --git a/src/Speculative_Search.hpp b/src/Speculative_Search.hpp index 8ba14c2..e0db82d 100644 --- a/src/Speculative_Search.hpp +++ b/src/Speculative_Search.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/Stats.cpp b/src/Stats.cpp index b65011b..15479e0 100644 --- a/src/Stats.cpp +++ b/src/Stats.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -51,6 +51,7 @@ NOMAD::Stats & NOMAD::Stats::operator = ( const NOMAD::Stats & s ) _sim_bb_eval = s._sim_bb_eval; _sgte_eval = s._sgte_eval; _bb_eval = s._bb_eval; + _block_eval = s._block_eval; _failed_eval = s._failed_eval; _cache_hits = s._cache_hits; _interrupted_eval = s._interrupted_eval; @@ -107,6 +108,7 @@ void NOMAD::Stats::reset ( void ) _sim_bb_eval = _sgte_eval = _bb_eval = + _block_eval = _failed_eval = _cache_hits = _interrupted_eval = @@ -167,6 +169,7 @@ void NOMAD::Stats::update ( const NOMAD::Stats & s , bool for_search ) _sim_bb_eval += s._sim_bb_eval; _sgte_eval += s._sgte_eval; _bb_eval += s._bb_eval; + _block_eval += s._block_eval; _failed_eval += s._failed_eval; _cache_hits += s._cache_hits; _interrupted_eval += s._interrupted_eval; @@ -256,6 +259,9 @@ void NOMAD::Stats::display ( const NOMAD::Display & out ) const out << "bb evaluations (with sgte cost) : " << get_bb_eval(); else out << "blackbox evaluations : " << _bb_eval; + out << std::endl; + if ( _block_eval > 0) + out << "Block of evaluations : " << _block_eval; if ( _p1_bbe > 0 ) out << " (phase one: " << _p1_bbe << ")"; out << std::endl; diff --git a/src/Stats.hpp b/src/Stats.hpp index 5e02b11..db9cf2a 100644 --- a/src/Stats.hpp +++ b/src/Stats.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -69,6 +69,7 @@ namespace NOMAD { int _sgte_eval; ///< Number of surrogate evaluations. int _sgte_cost; ///< Surrogate cost. int _bb_eval; ///< Number of blackbox evaluations. + int _block_eval; ///< Number of block of evaluations. int _failed_eval; ///< Number of failed evaluations. int _cache_hits; ///< Number of cache hits. int _interrupted_eval; ///< Number of interrupted sequence of evaluations. @@ -150,6 +151,7 @@ public: _sgte_eval ( s._sgte_eval ) , _sgte_cost ( s._sgte_cost ) , _bb_eval ( s._bb_eval ) , + _block_eval ( s._block_eval ) , _failed_eval ( s._failed_eval ) , _cache_hits ( s._cache_hits ) , _interrupted_eval ( s._interrupted_eval ) , @@ -239,10 +241,19 @@ public: /// Add \c 1 to stat \c _sgte_eval. void add_sgte_eval ( void ) { ++_sgte_eval; } - + + /// Add \c count_eval to stat \c _sgte_eval. + void add_sgte_eval ( int count_eval ) { _sgte_eval+=count_eval; } + /// Add \c 1 to stat \c _bb_eval. void add_bb_eval ( void ) { ++_bb_eval; } + /// Add \c 1 to stat \c _block_eval. + void add_one_block_eval ( void ) { ++_block_eval; } + + /// Add \c count_eval to stat \c _bb_eval. + void add_bb_eval ( int count_eval ) { _bb_eval+=count_eval; } + /// Add \c 1 to stat \c _failed_eval. void add_failed_eval ( void ) { ++_failed_eval; } @@ -475,6 +486,16 @@ public: return ( _sgte_cost > 0 ) ? _bb_eval + _sgte_eval / _sgte_cost : _bb_eval; } + + /// Access to the number of block of evaluations (includes bb and surrogates). + /** + \return The number of blackbox evaluations. + */ + int get_block_eval ( void ) const + { + return _block_eval; + } + /// Access to the \c sum stat. /** \return The \c sum stat. diff --git a/src/TGP_Model.cpp b/src/TGP_Model.cpp index 900d6ea..b5005f6 100644 --- a/src/TGP_Model.cpp +++ b/src/TGP_Model.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/TGP_Model.hpp b/src/TGP_Model.hpp index 22e0a10..78cf20c 100644 --- a/src/TGP_Model.hpp +++ b/src/TGP_Model.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/TGP_Model_Evaluator.cpp b/src/TGP_Model_Evaluator.cpp index 58538e8..3edc7c6 100644 --- a/src/TGP_Model_Evaluator.cpp +++ b/src/TGP_Model_Evaluator.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/TGP_Model_Evaluator.hpp b/src/TGP_Model_Evaluator.hpp index 5358b84..2a378f2 100644 --- a/src/TGP_Model_Evaluator.hpp +++ b/src/TGP_Model_Evaluator.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/TGP_Model_Search.cpp b/src/TGP_Model_Search.cpp index 4c1c373..bf5b6bc 100644 --- a/src/TGP_Model_Search.cpp +++ b/src/TGP_Model_Search.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -202,10 +202,8 @@ void NOMAD::TGP_Model_Search::search ( NOMAD::Mads & mads count_search = true; _one_search_stats.add_MS_nb_searches(); - // mesh: - int mesh_index = NOMAD::Mesh::get_mesh_index(); - NOMAD::Point delta_m; - signature->get_mesh().get_delta_m ( delta_m , mesh_index ); + NOMAD::Point delta_m; + signature->get_mesh()->get_delta(delta_m); // initial displays: if ( display_degree == NOMAD::FULL_DISPLAY ) { @@ -214,7 +212,6 @@ void NOMAD::TGP_Model_Search::search ( NOMAD::Mads & mads << _p.get_seed() << std::endl; #endif out << "number of cache points: " << cache.size() << std::endl - << "mesh index : " << mesh_index << std::endl << "mesh size parameter : ( " << delta_m << " )" << std::endl << "incumbent : ( "; incumbent->NOMAD::Point::display @@ -320,7 +317,6 @@ void NOMAD::TGP_Model_Search::search ( NOMAD::Mads & mads register_point ( *trial_pts[i] , *signature , *incumbent , - mesh_index , display_degree , ev_control ); @@ -1203,7 +1199,6 @@ void NOMAD::TGP_Model_Search::register_point ( NOMAD::Point x , NOMAD::Signature & signature , const NOMAD::Point & incumbent , - int mesh_index , NOMAD::dd_type display_degree , NOMAD::Evaluator_Control & ev_control ) const { @@ -1220,8 +1215,7 @@ void NOMAD::TGP_Model_Search::register_point } tk->set_signature ( &signature ); - tk->set_mesh_index ( &mesh_index ); - tk->Point::operator = ( x ); + tk->Point::operator = ( x ); // add the new point to the list of search trial points: ev_control.add_eval_point ( tk , @@ -1457,8 +1451,6 @@ bool NOMAD::TGP_Model_Search::optimize_model // parameters creation: NOMAD::Parameters model_param ( out ); - // random seed: - model_param.set_SEED ( _p.get_seed() + 10 * _all_searches_stats.get_MS_nb_searches() ); // number of variables: model_param.set_DIMENSION ( n ); @@ -1466,9 +1458,6 @@ bool NOMAD::TGP_Model_Search::optimize_model // blackbox outputs: model_param.set_BB_OUTPUT_TYPE ( _p.get_bb_output_type() ); - // blackbox inputs: - model_param.set_BB_INPUT_TYPE ( _p.get_bb_input_type() ); - // barrier parameters: model_param.set_H_MIN ( _p.get_h_min () ); model_param.set_H_NORM ( _p.get_h_norm() ); @@ -1501,30 +1490,19 @@ bool NOMAD::TGP_Model_Search::optimize_model else model_param.set_DISPLAY_STATS ( "bbe obj" ); } - - // mesh: - int mesh_index = NOMAD::Mesh::get_mesh_index(); - int min_mesh_index = NOMAD::Mesh::get_min_mesh_index(); - int max_mesh_index = NOMAD::Mesh::get_max_mesh_index(); - int max_halton_index = NOMAD::Mesh::get_max_halton_index(); - - NOMAD::Mesh::init ( 4.0 , 1 , -1 , 0 ); - - // searches: - // model_param.set_LH_SEARCH ( 1000 , 100 ); - // model_param.set_OPPORTUNISTIC_LH ( true ); - // model_param.set_VNS_SEARCH ( true ); + // mesh: use isotropic mesh + model_param.set_ANISOTROPIC_MESH ( false ); + model_param.set_MESH_UPDATE_BASIS ( 4.0 ); + model_param.set_MESH_COARSENING_EXPONENT ( 1 ); + model_param.set_MESH_REFINING_EXPONENT ( -1 ); + model_param.set_INITIAL_MESH_INDEX ( 0 ); + // maximum number of evaluations (2000 or 10000): model_param.set_MAX_BB_EVAL ( ( _p.get_model_tgp_mode() == NOMAD::TGP_PRECISE ) ? 10000 : 2000 ); - // min mesh size: - // model_param.set_MAX_MESH_INDEX ( 30 ); - // model_param.set_MIN_MESH_SIZE ( NOMAD::Double ( 1e-8 ) , false ); - model_param.set_SNAP_TO_BOUNDS ( true ); - // model_param.set_SNAP_TO_BOUNDS ( false ); // disable user calls: model_param.set_USER_CALLS_ENABLED ( false ); @@ -1600,18 +1578,6 @@ bool NOMAD::TGP_Model_Search::optimize_model NOMAD::Mads::set_flag_reset_barriers ( flag_reset_barriers ); NOMAD::Mads::set_flag_p1_active ( flag_p1_active ); - // reset mesh to what it was before: - NOMAD::Mesh::init ( _p.get_mesh_update_basis().value() , - _p.get_mesh_coarsening_exponent() , - _p.get_mesh_refining_exponent() , - _p.get_initial_mesh_index() ); - - NOMAD::Mesh::set_max_halton_index ( max_halton_index ); - - NOMAD::Mesh::set_mesh_index ( min_mesh_index ); - NOMAD::Mesh::set_mesh_index ( max_mesh_index ); - NOMAD::Mesh::set_mesh_index ( mesh_index ); - // close display block: if ( display_degree == NOMAD::FULL_DISPLAY ) { if ( error ) diff --git a/src/TGP_Model_Search.hpp b/src/TGP_Model_Search.hpp index fe614ca..c31faf1 100644 --- a/src/TGP_Model_Search.hpp +++ b/src/TGP_Model_Search.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -205,14 +205,12 @@ namespace NOMAD { \param x The point coordinates -- \b IN. \param signature Signature -- \b IN. \param incumbent The incumbent -- \b IN. - \param mesh_index Mesh index -- \b IN. \param display_degree Display degree -- \b IN. \param ev_control The NOMAD::Evaluator_Control object -- \b IN/OUT. */ void register_point ( NOMAD::Point x , NOMAD::Signature & signature , - const NOMAD::Point & incumbent , - int mesh_index , + const NOMAD::Point & incumbent ,, NOMAD::dd_type display_degree , NOMAD::Evaluator_Control & ev_control ) const; diff --git a/src/TGP_Output_Model.cpp b/src/TGP_Output_Model.cpp index 569c1b5..55152a1 100644 --- a/src/TGP_Output_Model.cpp +++ b/src/TGP_Output_Model.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -52,7 +52,7 @@ int TGP_OUTPUT_MODEL_DUMMY; // avoids that TGP_Output_Model.o has no symbols wit /*---------------------------------------------------------*/ /* NOMAD-TGP callback function (called regularly by TGP) */ /*---------------------------------------------------------*/ -// SLD -- 2012-09-04 +// SLD -- 2014-09-04 // void NOMAD::TGP_callback ( bool & TGP_interrupt ) // { // if ( NOMAD::TGP_Output_Model::get_force_quit() ) @@ -225,7 +225,7 @@ void NOMAD::TGP_Output_Model::compute ( double ** X , NULL ); // dhier=NULL // set the NOMAD-TGP callback function: - // _tgp_model->set_callback ( NOMAD::TGP_callback ); // SLD -- 2012-09-04 + // _tgp_model->set_callback ( NOMAD::TGP_callback ); // SLD -- 2014-09-04 // TGP verbim (display): #ifdef TGP_DEBUG diff --git a/src/TGP_Output_Model.hpp b/src/TGP_Output_Model.hpp index ea89275..eaae843 100644 --- a/src/TGP_Output_Model.hpp +++ b/src/TGP_Output_Model.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -62,7 +62,7 @@ extern "C" namespace NOMAD { // NOMAD-TGP callback function (called regularly by TGP). - // void TGP_callback ( bool & TGP_interrupt ); // SLD -- 2012-09-04 + // void TGP_callback ( bool & TGP_interrupt ); // SLD -- 2014-09-04 /// TGP models for one output. class TGP_Output_Model : private NOMAD::Uncopyable { diff --git a/src/Uncopyable.hpp b/src/Uncopyable.hpp index d14e567..64065a3 100644 --- a/src/Uncopyable.hpp +++ b/src/Uncopyable.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/VNS_Search.cpp b/src/VNS_Search.cpp index 343a4b1..508057a 100644 --- a/src/VNS_Search.cpp +++ b/src/VNS_Search.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -47,11 +47,9 @@ /*---------------------------------------------------------*/ void NOMAD::VNS_Search::reset ( void ) { - _k = _k_max = 1; - _halton_index = NOMAD::VNS_HALTON_INDEX_0; - _old_x = NULL; - for ( int ell = 0 ; ell <= NOMAD::L_LIMITS ; ++ell ) - _nb_performed[ell] = 0; + _k = _k_max = 1; + _old_x = NULL; + } /*---------------------------------------------------------*/ @@ -59,574 +57,580 @@ void NOMAD::VNS_Search::reset ( void ) /* VNS: x --[shaking(k)]--> x' --[descent]--> x" */ /*---------------------------------------------------------*/ void NOMAD::VNS_Search::search ( NOMAD::Mads & mads , - int & nb_search_pts , - bool & stop , - NOMAD::stop_type & stop_reason , - NOMAD::success_type & success , - bool & count_search , - const NOMAD::Eval_Point *& new_feas_inc , - const NOMAD::Eval_Point *& new_infeas_inc ) + int & nb_search_pts , + bool & stop , + NOMAD::stop_type & stop_reason , + NOMAD::success_type & success , + bool & count_search , + const NOMAD::Eval_Point *& new_feas_inc , + const NOMAD::Eval_Point *& new_infeas_inc ) { - new_feas_inc = new_infeas_inc = NULL; - nb_search_pts = 0; - success = NOMAD::UNSUCCESSFUL; - count_search = !stop; - - if ( stop ) - return; - - // initial display: - const NOMAD::Display & out = _p.out(); - NOMAD::dd_type display_degree = out.get_search_dd(); - if ( display_degree == NOMAD::FULL_DISPLAY ) { - std::ostringstream oss; - oss << NOMAD::VNS_SEARCH; - out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; - } - - bool opt_only_sgte = _p.get_opt_only_sgte(); - - // the barriers: - NOMAD::Barrier & true_barrier = mads.get_true_barrier(); - NOMAD::Barrier & sgte_barrier = mads.get_sgte_barrier(); - const NOMAD::Barrier & active_barrier = mads.get_active_barrier(); - - // point x: - NOMAD::Double best_f; - bool x_feas = true; - const NOMAD::Eval_Point * x = active_barrier.get_best_feasible(); - if ( x ) - best_f = x->get_f(); - else { - x = active_barrier.get_best_infeasible(); - x_feas = false; - } - - if ( !x ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out.close_block ( "end of VNS search (no incumbent)" ); - return; - } - - // update _k and _old_x: - if ( x == _old_x ) { - ++_k; - if ( _k > _k_max ) - _k_max = _k; - } - else - _k = 1; - - _old_x = x; - - // get the signature: - NOMAD::Signature * signature = x->get_signature(); - if ( !signature ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out.close_block ( "end of VNS search (no signature)" ); - return; - } - - int n = signature->get_n(); - if ( n != x->size() ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out.close_block ( "end of VNS search (incompatible signature)" ); - return; - } - - // shaking: get ONE direction from the signature: - NOMAD::Direction dir; - signature->get_one_direction ( dir , - 1 - _k , // mesh_index = 1-k - _halton_index ); - - _halton_index += NOMAD::VNS_HALTON_INCR; - - // shaking: construct x': - NOMAD::Point xp = *x + dir; - - // shaking: the perturbation is tried twice with dir and -dir - // (in case x == x + dir after snapping) - for ( int nbt = 0 ; nbt < 2 ; ++nbt ) { - - // treat xp: periodic variables or bounds: - if ( _p.has_periodic_variables() ) { - NOMAD::Direction * tmp_dir = NULL; - signature->treat_periodic_variables ( xp , NULL , tmp_dir ); - } - else - signature->snap_to_bounds ( xp , NULL ); - - // if xp == x : - if ( xp == *x ) { - - // no third try: the search fails - if ( nbt == 1 ) { - if ( display_degree == NOMAD::FULL_DISPLAY ) - out.close_block ( "end of VNS search (shaking failed)" ); - return; - } - - // 2nd try (-dir instead of dir): - xp = *x - dir; - } - } - - // current mesh index: - int mesh_index = NOMAD::Mesh::get_mesh_index(); - - // reset mesh index: - int initial_mesh_index = _p.get_initial_mesh_index(); - NOMAD::Mesh::set_mesh_index ( initial_mesh_index ); - - // stats: - NOMAD::Stats & stats = mads.get_stats(); - - // current number of blackbox evaluations: - int bbe = stats.get_bb_eval(); - int sgte_eval = stats.get_sgte_eval(); - int mads_iterations = stats.get_iterations(); - bool has_sgte = _p.has_sgte(); - - // displays: - if ( display_degree == NOMAD::FULL_DISPLAY ) { - out << " it = " << mads_iterations << std::endl - << " bbe = " << bbe << std::endl; - if ( has_sgte ) - out << " sgte_eval = " << sgte_eval << std::endl; - out << "mesh_index = " << mesh_index << std::endl - << " k = " << _k << std::endl - << " kmax = " << _k_max << std::endl - << " x = ( "; - x->Point::display ( out , " " , 5 , _p.get_point_display_limit() ); - out << " ) f=" << x->get_f() << " h=" << x->get_h() << std::endl - << " dir = ( "; - dir.Point::display ( out , " " , 5 , _p.get_point_display_limit() ); - out << " ) |dir|="; - NOMAD::Double norm = dir.norm(); - out << norm << std::endl; - out << " xp = ( "; - xp.display ( out , " " , 5 , _p.get_point_display_limit() ); - out << " )" << std::endl << std::endl; - out << "bb_eval (before+VNS only) objective_value" - << std::endl << std::endl; - } - - // save parameters that are going to be modified: - // ---------------------------------------------- - std::string old_display_degree; - _p.out().get_display_degree ( old_display_degree ); - - NOMAD::model_params_type old_mp; - _p.get_model_parameters ( old_mp ); - - bool old_ses = _p.get_sgte_eval_sort(); - bool old_sif = _p.get_stop_if_feasible(); - int old_hs = _p.get_halton_seed(); - int old_max_time = _p.get_max_time(); - int old_max_mesh_index = _p.get_max_mesh_index(); - int old_max_bbe = _p.get_max_bb_eval(); - int old_max_eval = _p.get_max_eval(); - int old_max_sgte_eval = _p.get_max_sgte_eval(); - int old_max_it = _p.get_max_iterations(); - int old_max_cfi = _p.get_max_consecutive_failed_iterations(); - int old_LH_p0 = _p.get_LH_search_p0(); - int old_LH_pi = _p.get_LH_search_pi(); - bool old_opp_LH = _p.get_opportunistic_LH(); - bool old_CS = _p.get_cache_search(); - bool old_opp_CS = _p.get_opportunistic_cache_search(); - int old_max_sbe = _p.get_max_sim_bb_eval(); - NOMAD::Double old_sst = _p.get_stat_sum_target(); - NOMAD::Double old_lct = _p.get_L_curve_target(); - NOMAD::Double old_trigger = _p.get_VNS_trigger(); - NOMAD::Point old_ft = _p.get_f_target(); - const std::list<std::string> old_ds = _p.get_display_stats(); - const std::list<std::string> old_stats_file = _p.get_stats_file(); - const std::string old_stats_file_name = _p.get_stats_file_name(); - const std::string old_sol_file = _p.get_solution_file(); - const std::string old_his_file = _p.get_history_file(); - bool old_uce = _p.get_user_calls_enabled(); - bool old_epe = _p.get_extended_poll_enabled(); - const std::vector<NOMAD::bb_output_type> old_bbot = _p.get_bb_output_type(); - - - - // save list of starting points: - std::string x0_cache_file = _p.get_x0_cache_file(); - std::vector<NOMAD::Point *> x0s; - { - const std::vector<NOMAD::Point *> & x0s_tmp = _p.get_x0s(); - size_t nx0 = x0s_tmp.size() , k; - for ( k = 0 ; k < nx0 ; ++k ) - x0s.push_back ( new Point ( *x0s_tmp[k] ) ); - } - - // modify parameters: - // ------------------ - if (display_degree == NOMAD::FULL_DISPLAY) - _p.set_DISPLAY_DEGREE(NOMAD::NORMAL_DISPLAY); - else if (display_degree == NOMAD::NORMAL_DISPLAY) - _p.set_DISPLAY_DEGREE(NOMAD::MINIMAL_DISPLAY); - else - _p.set_DISPLAY_DEGREE(display_degree); - - - _p.set_HALTON_SEED ( NOMAD::Mesh::get_max_halton_index() ); - _p.set_SOLUTION_FILE ( "" ); - _p.set_LH_SEARCH ( 0 , 0 ); - _p.set_VNS_SEARCH ( false ); - _p.set_CACHE_SEARCH ( false ); - _p.set_MAX_ITERATIONS ( -1 ); - _p.set_MAX_CONSECUTIVE_FAILED_ITERATIONS ( -1 ); - _p.reset_X0(); - _p.reset_stats_file(); - - - if ( has_sgte ) { - _p.set_OPT_ONLY_SGTE ( true ); - _p.set_MODEL_SEARCH ( NOMAD::NO_MODEL ); - _p.set_MODEL_EVAL_SORT ( NOMAD::NO_MODEL ); - } - - _p.set_USER_CALLS_ENABLED ( false ); - _p.set_EXTENDED_POLL_ENABLED ( false ); - - // DISPLAY_STATS: - { - if ( has_sgte ) - _p.set_DISPLAY_STATS ( NOMAD::itos(sgte_eval) + "+SGTE OBJ (VNS--surrogate)" ); - else - { - std::list<std::string> ds = old_ds; - std::list<std::string>::iterator it = ds.begin(); - std::list<std::string>::const_iterator end = ds.end(); - std::string s_bbe = NOMAD::itos(bbe) + "+"; - while ( it != end ) - { - if ( *it == "BBE" ) - ds.insert ( it , s_bbe ); - ++it; - } - ds.push_back ( " (VNS)" ); - _p.set_DISPLAY_STATS ( ds ); - } - } - - // STATS_FILE: - { - std::list<std::string> sf = old_stats_file; - std::list<std::string>::iterator it = sf.begin(); - std::list<std::string>::const_iterator end = sf.end(); - std::string s_bbe = NOMAD::itos(bbe) + "+"; - while ( it != end ) - { - if ( *it == "BBE" ) - sf.insert ( it , s_bbe ); - ++it; - } - sf.push_back ( " (VNS)" ); - _p.set_STATS_FILE ( old_stats_file_name , sf ); - } - - - // mesh: - _p.set_MAX_MESH_INDEX ( (mesh_index > initial_mesh_index) ? - mesh_index : initial_mesh_index); - - // X0: - _p.set_EXTERN_SIGNATURE ( signature ); - _p.set_X0 ( xp ); - - // MAX_BB_EVAL: - if ( old_max_bbe < 0 ) - _p.set_MAX_BB_EVAL ( 100 * n ); - else - _p.set_MAX_BB_EVAL ( old_max_bbe - bbe ); - - // MAX_SGTE_EVAL: - if ( old_max_sgte_eval > 0 ) - _p.set_MAX_SGTE_EVAL ( old_max_sgte_eval - sgte_eval ); - - // MAX_EVAL: - if ( old_max_eval > 0 ) - _p.set_MAX_EVAL ( old_max_eval - stats.get_eval() ); - - // MAX_SIM_BB_EVAL: - if ( old_max_sbe > 0 ) - _p.set_MAX_SIM_BB_EVAL ( old_max_sbe - stats.get_sim_bb_eval() ); - - // STAT_SUM_TARGET: - if ( old_sst.is_defined() ) - _p.set_STAT_SUM_TARGET ( old_sst - stats.get_stat_sum() ); - - // MAX_TIME: - if ( old_max_time > 0 ) - _p.set_MAX_TIME ( old_max_time - stats.get_real_time() ); - - // L_CURVE_TARGET: - if ( !has_sgte ) - _p.set_L_CURVE_TARGET ( best_f ); - - // F_TARGET and STOP_IF_FEASIBLE: - if ( has_sgte ) { - _p.reset_f_target(); - _p.set_STOP_IF_FEASIBLE ( false ); - } - - // check the parameters: - _p.check ( false , // remove_history_file = false - false , // remove_solution_file = false - false ); // remove_stats_file = false - - // Evaluator_Control: - NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); - - // descent: run MADS: - // ------------------ - NOMAD::Mads VNS_mads ( _p , - ev_control.get_evaluator () , - mads.get_extended_poll () , - &ev_control.get_cache () , - &ev_control.get_sgte_cache() ); - - NOMAD::Mads::set_flag_reset_mesh ( false ); - NOMAD::Mads::set_flag_reset_barriers ( true ); - - NOMAD::stop_type st = VNS_mads.run(); - - NOMAD::Mads::set_flag_reset_mesh ( true ); - - // update stats: - { - const NOMAD::Stats & VNS_stats = VNS_mads.get_stats(); - stats.update ( VNS_stats , true ); // for_search = true - stats.add_VNS_bb_eval ( VNS_stats.get_bb_eval () ); - stats.add_VNS_sgte_eval ( VNS_stats.get_sgte_eval() ); - } - - // check MADS stopping criteria: - if ( st == NOMAD::CTRL_C || - st == NOMAD::ERROR || - st == NOMAD::UNKNOWN_STOP_REASON || - st == NOMAD::FEAS_REACHED || - st == NOMAD::MAX_CACHE_MEMORY_REACHED || - st == NOMAD::STAT_SUM_TARGET_REACHED || - st == NOMAD::MAX_SGTE_EVAL_REACHED || - st == NOMAD::F_TARGET_REACHED || - st == NOMAD::MAX_SIM_BB_EVAL_REACHED || - st == NOMAD::MAX_TIME_REACHED || - (st == NOMAD::MAX_BB_EVAL_REACHED && old_max_bbe > 0 ) ) { - stop_reason = st; - stop = true; - } - - // Pareto front: - NOMAD::Pareto_Front * pareto_front = mads.get_pareto_front(); - - // restore starting points: - { - _p.reset_X0(); - size_t nx0 = x0s.size(); - - if ( nx0 > 0 ) { - for ( size_t k = 0 ; k < nx0 ; ++k ) { - _p.set_X0 ( *x0s[k] ); - delete x0s[k]; - } - } - else if ( !x0_cache_file.empty() ) - _p.set_X0 ( x0_cache_file ); - } - - // restore other saved parameters: - _p.set_model_parameters ( old_mp ); - _p.set_USER_CALLS_ENABLED ( old_uce ); - _p.set_EXTENDED_POLL_ENABLED ( old_epe ); - _p.set_VNS_SEARCH ( old_trigger ); - _p.set_F_TARGET ( old_ft ); - _p.set_STOP_IF_FEASIBLE ( old_sif ); - _p.set_L_CURVE_TARGET ( old_lct ); - _p.set_DISPLAY_DEGREE ( old_display_degree ); - _p.set_DISPLAY_STATS ( old_ds ); - _p.set_STATS_FILE ( old_stats_file_name , old_stats_file ); - _p.set_SOLUTION_FILE ( old_sol_file ); - _p.set_MAX_BB_EVAL ( old_max_bbe ); - _p.set_MAX_EVAL ( old_max_eval ); - _p.set_MAX_SGTE_EVAL ( old_max_sgte_eval ); - _p.set_MAX_ITERATIONS ( old_max_it ); - _p.set_MAX_CONSECUTIVE_FAILED_ITERATIONS ( old_max_cfi ); - _p.set_STAT_SUM_TARGET ( old_sst ); - _p.set_LH_SEARCH ( old_LH_p0 , old_LH_pi ); - _p.set_OPPORTUNISTIC_LH ( old_opp_LH ); - _p.set_CACHE_SEARCH ( old_CS ); - _p.set_OPPORTUNISTIC_CACHE_SEARCH ( old_opp_CS ); - _p.set_MAX_SIM_BB_EVAL ( old_max_sbe ); - _p.set_MAX_MESH_INDEX ( old_max_mesh_index ); - _p.set_HALTON_SEED ( old_hs ); - _p.set_MAX_TIME ( old_max_time ); - _p.set_SGTE_EVAL_SORT ( old_ses ); - _p.set_OPT_ONLY_SGTE ( opt_only_sgte ); - _p.set_BB_OUTPUT_TYPE ( old_bbot ); - - - - _p.check ( false , // remove_history_file = false - false , // remove_solution_file = false - false ); // remove_stats_file = false - - // restore mesh index: - NOMAD::Mesh::set_mesh_index ( mesh_index ); - - // surrogate evaluations: perform only one true evaluation: - if ( has_sgte && !opt_only_sgte ) - { - - if ( !stop ) - { - - // remember old best surrogates incumbents: - const NOMAD::Eval_Point * old_sgte_bf = sgte_barrier.get_best_feasible (); - const NOMAD::Eval_Point * old_sgte_bi = sgte_barrier.get_best_infeasible(); - - // update the surrogate barrier - // (no need to invoke Evaluator_Control::process_barrier_points() here - // since only surrogate evaluations have been made): - sgte_barrier.insert ( VNS_mads.get_sgte_barrier() ); - NOMAD::success_type sgte_succ = sgte_barrier.get_success(); - sgte_barrier.update_and_reset_success(); - - // we generate only a true trial point if the - // surrogates improved the surrogate barrier: - if ( sgte_succ != NOMAD::UNSUCCESSFUL ) - { - - // choose the best surrogate point(s) where to evaluate the true function: - const NOMAD::Eval_Point * sgte_bf = sgte_barrier.get_best_feasible (); - const NOMAD::Eval_Point * sgte_bi = sgte_barrier.get_best_infeasible(); - - std::list<const NOMAD::Eval_Point *> candidates; - - if ( sgte_bf && ( !x_feas || sgte_bf != old_sgte_bf ) ) - candidates.push_back ( sgte_bf ); - - if ( sgte_bi && sgte_bi != old_sgte_bi ) - candidates.push_back ( sgte_bi ); - - // generate the new trial points: - NOMAD::Eval_Point * sk; - std::list<const NOMAD::Eval_Point *>::const_iterator - it , end = candidates.end(); - for ( it = candidates.begin() ; it != end ; ++it ) - { - - // display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - out << std::endl << "VNS surrogate candidate: " - << **it << std::endl; - - sk = new NOMAD::Eval_Point; - sk->set ( n , _p.get_bb_nb_outputs() ); - sk->set_signature ( signature ); - sk->set_mesh_index ( &mesh_index ); - sk->Point::operator = ( **it ); - - // add the new point to the list of search trial points: - ev_control.add_eval_point ( sk , - display_degree , - _p.get_snap_to_bounds() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() , - NOMAD::Double() ); - } - - // eval_list_of_points: - // -------------------- - success = NOMAD::UNSUCCESSFUL; - new_feas_inc = new_infeas_inc = NULL; - - ev_control.eval_list_of_points ( _type , - true_barrier , - sgte_barrier , - pareto_front , - stop , - stop_reason , - new_feas_inc , - new_infeas_inc , - success ); - - // number of search points (0 or 1 or 2): - nb_search_pts = static_cast<int> ( candidates.size() ); - } - } - } - - // true evaluations (or surrogate evaluations if opt_only_sgte==true): - else - { - - // for the update of new_feas_inc and new_infeas_inc (1/2): - const NOMAD::Eval_Point * old_feasible_incumbent = - active_barrier.get_best_feasible(); - const NOMAD::Eval_Point * old_infeasible_incumbent = - active_barrier.get_best_infeasible(); - - // update barriers and process VNS search points: - NOMAD::success_type sgte_succ - = ev_control.process_barrier_points ( sgte_barrier , - VNS_mads.get_sgte_barrier() , - pareto_front , - display_degree , - NOMAD::VNS_SEARCH ); - NOMAD::success_type true_succ - = ev_control.process_barrier_points ( true_barrier , - VNS_mads.get_true_barrier() , - pareto_front , - display_degree , - NOMAD::VNS_SEARCH ); - - // update of new_feas_inc and new_infeas_inc (2/2): - const NOMAD::Eval_Point * bf = active_barrier.get_best_feasible (); - const NOMAD::Eval_Point * bi = active_barrier.get_best_infeasible(); - if ( bf && bf != old_feasible_incumbent ) - new_feas_inc = bf; - - if ( bi && bi != old_infeasible_incumbent ) - { - new_infeas_inc = bi; - // check the PEB constraints: if we have a new best infeasible - // incumbent from another infeasible incumbent - if ( _p.get_barrier_type() == NOMAD::PEB_P ) - ( ( _p.get_opt_only_sgte() ) ? sgte_barrier : true_barrier ).check_PEB_constraints ( *new_infeas_inc , display_degree==NOMAD::FULL_DISPLAY ); - } - - // number of search points and success: - if ( opt_only_sgte ) - { - nb_search_pts = VNS_mads.get_stats().get_sgte_eval(); - success = sgte_succ; - } - else - { - nb_search_pts = VNS_mads.get_stats().get_eval(); - success = true_succ; - } - - // solution file: - if ( bf ) - ev_control.write_solution_file ( *bf ); - - } - - // update _nb_performed: - if ( mesh_index > 0 ) - ++_nb_performed [ mesh_index ]; - - // final display: - if ( display_degree == NOMAD::FULL_DISPLAY ) - { - std::ostringstream oss; - oss << "end of VNS search (" << success << ")"; - out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; - } + new_feas_inc = new_infeas_inc = NULL; + nb_search_pts = 0; + success = NOMAD::UNSUCCESSFUL; + count_search = !stop; + + if ( stop ) + return; + + // initial display: + const NOMAD::Display & out = _p.out(); + NOMAD::dd_type display_degree = out.get_search_dd(); + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << NOMAD::VNS_SEARCH; + out << std::endl << NOMAD::open_block ( oss.str() ) << std::endl; + } + + bool opt_only_sgte = _p.get_opt_only_sgte(); + + // the barriers: + NOMAD::Barrier & true_barrier = mads.get_true_barrier(); + NOMAD::Barrier & sgte_barrier = mads.get_sgte_barrier(); + const NOMAD::Barrier & active_barrier = mads.get_active_barrier(); + + // point x: + NOMAD::Double best_f; + bool x_feas = true; + const NOMAD::Eval_Point * x = active_barrier.get_best_feasible(); + if ( x ) + best_f = x->get_f(); + else + { + x = active_barrier.get_best_infeasible(); + x_feas = false; + } + + if ( !x ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out.close_block ( "end of VNS search (no incumbent)" ); + return; + } + + // update _k and _old_x: + if ( x == _old_x ) + { + ++_k; + if ( _k > _k_max ) + _k_max = _k; + } + else + _k = 1; + + _old_x = x; + + // get the signature: + NOMAD::Signature * signature = x->get_signature(); + if ( !signature ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out.close_block ( "end of VNS search (no signature)" ); + return; + } + + int n = signature->get_n(); + if ( n != x->size() ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out.close_block ( "end of VNS search (incompatible signature)" ); + return; + } + + // shaking: get ONE direction from the signature: + NOMAD::Direction dir; + + signature->get_one_direction ( dir , _k - 1); + + + // shaking: construct x': + NOMAD::Point xp = *x + dir; + + // shaking: the perturbation is tried twice with dir and -dir + // (in case x == x + dir after snapping) + for ( int nbt = 0 ; nbt < 2 ; ++nbt ) + { + + // treat xp: periodic variables or bounds: + if ( _p.has_periodic_variables() ) + { + NOMAD::Direction * tmp_dir = NULL; + signature->treat_periodic_variables ( xp , NULL , tmp_dir ); + } + else + signature->snap_to_bounds ( xp , NULL ); + + if ( xp == *x ) + { + + // no third try: the search fails + if ( nbt == 1 ) + { + if ( display_degree == NOMAD::FULL_DISPLAY ) + out.close_block ( "end of VNS search (shaking failed)" ); + return; + } + + // 2nd try (-dir instead of dir): + xp = *x - dir; + } + } + + // Current mesh indices + const NOMAD::Point old_mesh_indices = signature->get_mesh()->get_mesh_indices ( ); + const NOMAD::Point old_delta_min = signature->get_mesh()->get_min_mesh_size(); + + + // stats: + NOMAD::Stats & stats = mads.get_stats(); + + // current number of blackbox evaluations: + int bbe = stats.get_bb_eval(); + int blk_eva = stats.get_block_eval(); + int sgte_eval = stats.get_sgte_eval(); + int mads_iterations = stats.get_iterations(); + bool has_sgte = _p.has_sgte(); + + // displays: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + out << " it = " << mads_iterations << std::endl + << " bbe = " << bbe << std::endl + << " blk_eva = " << blk_eva << std::endl; + if ( has_sgte ) + out << " sgte_eval = " << sgte_eval << std::endl; + out << "mesh_indices = ( " << old_mesh_indices << " ) " << std::endl + << " k = " << _k << std::endl + << " kmax = " << _k_max << std::endl + << " x = ( "; + x->Point::display ( out , " " , 5 , _p.get_point_display_limit() ); + out << " ) f=" << x->get_f() << " h=" << x->get_h() << std::endl + << " dir = ( "; + dir.Point::display ( out , " " , 5 , _p.get_point_display_limit() ); + out << " ) |dir|="; + NOMAD::Double norm = dir.norm(); + out << norm << std::endl; + out << " xp = ( "; + xp.display ( out , " " , 5 , _p.get_point_display_limit() ); + out << " )" << std::endl << std::endl; + out << "bb_eval (before+VNS only) objective_value" + << std::endl << std::endl; + } + + // save parameters that are going to be modified: + // ---------------------------------------------- + std::string old_display_degree; + _p.out().get_display_degree ( old_display_degree ); + + NOMAD::model_params_type old_mp; + _p.get_model_parameters ( old_mp ); + + bool old_ses = _p.get_sgte_eval_sort(); + bool old_sif = _p.get_stop_if_feasible(); + int old_max_time = _p.get_max_time(); + int old_max_bbe = _p.get_max_bb_eval(); + int old_max_eval = _p.get_max_eval(); + int old_max_sgte_eval = _p.get_max_sgte_eval(); + int old_max_it = _p.get_max_iterations(); + int old_max_cfi = _p.get_max_consecutive_failed_iterations(); + int old_LH_p0 = _p.get_LH_search_p0(); + int old_LH_pi = _p.get_LH_search_pi(); + bool old_opp_LH = _p.get_opportunistic_LH(); + bool old_CS = _p.get_cache_search(); + bool old_opp_CS = _p.get_opportunistic_cache_search(); + int old_max_sbe = _p.get_max_sim_bb_eval(); + NOMAD::Double old_sst = _p.get_stat_sum_target(); + NOMAD::Double old_lct = _p.get_L_curve_target(); + NOMAD::Double old_trigger = _p.get_VNS_trigger(); + NOMAD::Point old_ft = _p.get_f_target(); + const std::list<std::string> old_ds = _p.get_display_stats(); + const std::list<std::string> old_stats_file = _p.get_stats_file(); + const std::string old_stats_file_name = _p.get_stats_file_name(); + const std::string old_sol_file = _p.get_solution_file(); + const std::string old_his_file = _p.get_history_file(); + bool old_uce = _p.get_user_calls_enabled(); + bool old_epe = _p.get_extended_poll_enabled(); + const std::vector<NOMAD::bb_output_type> old_bbot = _p.get_bb_output_type(); + + // save list of starting points: + std::string x0_cache_file = _p.get_x0_cache_file(); + std::vector<NOMAD::Point *> x0s; + { + const std::vector<NOMAD::Point *> & x0s_tmp = _p.get_x0s(); + size_t nx0 = x0s_tmp.size() , k; + for ( k = 0 ; k < nx0 ; ++k ) + x0s.push_back ( new Point ( *x0s_tmp[k] ) ); + } + + // modify parameters: + // ------------------ + _p.set_DISPLAY_DEGREE(NOMAD::NO_DISPLAY); + + _p.set_SOLUTION_FILE ( "" ); + _p.set_LH_SEARCH ( 0 , 0 ); + _p.set_VNS_SEARCH ( false ); + _p.set_CACHE_SEARCH ( false ); + _p.set_MAX_ITERATIONS ( -1 ); + _p.set_MAX_CONSECUTIVE_FAILED_ITERATIONS ( -1 ); + _p.reset_X0(); + _p.reset_stats_file(); + + + if ( has_sgte ) + { + _p.set_OPT_ONLY_SGTE ( true ); + _p.set_MODEL_SEARCH ( NOMAD::NO_MODEL ); + _p.set_MODEL_EVAL_SORT ( NOMAD::NO_MODEL ); + } + + _p.set_USER_CALLS_ENABLED ( false ); + _p.set_EXTENDED_POLL_ENABLED ( false ); + + // DISPLAY_STATS: + { + if ( has_sgte ) + _p.set_DISPLAY_STATS ( NOMAD::itos(sgte_eval) + "+SGTE OBJ (VNS--surrogate)" ); + else + { + std::list<std::string> ds = old_ds; + std::list<std::string>::iterator it = ds.begin(); + std::list<std::string>::const_iterator end = ds.end(); + std::string s_bbe = NOMAD::itos(bbe) + "+"; + std::string s_blk = NOMAD::itos(blk_eva) + "+"; + while ( it != end ) + { + if ( *it == "BBE" ) + ds.insert ( it , s_bbe ); + if ( *it == "BLK_EVA" ) + ds.insert ( it , s_blk ); + ++it; + } + ds.push_back ( " (VNS)" ); + _p.set_DISPLAY_STATS ( ds ); + } + } + + // STATS_FILE: + { + std::list<std::string> sf = old_stats_file; + std::list<std::string>::iterator it = sf.begin(); + std::list<std::string>::const_iterator end = sf.end(); + std::string s_bbe = NOMAD::itos(bbe) + "+"; + std::string s_blk = NOMAD::itos(blk_eva) + "+"; + while ( it != end ) + { + if ( *it == "BBE" ) + sf.insert ( it , s_bbe ); + if ( *it == "BLK_EVA" ) + sf.insert ( it , s_blk ); + ++it; + } + sf.push_back ( " (VNS)" ); + + _p.set_STATS_FILE( old_stats_file_name, sf); + } + + + // Mesh size at current mads iterate can be used as termination criterion for vns search. + // Mesh indices are reinitialized during p.check() + NOMAD::Point delta=signature->get_mesh()->get_delta ( ); + signature->get_mesh()->set_min_mesh_sizes( delta ); + + + // X0: + _p.set_EXTERN_SIGNATURE ( signature ); + _p.set_X0 ( xp ); + + // MAX_BB_EVAL: + if ( old_max_bbe < 0 ) + _p.set_MAX_BB_EVAL ( 100 * n ); + else + _p.set_MAX_BB_EVAL ( old_max_bbe - bbe ); + + // MAX_SGTE_EVAL: + if ( old_max_sgte_eval > 0 ) + _p.set_MAX_SGTE_EVAL ( old_max_sgte_eval - sgte_eval ); + + // MAX_EVAL: + if ( old_max_eval > 0 ) + _p.set_MAX_EVAL ( old_max_eval - stats.get_eval() ); + + // MAX_SIM_BB_EVAL: + if ( old_max_sbe > 0 ) + _p.set_MAX_SIM_BB_EVAL ( old_max_sbe - stats.get_sim_bb_eval() ); + + // STAT_SUM_TARGET: + if ( old_sst.is_defined() ) + _p.set_STAT_SUM_TARGET ( old_sst - stats.get_stat_sum() ); + + // MAX_TIME: + if ( old_max_time > 0 ) + _p.set_MAX_TIME ( old_max_time - stats.get_real_time() ); + + // L_CURVE_TARGET: + if ( !has_sgte ) + _p.set_L_CURVE_TARGET ( best_f ); + + // F_TARGET and STOP_IF_FEASIBLE: + if ( has_sgte ) + { + _p.reset_f_target(); + _p.set_STOP_IF_FEASIBLE ( false ); + } + + // check the parameters: + _p.check ( false , // remove_history_file = false + false , // remove_solution_file = false + false ); // remove_stats_file = false + + // Evaluator_Control: + NOMAD::Evaluator_Control & ev_control = mads.get_evaluator_control(); + + // descent: run MADS: + // ------------------ + NOMAD::Mads VNS_mads ( _p , + ev_control.get_evaluator () , + mads.get_extended_poll () , + &ev_control.get_cache () , + &ev_control.get_sgte_cache() ); + NOMAD::Mads::set_flag_reset_mesh ( false ); + NOMAD::Mads::set_flag_reset_barriers ( true ); + + NOMAD::stop_type st = VNS_mads.run(); + + NOMAD::Mads::set_flag_reset_mesh ( true ); + + // update stats: + { + const NOMAD::Stats & VNS_stats = VNS_mads.get_stats(); + stats.update ( VNS_stats , true ); // for_search = true + stats.add_VNS_bb_eval ( VNS_stats.get_bb_eval () ); + stats.add_VNS_sgte_eval ( VNS_stats.get_sgte_eval() ); + } + + // check MADS stopping criteria: + if ( st == NOMAD::CTRL_C || + st == NOMAD::ERROR || + st == NOMAD::UNKNOWN_STOP_REASON || + st == NOMAD::FEAS_REACHED || + st == NOMAD::MAX_CACHE_MEMORY_REACHED || + st == NOMAD::STAT_SUM_TARGET_REACHED || + st == NOMAD::MAX_SGTE_EVAL_REACHED || + st == NOMAD::F_TARGET_REACHED || + st == NOMAD::MAX_SIM_BB_EVAL_REACHED || + st == NOMAD::MAX_TIME_REACHED || + (st == NOMAD::MAX_BB_EVAL_REACHED && old_max_bbe > 0 ) ) + { + stop_reason = st; + stop = true; + } + + // Pareto front: + NOMAD::Pareto_Front * pareto_front = mads.get_pareto_front(); + + // restore starting points: + { + _p.reset_X0(); + size_t nx0 = x0s.size(); + + if ( nx0 > 0 ) + { + + for ( size_t k = 0 ; k < nx0 ; ++k ) + { + _p.set_X0 ( *x0s[k] ); + delete x0s[k]; + } + } + else if ( !x0_cache_file.empty() ) + _p.set_X0 ( x0_cache_file ); + } + + // restore other saved parameters: + _p.set_model_parameters ( old_mp ); + _p.set_USER_CALLS_ENABLED ( old_uce ); + _p.set_EXTENDED_POLL_ENABLED ( old_epe ); + _p.set_VNS_SEARCH ( old_trigger ); + _p.set_F_TARGET ( old_ft ); + _p.set_STOP_IF_FEASIBLE ( old_sif ); + _p.set_L_CURVE_TARGET ( old_lct ); + _p.set_DISPLAY_DEGREE ( old_display_degree ); + _p.set_DISPLAY_STATS ( old_ds ); + _p.set_STATS_FILE ( old_stats_file_name , old_stats_file ); + _p.set_SOLUTION_FILE ( old_sol_file ); + _p.set_MAX_BB_EVAL ( old_max_bbe ); + _p.set_MAX_EVAL ( old_max_eval ); + _p.set_MAX_SGTE_EVAL ( old_max_sgte_eval ); + _p.set_MAX_ITERATIONS ( old_max_it ); + _p.set_MAX_CONSECUTIVE_FAILED_ITERATIONS ( old_max_cfi ); + _p.set_STAT_SUM_TARGET ( old_sst ); + _p.set_LH_SEARCH ( old_LH_p0 , old_LH_pi ); + _p.set_OPPORTUNISTIC_LH ( old_opp_LH ); + _p.set_CACHE_SEARCH ( old_CS ); + _p.set_OPPORTUNISTIC_CACHE_SEARCH ( old_opp_CS ); + _p.set_MAX_SIM_BB_EVAL ( old_max_sbe ); + _p.set_MAX_TIME ( old_max_time ); + _p.set_SGTE_EVAL_SORT ( old_ses ); + _p.set_OPT_ONLY_SGTE ( opt_only_sgte ); + _p.set_BB_OUTPUT_TYPE ( old_bbot ); + + + _p.check ( false , // remove_history_file = false + false , // remove_solution_file = false + false ); // remove_stats_file = false + + // restore min mesh sizes and mesh indices + signature->get_mesh()->set_min_mesh_sizes( old_delta_min ); + signature->get_mesh()->set_mesh_indices( old_mesh_indices ); // Needed because mesh indices reinitialized during p.check() + + + // surrogate evaluations: perform only one true evaluation: + if ( has_sgte && !opt_only_sgte ) + { + + if ( !stop ) + { + + // remember old best surrogates incumbents: + const NOMAD::Eval_Point * old_sgte_bf = sgte_barrier.get_best_feasible (); + const NOMAD::Eval_Point * old_sgte_bi = sgte_barrier.get_best_infeasible(); + + // update the surrogate barrier + // (no need to invoke Evaluator_Control::process_barrier_points() here + // since only surrogate evaluations have been made): + sgte_barrier.insert ( VNS_mads.get_sgte_barrier() ); + NOMAD::success_type sgte_succ = sgte_barrier.get_success(); + sgte_barrier.update_and_reset_success(); + + // we generate only a true trial point if the + // surrogates improved the surrogate barrier: + if ( sgte_succ != NOMAD::UNSUCCESSFUL ) + { + + // choose the best surrogate point(s) where to evaluate the true function: + const NOMAD::Eval_Point * sgte_bf = sgte_barrier.get_best_feasible (); + const NOMAD::Eval_Point * sgte_bi = sgte_barrier.get_best_infeasible(); + + std::list<const NOMAD::Eval_Point *> candidates; + + if ( sgte_bf && ( !x_feas || sgte_bf != old_sgte_bf ) ) + candidates.push_back ( sgte_bf ); + + if ( sgte_bi && sgte_bi != old_sgte_bi ) + candidates.push_back ( sgte_bi ); + + // generate the new trial points: + NOMAD::Eval_Point * sk; + std::list<const NOMAD::Eval_Point *>::const_iterator + it , end = candidates.end(); + for ( it = candidates.begin() ; it != end ; ++it ) + { + + // display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + out << std::endl << "VNS surrogate candidate: " + << **it << std::endl; + + sk = new NOMAD::Eval_Point; + sk->set ( n , _p.get_bb_nb_outputs() ); + sk->set_signature ( signature ); + sk->Point::operator = ( **it ); + + // add the new point to the list of search trial points: + ev_control.add_eval_point ( sk , + display_degree , + _p.get_snap_to_bounds() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() , + NOMAD::Double() ); + } + + // eval_list_of_points: + // -------------------- + success = NOMAD::UNSUCCESSFUL; + new_feas_inc = new_infeas_inc = NULL; + + ev_control.eval_list_of_points ( _type , + true_barrier , + sgte_barrier , + pareto_front , + stop , + stop_reason , + new_feas_inc , + new_infeas_inc , + success ); + + // number of search points (0 or 1 or 2): + nb_search_pts = static_cast<int> ( candidates.size() ); + } + } + } + + // true evaluations (or surrogate evaluations if opt_only_sgte==true): + else + { + + // for the update of new_feas_inc and new_infeas_inc (1/2): + const NOMAD::Eval_Point * old_feasible_incumbent = + active_barrier.get_best_feasible(); + const NOMAD::Eval_Point * old_infeasible_incumbent = + active_barrier.get_best_infeasible(); + + // update barriers and process VNS search points: + NOMAD::success_type sgte_succ + = ev_control.process_barrier_points ( sgte_barrier , + VNS_mads.get_sgte_barrier() , + pareto_front , + display_degree , + NOMAD::VNS_SEARCH ); + NOMAD::success_type true_succ + = ev_control.process_barrier_points ( true_barrier , + VNS_mads.get_true_barrier() , + pareto_front , + display_degree , + NOMAD::VNS_SEARCH ); + + // update of new_feas_inc and new_infeas_inc (2/2): + const NOMAD::Eval_Point * bf = active_barrier.get_best_feasible (); + const NOMAD::Eval_Point * bi = active_barrier.get_best_infeasible(); + if ( bf && bf != old_feasible_incumbent ) + new_feas_inc = bf; + + if ( bi && bi != old_infeasible_incumbent ) + { + new_infeas_inc = bi; + // check the PEB constraints: if we have a new best infeasible + // incumbent from another infeasible incumbent + // ( active_barrier.check_PEB_constraints() ): + if ( _p.get_barrier_type() == NOMAD::PEB_P ) + ( ( _p.get_opt_only_sgte() ) ? sgte_barrier : true_barrier ).check_PEB_constraints ( *new_infeas_inc , display_degree==NOMAD::FULL_DISPLAY ); + } + + // number of search points and success: + if ( opt_only_sgte ) + { + nb_search_pts = VNS_mads.get_stats().get_sgte_eval(); + success = sgte_succ; + } + else + { + nb_search_pts = VNS_mads.get_stats().get_eval(); + success = true_succ; + } + + // solution file: + if ( bf ) + ev_control.write_solution_file ( *bf ); + + } + + // final display: + if ( display_degree == NOMAD::FULL_DISPLAY ) + { + std::ostringstream oss; + oss << "end of VNS search (" << success << ")"; + out << std::endl << NOMAD::close_block ( oss.str() ) << std::endl; + } } diff --git a/src/VNS_Search.hpp b/src/VNS_Search.hpp index 26cead6..f74a3fe 100644 --- a/src/VNS_Search.hpp +++ b/src/VNS_Search.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -55,15 +55,8 @@ namespace NOMAD { int _k; ///< VNS neighborhood parameter. int _k_max; ///< Maximum value of \c _k. - int _halton_index; ///< Halton index used for shaking directions. const NOMAD::Eval_Point * _old_x; ///< Previous reference point (updates \c _k). - /// Search frequency. - /** - \c _nb_performed[ell] corresponds to the number of times that - the VNS search has been performed on a mesh of a size \c ell. - */ - int _nb_performed [NOMAD::L_LIMITS+1]; public: @@ -75,7 +68,6 @@ namespace NOMAD { : NOMAD::Search ( p , NOMAD::VNS_SEARCH ) , _k ( 1 ) , _k_max ( 1 ) , - _halton_index ( NOMAD::VNS_HALTON_INDEX_0 ) , _old_x ( NULL ) {} /// Destructor. @@ -104,16 +96,7 @@ namespace NOMAD { bool & count_search , const NOMAD::Eval_Point *& new_feas_inc , const NOMAD::Eval_Point *& new_infeas_inc ); - - /// Access to the search frequency. - /** - \param ell The mesh index -- \b IN. - \return Number of times that the VNS search has been performed on a given mesh. - */ - int get_nb_performed ( int ell ) const - { - return ( ell < 0 ) ? 0 : _nb_performed[ell]; - } + }; } diff --git a/src/Variable_Group.cpp b/src/Variable_Group.cpp index f00a7d6..c177fec 100644 --- a/src/Variable_Group.cpp +++ b/src/Variable_Group.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -51,160 +51,105 @@ bool NOMAD::Variable_Group::check std::vector<bool> * in_group , bool & mod ) { - - // initial checks: - if ( _var_indexes.empty() ) - return false; - bool binary = true; - bool categorical = false; - bool reset_dirs = false; - - // other checks + filling of vector in_group: - int n = static_cast<int>(bbit.size()); - std::set<int>::const_iterator end = _var_indexes.end() , - it = _var_indexes.begin(); - - while ( it != end ) - { - - if ( *it < 0 || *it >= n ) - return false; - - // check if the variable is fixed: - if ( fixed_vars[*it].is_defined() ) - { - reset_dirs = true; - _var_indexes.erase ( it++ ); - mod=true; - continue; - } - - if ( bbit[*it] == NOMAD::CATEGORICAL ) - { - categorical = true; - binary = false; - } - else - { - if ( categorical ) - return false; - if ( bbit[*it] != NOMAD::BINARY ) - binary = false; - } - - if ( in_group ) - (*in_group)[*it] = true; - - ++it; - } - - // modify the directions if a fixed variable has been removed: - if ( reset_dirs ) - { - - int halton_seed = _directions->get_halton_seed(); - std::set<NOMAD::direction_type> direction_types - = _directions->get_direction_types(); - std::set<NOMAD::direction_type> sec_poll_dir_types - = _directions->get_sec_poll_dir_types(); - - delete _directions; - - _directions = new Directions ( static_cast<int>(_var_indexes.size()) , - direction_types , - sec_poll_dir_types , - halton_seed , - _out ); - } - - if ( binary ) - _directions->set_binary(); - - else - { - - // we check here that NOMAD::GPS_BINARY is not in - // dir_types nor in sec_poll_dir_types: - const std::set<NOMAD::direction_type> & direction_types - = _directions->get_direction_types(); - const std::set<NOMAD::direction_type> & sec_poll_dir_types - = _directions->get_sec_poll_dir_types(); - - if ( direction_types.find ( NOMAD::GPS_BINARY ) != direction_types.end () || - sec_poll_dir_types.find ( NOMAD::GPS_BINARY ) != sec_poll_dir_types.end() ) - return false; - - if ( categorical ) - _directions->set_categorical(); - } - - return true; + // initial checks: + if ( _var_indexes.empty() ) + return false; + + bool binary = true; + bool categorical = false; + bool reset_dirs = false; + + // other checks + filling of vector in_group: + int n = static_cast<int>(bbit.size()); + std::set<int>::const_iterator end = _var_indexes.end() , + it = _var_indexes.begin(); + + while ( it != end ) + { + + if ( *it < 0 || *it >= n ) + return false; + + // check if the variable is fixed: + if ( fixed_vars[*it].is_defined() ) + { + reset_dirs = true; + _var_indexes.erase ( it++ ); + mod=true; + continue; + } + + if ( bbit[*it] == NOMAD::CATEGORICAL ) + { + categorical = true; + binary = false; + } + else + { + if ( categorical ) + return false; + if ( bbit[*it] != NOMAD::BINARY ) + binary = false; + } + + if ( in_group ) + (*in_group)[*it] = true; + + ++it; + } + + // modify the directions if a fixed variable has been removed: + if ( reset_dirs ) + { + + std::set<NOMAD::direction_type> direction_types = _directions->get_direction_types(); + std::set<NOMAD::direction_type> sec_poll_dir_types = _directions->get_sec_poll_dir_types(); + + delete _directions; + + _directions = new Directions ( static_cast<int>(_var_indexes.size()) , + direction_types , + sec_poll_dir_types , + _out ); + } + + if ( binary ) + _directions->set_binary(); + + else + { + + // we check here that NOMAD::GPS_BINARY is not in + // dir_types nor in sec_poll_dir_types: + const std::set<NOMAD::direction_type> & direction_types + = _directions->get_direction_types(); + const std::set<NOMAD::direction_type> & sec_poll_dir_types + = _directions->get_sec_poll_dir_types(); + + if ( direction_types.find ( NOMAD::GPS_BINARY ) != direction_types.end () || + sec_poll_dir_types.find ( NOMAD::GPS_BINARY ) != sec_poll_dir_types.end() ) + return false; + + if ( categorical ) + _directions->set_categorical(); + } + + return true; } /*---------------------------------------------------------*/ /* compute the directions */ /*---------------------------------------------------------*/ -void NOMAD::Variable_Group::get_directions ( std::list<NOMAD::Direction> & dirs , - NOMAD::poll_type poll , - const NOMAD::Point & poll_center , - int mesh_index , - const NOMAD::Direction & feas_success_dir , - const NOMAD::Direction & infeas_success_dir ) +void NOMAD::Variable_Group::get_directions ( std::list<NOMAD::Direction> & dirs , + NOMAD::poll_type poll , + const NOMAD::OrthogonalMesh & mesh ) { - - int nc = static_cast<int>(_var_indexes.size()); - - // vectors are of size nc : - // ------------------------ - if ( nc == poll_center.size() ) { - - _directions->compute ( dirs , - poll , - poll_center , - mesh_index , - -1 , - feas_success_dir , - infeas_success_dir ); - return; - } - - // construct vectors of size nc from vectors of size < nc : - // -------------------------------------------------------- - std::set<int>::const_iterator it ; - int i = 0; - - NOMAD::Point new_poll_center ( nc ); - NOMAD::Direction new_fsd , new_isd; - - if ( feas_success_dir.is_defined() ) - new_fsd = NOMAD::Direction ( nc , 0.0 , feas_success_dir.get_type() ); - - if ( infeas_success_dir.is_defined() ) - new_isd = NOMAD::Direction ( nc , 0.0 , infeas_success_dir.get_type() ); - - for ( it = _var_indexes.begin() ; it != _var_indexes.end() ; ++it ) - { - - new_poll_center[i] = poll_center[*it]; - - if ( feas_success_dir.is_defined() ) - new_fsd[i] = feas_success_dir [*it]; - - if ( infeas_success_dir.is_defined() ) - new_isd[i] = infeas_success_dir[*it]; - - ++i; - } - - _directions->compute ( dirs , - poll , - new_poll_center , - mesh_index , - -1 , - new_fsd , - new_isd ); - + + _directions->compute ( dirs , + poll , + mesh ); + return; } /*---------------------------------------------------------*/ @@ -212,24 +157,24 @@ void NOMAD::Variable_Group::get_directions ( std::list<NOMAD::Direction> & dirs /*---------------------------------------------------------*/ bool NOMAD::Variable_Group::operator < ( const NOMAD::Variable_Group & vg ) const { - // variable indexes: - if ( _var_indexes.size() < vg._var_indexes.size() ) - return true; - if ( _var_indexes.size() > vg._var_indexes.size() ) - return false; - - std::set<int>::const_iterator it1 , - it2 = vg._var_indexes.begin() , - end = _var_indexes.end(); - for ( it1 = _var_indexes.begin() ; it1 != end ; ++it1 , ++it2 ) { - if ( *it1 < *it2 ) - return true; - if ( *it1 > *it2 ) - return false; - } - - // directions: - return ( *_directions < *vg._directions ); + // variable indexes: + if ( _var_indexes.size() < vg._var_indexes.size() ) + return true; + if ( _var_indexes.size() > vg._var_indexes.size() ) + return false; + + std::set<int>::const_iterator it1 , + it2 = vg._var_indexes.begin() , + end = _var_indexes.end(); + for ( it1 = _var_indexes.begin() ; it1 != end ; ++it1 , ++it2 ) { + if ( *it1 < *it2 ) + return true; + if ( *it1 > *it2 ) + return false; + } + + // directions: + return ( *_directions < *vg._directions ); } /*---------------------------------------------------------*/ @@ -237,15 +182,15 @@ bool NOMAD::Variable_Group::operator < ( const NOMAD::Variable_Group & vg ) cons /*---------------------------------------------------------*/ void NOMAD::Variable_Group::display ( const NOMAD::Display & out ) const { - out << "indexes: { "; - std::set<int>::const_iterator end = _var_indexes.end(); - for ( std::set<int>::const_iterator it = _var_indexes.begin() ; it != end ; ++it ) - out << *it << " "; - out << "}" << std::endl; - if ( _directions->is_categorical() ) - out << "no directions (categorical variables)" << std::endl; - else - out << NOMAD::open_block ( "directions" ) - << *_directions - << NOMAD::close_block(); + out << "indexes: { "; + std::set<int>::const_iterator end = _var_indexes.end(); + for ( std::set<int>::const_iterator it = _var_indexes.begin() ; it != end ; ++it ) + out << *it << " "; + out << "}" << std::endl; + if ( _directions->is_categorical() ) + out << "no directions (categorical variables)" << std::endl; + else + out << NOMAD::open_block ( "directions" ) + << *_directions + << NOMAD::close_block(); } diff --git a/src/Variable_Group.hpp b/src/Variable_Group.hpp index 4e9725c..70f6054 100644 --- a/src/Variable_Group.hpp +++ b/src/Variable_Group.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,198 +34,180 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file Variable_Group.hpp - \brief Group of variables (headers) - \author Sebastien Le Digabel - \date 2010-04-XX - \see Variable_Group.cpp -*/ + \file Variable_Group.hpp + \brief Group of variables (headers) + \author Sebastien Le Digabel + \date 2010-04-XX + \see Variable_Group.cpp + */ #ifndef __VARIABLE_GROUP__ #define __VARIABLE_GROUP__ #include "Directions.hpp" namespace NOMAD { - - /// Group of variables. - /** - A group can be composed of integer / continous / binary variables - or only categorical variables. - */ - class Variable_Group { - - private: - - std::set<int> _var_indexes; ///< The variable indexes. - NOMAD::Directions * _directions; ///< The directions. - const NOMAD::Display & _out; ///< Display. - - /// Affectation operator. - /** - \param vg The right-hand side object -- \b IN. - */ - Variable_Group & operator = ( const Variable_Group & vg ); - - public: - - /// Constructor. - /** - \param var_indexes Variable indexes -- \b IN. - \param direction_types Direction types -- \b IN. - \param sec_poll_dir_types Direction types for secondary poll -- \b IN. - \param halton_seed Halton seed -- \b IN. - \param out Display -- \b IN. - */ - Variable_Group ( const std::set<int> & var_indexes , - const std::set<NOMAD::direction_type> & direction_types , - const std::set<NOMAD::direction_type> & sec_poll_dir_types , - int halton_seed , - const NOMAD::Display & out ) - : _var_indexes ( var_indexes ) , - _directions ( new Directions ( static_cast<int>(var_indexes.size()) , - direction_types , - sec_poll_dir_types , - halton_seed , - out ) ) , - _out ( out ) {} - - /// Copy constructor. - /** - \param vg The copied object -- \b IN. - */ - Variable_Group ( const Variable_Group & vg ) - : _var_indexes ( vg._var_indexes ) , - _directions ( new Directions ( *vg._directions ) ) , - _out ( vg._out ) {} - - /// Destructor. - virtual ~Variable_Group ( void ) { delete _directions; } - - /// Comparison operator. - /** - \param vg The right-hand side object -- \b IN. - \return A boolean equal to \c true if \c *this \c < \c vg. - */ - bool operator < ( const Variable_Group & vg ) const; - - /// Check the group. - /** - Also removes fixed variables from the group. - \param fixed_vars Fixed variables -- \b IN. - \param bbit Input types -- \b IN. - \param in_group A pointer to a vector indicating if variables - belong to a group (may be \c NULL) -- \b OUT. - \param mod True if the variable group has been modified -- \b out - \return A boolean equal to \c true if the verification is valid. - */ - bool check ( const NOMAD::Point & fixed_vars , - const std::vector<NOMAD::bb_input_type> & bbit , - std::vector<bool> * in_group , - bool & mod ); - /// Check if the directions are Ortho-MADS directions. + /// Group of variables. /** - \return A boolean equal to \c true if the directions are Ortho-MADS directions. - */ - bool is_orthomads ( void ) const { return _directions->is_orthomads(); } - - /// Access to the Halton seed. - /** - \return The Halton seed. - */ - int get_halton_seed ( void ) const { return _directions->get_halton_seed(); } - - /// Access to the variable indexes. - /** - \return The variable indexes. - */ - const std::set<int> & get_var_indexes ( void ) const { return _var_indexes; } - - /// Access to the direction types. - /** - \return The direction types. - */ - const std::set<NOMAD::direction_type> & get_direction_types ( void ) const - { - return _directions->get_direction_types(); - } - - /// Access to the direction types for the secondary poll. - /** - \return The direction types for the secondary poll. - */ - const std::set<NOMAD::direction_type> & get_sec_poll_dir_types ( void ) const - { - return _directions->get_sec_poll_dir_types(); - } - - /// Access to the directions. - /** - - The computed directions already include Delta^k_m. - \param dirs List of directions -- \b OUT. - \param poll Type of poll (primary or secondary) -- \b IN. - \param poll_center Poll center -- \b IN. - \param mesh_index Mesh index ell -- \b IN. - \param feas_success_dir Feasible success direction -- \b IN. - \param infeas_success_dir Infeasible success direction -- \b IN. - */ - void get_directions ( std::list<NOMAD::Direction> & dirs , - NOMAD::poll_type poll , - const NOMAD::Point & poll_center , - int mesh_index , - const NOMAD::Direction & feas_success_dir , - const NOMAD::Direction & infeas_success_dir ); - - - /// Access to one direction for a given mesh. - /** - Used for example in the VNS search. - \param dir The direction -- \b OUT. - \param mesh_index Mesh index ell -- \b IN. - \param halton_index Halton index; must be > 0 -- \b IN. - */ - bool get_one_direction ( NOMAD::Direction & dir , - int mesh_index , - int halton_index ) - { - return _directions->compute_one_direction ( dir , mesh_index , halton_index ); - } + A group can be composed of integer / continous / binary variables + or only categorical variables. + */ + class Variable_Group { + + private: + + std::set<int> _var_indexes; ///< The variable indexes. + NOMAD::Directions * _directions; ///< The directions. + const NOMAD::Display & _out; ///< Display. + + /// Affectation operator. + /** + \param vg The right-hand side object -- \b IN. + */ + Variable_Group & operator = ( const Variable_Group & vg ); + + public: + + /// Constructor. + /** + \param var_indexes Variable indexes -- \b IN. + \param direction_types Direction types -- \b IN. + \param sec_poll_dir_types Direction types for secondary poll -- \b IN. + \param out Display -- \b IN. + */ + Variable_Group ( const std::set<int> & var_indexes , + const std::set<NOMAD::direction_type> & direction_types , + const std::set<NOMAD::direction_type> & sec_poll_dir_types , + const NOMAD::Display & out ) + : _var_indexes ( var_indexes ), + _directions ( new Directions ( static_cast<int>(var_indexes.size()) , + direction_types , + sec_poll_dir_types , + out ) ) , + _out ( out ) {} + + /// Copy constructor. + /** + \param vg The copied object -- \b IN. + */ + Variable_Group ( const Variable_Group & vg ) + : _var_indexes ( vg._var_indexes ) , + _directions ( new Directions ( *vg._directions ) ) , + _out ( vg._out ) {} + + /// Destructor. + virtual ~Variable_Group ( void ) { delete _directions; } + + /// Comparison operator. + /** + \param vg The right-hand side object -- \b IN. + \return A boolean equal to \c true if \c *this \c < \c vg. + */ + bool operator < ( const Variable_Group & vg ) const; + + /// Check the group. + /** + Also removes fixed variables from the group. + \param fixed_vars Fixed variables -- \b IN. + \param bbit Input types -- \b IN. + \param in_group A pointer to a vector indicating if variables + belong to a group (may be \c NULL) -- \b OUT. + \param mod True if the variable group has been modified -- \b out + \return A boolean equal to \c true if the verification is valid. + */ + bool check ( const NOMAD::Point & fixed_vars , + const std::vector<NOMAD::bb_input_type> & bbit , + std::vector<bool> * in_group , + bool & mod ); + + /// Check if the directions are Ortho-MADS directions. + /** + \return A boolean equal to \c true if the directions are Ortho-MADS directions. + */ + bool is_orthomads ( void ) const { return _directions->is_orthomads(); } + + + /// Access to the variable indexes. + /** + \return The variable indexes. + */ + const std::set<int> & get_var_indexes ( void ) const { return _var_indexes; } + + /// Access to the direction types. + /** + \return The direction types. + */ + const std::set<NOMAD::direction_type> & get_direction_types ( void ) const + { + return _directions->get_direction_types(); + } + + /// Access to the direction types for the secondary poll. + /** + \return The direction types for the secondary poll. + */ + const std::set<NOMAD::direction_type> & get_sec_poll_dir_types ( void ) const + { + return _directions->get_sec_poll_dir_types(); + } + + /// Access to the directions. + /** + \param dirs List of directions -- \b OUT. + \param poll Type of poll (primary or secondary) -- \b IN. + \param mesh Mesh -- \b IN. + */ + void get_directions ( std::list<NOMAD::Direction> & dirs , + NOMAD::poll_type poll , + const NOMAD::OrthogonalMesh & mesh ); + + + /// Access to one direction for a given mesh. + /** + Used for example in the VNS search. + \param dir The direction -- \b OUT. + */ + bool get_one_direction ( NOMAD::Direction & dir ) + { + return _directions->compute_dir_on_unit_sphere( dir ); + } + + + /// Display. + /** + \param out The NOMAD::Display object -- \b IN. + */ + void display ( const NOMAD::Display & out ) const; + + /// Display. + /** + Uses the \c this->_out member as NOMAD::Display object. + */ + void display ( void ) const { display ( _out ); } + }; - /// Display. + /// Display a NOMAD::Variable_Group object. /** - \param out The NOMAD::Display object -- \b IN. - */ - void display ( const NOMAD::Display & out ) const; - - /// Display. - /** - Uses the \c this->_out member as NOMAD::Display object. - */ - void display ( void ) const { display ( _out ); } - }; - - /// Display a NOMAD::Variable_Group object. - /** \param out The NOMAD::Display object -- \b IN. \param vg The NOMAD::Variable_Group object to be displayed -- \b IN. \return The NOMAD::Display object. - */ - inline const NOMAD::Display & operator << ( const NOMAD::Display & out , - const NOMAD::Variable_Group & vg ) { - vg.display ( out ); - return out; - } - - /// Allow the comparison between two pointers to NOMAD::Variable_Group objects. - /** - Used with \c set<Variable_Group*,VG_Comp> in class NOMAD::Parameters. - */ - struct VG_Comp { - /// Comparison between two NOMAD::Variable_Group objects. - bool operator() ( const Variable_Group * vg1 , const Variable_Group * vg2 ) const { - return (*vg1 < *vg2); + */ + inline const NOMAD::Display & operator << ( const NOMAD::Display & out , + const NOMAD::Variable_Group & vg ) { + vg.display ( out ); + return out; } - }; + + /// Allow the comparison between two pointers to NOMAD::Variable_Group objects. + /** + Used with \c set<Variable_Group*,VG_Comp> in class NOMAD::Parameters. + */ + struct VG_Comp { + /// Comparison between two NOMAD::Variable_Group objects. + bool operator() ( const Variable_Group * vg1 , const Variable_Group * vg2 ) const { + return (*vg1 < *vg2); + } + }; } #endif diff --git a/src/XMesh.cpp b/src/XMesh.cpp new file mode 100644 index 0000000..926ddac --- /dev/null +++ b/src/XMesh.cpp @@ -0,0 +1,511 @@ +/*-------------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ +/* */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ +/* Charles Audet - Ecole Polytechnique, Montreal */ +/* Gilles Couture - Ecole Polytechnique, Montreal */ +/* John Dennis - Rice University, Houston */ +/* Sebastien Le Digabel - Ecole Polytechnique, Montreal */ +/* Christophe Tribes - Ecole Polytechnique, Montreal */ +/* */ +/* funded in part by AFOSR and Exxon Mobil */ +/* */ +/* Author: Sebastien Le Digabel */ +/* */ +/* Contact information: */ +/* Ecole Polytechnique de Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* phone : 1-514-340-6053 #6928 */ +/* fax : 1-514-340-5665 */ +/* */ +/* This program is free software: you can redistribute it and/or modify it under the */ +/* terms of the GNU Lesser General Public License as published by the Free Software */ +/* Foundation, either version 3 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 Lesser General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public License along */ +/* with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*-------------------------------------------------------------------------------------*/ +/** + \file XMesh.cpp + \brief Class for the MADS xmesh (implementation) + \author Christophe Tribes + \date 2014-07 + \see XMesh.hpp + */ +#include "XMesh.hpp" +#include <math.h> + + +/*-----------------------------------------------------------*/ +/* init the XMesh */ +/*-----------------------------------------------------------*/ +void NOMAD::XMesh::init ( ) +{ + bool chkMesh = _delta_min.is_defined(); + bool chkPoll = _Delta_min_is_defined; + _n = _delta_0.size(); + + + if ( !_Delta_0.is_complete() ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::XMesh::init(): Delta_0 has undefined values" ); + if ( _delta_0.size() != _Delta_0.size() ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::XMesh::init(): delta_0 and Delta_0 have different sizes" ); + + if ( !_delta_0.is_complete() ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::XMesh::init(): delta_0 has undefined values" ); + + if ( chkMesh && _delta_min.size() != _n ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::XMesh::init(): delta_0 and delta_min have different sizes" ); + + if ( chkPoll && _Delta_min.size() != _n ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::XMesh::init(): delta_0 and Delta_min have different sizes" ); + + if ( _limit_mesh_index >0 ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::XMesh::XMesh(): limit mesh index must be <=0 " ); + + + _r.resize( _n ); + _r_max.resize( _n ); + _r_min.resize( _n ); + + for ( int k = 0 ; k < _n ; ++k ) + { + _r[k]=0; + _r_max[k]=0; + _r_min[k]=0; + } + + +} + + +/*-----------------------------------------------------------*/ +/* Update the provided mesh indices (the Mesh is unchanged). */ +/*-----------------------------------------------------------*/ +void NOMAD::XMesh::update ( NOMAD::success_type success , NOMAD::Point & mesh_indices, const NOMAD::Direction *dir ) const +{ + + if ( mesh_indices.is_defined() ) + { + + if ( dir && dir->size() != mesh_indices.size() ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::XMesh::update(): mesh_indices and dir have different sizes" ); + + for (int i=0; i < mesh_indices.size() ; i++) + { + if ( success == NOMAD::FULL_SUCCESS ) + { + + if ( (*dir)[i] !=0.0) + mesh_indices[i] += _coarsening_step; + + if ( mesh_indices[i] > -NOMAD::XL_LIMITS ) + mesh_indices[i] = -NOMAD::XL_LIMITS; + } + else if ( success == NOMAD::UNSUCCESSFUL ) + mesh_indices[i] += _refining_step; + } + } +} + + + +/*-----------------------------------------------------------*/ +/* update the XMesh */ +/*-----------------------------------------------------------*/ +void NOMAD::XMesh::update ( NOMAD::success_type success , const NOMAD::Direction * dir) +{ + // defaults: + // full success: r^k_j = r^k_j + 1 if (dir_k != 0 and anistropic_mesh) and r^k_j remains the same if dir_k=0 + // failure : r^k_j = r^k_j - 1 + + + if ( dir && dir->size() != _n ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::XMesh::update(): delta_0 and dir have different sizes" ); + + + if ( success == NOMAD::FULL_SUCCESS ) + { + // Evaluate ||d||_inf + NOMAD::Double norm_inf=0; + NOMAD::Point delta=NOMAD::OrthogonalMesh::get_delta(); + + if ( _anisotropic_mesh ) + { + for (int i=0; i < _n; i++) + { + if ( dir && (*dir)[i].abs()/delta[i] > norm_inf ) + norm_inf=(*dir)[i].abs()/delta[i]; + } + } + else + norm_inf=-1; + + // Determine current max mesh index + NOMAD::Double max_index=NOMAD::XL_LIMITS; + for (int j=0; j < _n; j++) + if ( _r[j] > max_index ) + max_index=_r[j]; + + + // Update mesh indices for coordinates with |dir_j|>1/n_free_variables ||dir||_inf or mesh index >=-2 + for (int i=0; i < _n; i++) + { + if ( ! dir || (*dir)[i].abs()/delta[i] > norm_inf/_n_free_variables || _r[i] >=-2 ) + { + _r[i] += _coarsening_step; + + if (_r[i] > -NOMAD::XL_LIMITS ) + _r[i] = -NOMAD::XL_LIMITS; + + if ( _r[i] > _r_max[i] ) + _r_max[i] = _r[i]; + + } + } + + + // Udate mesh indices for coordinates with |dir_l| < 1/n_free_variables ||dir||_inf and mesh index < 2*max_mesh_index + for (int l=0; l < _n; l++) + { + if ( dir && _r[l] < -2 && (*dir)[l].abs()/delta[l] <= norm_inf/_n_free_variables && _r[l] < 2*max_index ) + _r[l]+= _coarsening_step; + } + + } + else if ( success == NOMAD::UNSUCCESSFUL ) + for (int i=0; i< _n; i++) + { + _r[i] += _refining_step; + + if ( _r[i] < _r_min[i] ) + _r_min[i] = _r[i]; + + } +} + + +/*-----------------------------------------------------------*/ +/* display */ +/*-----------------------------------------------------------*/ +void NOMAD::XMesh::display ( const NOMAD::Display & out ) const +{ + out << "n : " << _n << std::endl + << "tau : " << _update_basis << std::endl + << "poll coarsening exponent: " << _coarsening_step << std::endl + << "poll refining exponent : " << _refining_step << std::endl; + out << "minimal mesh size : "; + if ( _delta_min.is_defined() ) + out << "(" << _delta_min << " )" << std::endl; + else + out << "none"; + out << std::endl + << "minimal poll size : "; + if ( _Delta_min_is_defined ) + out << "( " << _Delta_min << " )" << std::endl; + else + out << "none"; + + out << std::endl << "initial poll size : "; + if (_Delta_0.is_defined()) + out <<"( " << _Delta_0 << " )" << std::endl; + else + out <<"( none )" << std::endl; + + out << std::endl << "initial mesh size : "; + + if ( _delta_0.is_defined() ) + out <<"( " << _delta_0 << " )" << std::endl; + else + out <<"( none )" << std::endl; + + out << std::endl; +} + + +/*----------------------------------------------------------*/ +/* check the stopping conditions on the minimal poll size */ +/* and on the minimal mesh size */ +/*----------------------------------------------------------*/ +void NOMAD::XMesh::check_min_mesh_sizes ( bool & stop , + NOMAD::stop_type & stop_reason ) const +{ + if ( stop ) + return; + + // Coarse mesh stopping criterion + stop=false; + + for (int i=0;i<_n;i++) + if ( _r[i] > -NOMAD::XL_LIMITS ) + { + stop = true; + break; + } + + if (stop) + { + stop_reason = NOMAD::XL_LIMITS_REACHED; + return; + } + + stop=true; + + // Fine mesh stopping criterion + // All mesh indices must < _limit_mesh_index to trigger this stopping criterion + for (int i=0;i<_n;i++) + { + if ( _r[i] >= _limit_mesh_index ) + { + stop = false; + break; + } + } + if (stop) + { + stop_reason = NOMAD::XL_LIMITS_REACHED; + return; + } + + // 2. Delta^k (poll size) tests: + if ( check_min_poll_size_criterion ( ) ) + { + stop = true; + stop_reason = NOMAD::DELTA_P_MIN_REACHED; + } + + // 3. delta^k (mesh size) tests: + if ( check_min_mesh_size_criterion ( ) ) + { + stop = true; + stop_reason = NOMAD::DELTA_M_MIN_REACHED; + } +} + +/*-----------------------------------------------------------*/ +/* check the minimal poll size (private) */ +/*-----------------------------------------------------------*/ +bool NOMAD::XMesh::check_min_poll_size_criterion ( ) const +{ + if ( !_Delta_min_is_defined ) + return false; + + NOMAD::Point Delta; + return get_Delta ( Delta ); +} + +/*-----------------------------------------------------------*/ +/* check the minimal mesh size (private) */ +/*-----------------------------------------------------------*/ +bool NOMAD::XMesh::check_min_mesh_size_criterion ( ) const +{ + if ( !_delta_min.is_defined() ) + return false; + + NOMAD::Point delta; + return get_delta ( delta ); +} + + +/*--------------------------------------------------------------*/ +/* get delta (mesh size parameter) */ +/* delta^k = delta^0 \tau ^min{0,2*r^k} */ +/*--------------------------------------------------------------*/ +/* the function also returns true if ALL delta[i] < delta_min */ +/*----------------------------------------------------------------*/ +bool NOMAD::XMesh::get_delta ( NOMAD::Point & delta ) const +{ + + delta.resize(_n); + + bool delta_min_is_defined=_delta_min.is_defined(); + + bool stop = true; + + // delta^k = power_of_beta * delta^0: + for ( int i = 0 ; i < _n ; ++i ) + { + NOMAD::Double power_of_beta + = pow ( _update_basis.value() , ( (_r[i] >= 0) ? 0 : 2*_r[i].value() ) ); + + delta[i] = _delta_0[i] * power_of_beta; + + if ( delta_min_is_defined && _delta_min[i].is_defined() && delta[i] >= _delta_min[i] ) + stop = false; + } + + return stop; +} + + +/*--------------------------------------------------------------*/ +/* get delta (mesh size parameter) */ +/* delta^k = delta^0 \tau ^min{0,2*r^k} */ +/*--------------------------------------------------------------*/ +NOMAD::Double NOMAD::XMesh::get_delta ( int i ) const +{ + + // delta^k = power_of_beta * delta^0: + NOMAD::Double power_of_beta = pow ( _update_basis.value() , ( (_r[i] >= 0) ? 0 : 2*_r[i].value() ) ); + + return _delta_0[i] * power_of_beta; + +} + + + +/*--------------------------------------------------------------*/ +/* get Delta (poll size parameter) */ +/* Delta^k = Delta^0 \tau ^{r^k} */ +/*--------------------------------------------------------------*/ +/* the function also returns true if all values are < Delta_min */ +/*----------------------------------------------------------------*/ +bool NOMAD::XMesh::get_Delta ( NOMAD::Point & Delta ) const +{ + + bool stop = true; + + Delta.resize(_n); + + // delta^k = power_of_tau * delta^0: + for ( int i = 0 ; i < _n ; ++i ) + { + Delta[i] = _Delta_0[i] * pow( _update_basis.value() , _r[i].value() ); + + if ( !_Delta_min_is_complete || Delta[i] >= _Delta_min[i] ) + stop = false; + + if ( _Delta_min_is_defined && _Delta_min[i].is_defined() && Delta[i] < _Delta_min[i] ) + Delta[i]=_Delta_min[i]; + + } + + return stop; +} + +/*--------------------------------------------------------------*/ +/* get Delta_i (poll size parameter) */ +/* Delta^k = Delta^0 \tau ^{r^k} */ +/*--------------------------------------------------------------*/ +/* the function returns Delta >= Delta_min */ +/*--------------------------------------------------------------*/ +NOMAD::Double NOMAD::XMesh::get_Delta ( int i ) const +{ + + NOMAD::Double Delta = _Delta_0[i] * pow( _update_basis.value() , _r[i].value() ); + + if ( _Delta_min_is_defined && _Delta_min[i].is_defined() && Delta < _Delta_min[i] ) + Delta=_Delta_min[i]; + + + return Delta; +} + + +bool NOMAD::XMesh::is_finest ( ) const +{ + + for ( int i = 0 ; i < _n ; ++i ) + { + if ( _r[i] > _r_min[i] ) + return false; + } + return true; +} + + +/*-----------------------------------------------------------*/ +/* set the mesh indices */ +/*-----------------------------------------------------------*/ +void NOMAD::XMesh::set_mesh_indices ( const NOMAD::Point & r ) +{ + + if ( r.size() != _n ) + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "NOMAD::XMesh::set_mesh_indices(): dimension of provided mesh indices must be consistent with their previous dimension" ); + + _r=r; + for ( int i = 0 ; i < _n ; ++i ) + { + if ( r[i] > _r_max[i] ) + _r_max[i] = r[i]; + if ( r[i] < _r_min[i] ) + _r_min[i] = r[i]; + } +} + + +/*-----------------------------------------------------------*/ +/* set the limit mesh index (min value for XMesh) */ +/*-----------------------------------------------------------*/ +void NOMAD::XMesh::set_limit_mesh_index ( int l ) +{ + _limit_mesh_index=l; +} + + + + +/*-----------------------------------------------------------*/ +/* scale and project on the mesh */ +/*-----------------------------------------------------------*/ +NOMAD::Double NOMAD::XMesh::scale_and_project(int i, const NOMAD::Double & l) const +{ + NOMAD::Double delta = get_delta( i ); + NOMAD::Double Delta = get_Delta( i ); + + + if ( i<=_n && delta.is_defined() && Delta.is_defined() ) + { + NOMAD::Double d = Delta / delta * l; + return d.NOMAD::Double::round()*delta; + } + else + throw NOMAD::Exception ( "XMesh.cpp" , __LINE__ , + "Mesh scaling and projection cannot be performed!" ); + + +} + + +NOMAD::Point NOMAD::XMesh::get_mesh_ratio_if_success ( void ) const +{ + + try + { + NOMAD::Point ratio( _n ); + for (int i=0 ; i < _n ; i++) + { + NOMAD::Double power_of_tau + = pow ( _update_basis.value() , ( (_r[i] >= 0) ? 0 : 2*_r[i].value() ) ); + + NOMAD::Double power_of_tau_if_success + = pow ( _update_basis.value() , ( (_r[i] + _coarsening_step >= 0) ? 0 : 2*(_r[i].value() + _coarsening_step) ) ); + + ratio[i] = power_of_tau_if_success/power_of_tau; + + } + + return ratio; + } + catch ( NOMAD::Double::Invalid_Value & ) + { + return NOMAD::Point( _n,-1 ); + } +} diff --git a/src/XMesh.hpp b/src/XMesh.hpp new file mode 100644 index 0000000..e29262c --- /dev/null +++ b/src/XMesh.hpp @@ -0,0 +1,307 @@ +/*-------------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ +/* */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ +/* Charles Audet - Ecole Polytechnique, Montreal */ +/* Gilles Couture - Ecole Polytechnique, Montreal */ +/* John Dennis - Rice University, Houston */ +/* Sebastien Le Digabel - Ecole Polytechnique, Montreal */ +/* Christophe Tribes - Ecole Polytechnique, Montreal */ +/* */ +/* funded in part by AFOSR and Exxon Mobil */ +/* */ +/* Author: Christophe Tribes */ +/* */ +/* Contact information: */ +/* Ecole Polytechnique de Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* phone : 1-514-340-6053 #6928 */ +/* fax : 1-514-340-5665 */ +/* */ +/* This program is free software: you can redistribute it and/or modify it under the */ +/* terms of the GNU Lesser General Public License as published by the Free Software */ +/* Foundation, either version 3 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 Lesser General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public License along */ +/* with this program. If not, see <http://www.gnu.org/licenses/>. */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*-------------------------------------------------------------------------------------*/ +/** + \file XMesh.hpp + \brief Class for the xmesh (extensible mesh) (headers) + \author Christophe Tribes + \date 2014-07 + \see XMesh.cpp + */ +#ifndef __XMESH__ +#define __XMESH__ + +#include "OrthogonalMesh.hpp" + +namespace NOMAD { + + /// Class for the MADS Xmesh. + /** + - The Xmesh in NOMAD is defined with the basic directions and the + mesh size parameter delta^k for each coordinate. + */ + + class XMesh : public NOMAD::OrthogonalMesh { + + /*--------------------------------------------------------------*/ + private: + + NOMAD::Point _r; // Mesh index per coordinate. + NOMAD::Point _r_min; + NOMAD::Point _r_max; + bool _anisotropic_mesh; + + + + /*--------------------------------------------------------------*/ + + /// Private affectation operator. + /** + \param m The right-hand side object -- \b IN. + */ + const XMesh & operator = ( const XMesh & m ); + + /// Check the minimal poll size criterion. + bool check_min_poll_size_criterion ( ) const; + + /// Check the minimal mesh size criterion. + bool check_min_mesh_size_criterion ( ) const; + + + /// Access to the mesh size parameter delta^k. + /** + \return delta The mesh size parameter delta^k -- \b OUT. + \param i The index of the mesh size + */ + NOMAD::Double get_delta ( int i ) const ; + + + /// Access to the poll size parameter Delta^k. + /** + \return Delta The poll size parameter Delta^k -- \b OUT. + \param i The index of the poll size + */ + NOMAD::Double get_Delta ( int i ) const ; + + void init ( ); + + public: + + /// Constructor. + /** + \param anistropic_mesh Use anisotropic mesh or not -- \b IN. + \param Delta_0 Initial poll size Delta^0 -- \b IN. + \param Delta_min Minimal poll size Delta^min (may be undefined) -- \b IN. + \param delta_min Minimal mesh size delta^min (may be undefined) -- \b IN. + \param poll_update_basis Poll update basis (b); default=2 -- \b IN. + \param poll_coarsening_step Poll coarsening step (w+); default=1 -- \b IN. + \param poll_refining_step Poll refining step (w-); default=-1 -- \b IN. + \param fixed_variables Fixed variables -- \b IN. + \param limit_min_mesh_index Limit mesh index (<0) -- \b IN. + */ + XMesh (bool anisotropic_mesh, + const NOMAD::Point & Delta_0 , + const NOMAD::Point & Delta_min , + const NOMAD::Point & delta_min , + const NOMAD::Point & fixed_variables, + NOMAD::Double poll_update_basis=2.0, + int poll_coarsening_step=1, + int poll_refining_step=-1 , + int limit_min_mesh_index=NOMAD::XL_LIMITS ) + : NOMAD::OrthogonalMesh ( Delta_0, + Delta_min, + delta_min, + fixed_variables, + poll_update_basis, + poll_coarsening_step, + poll_refining_step , + limit_min_mesh_index ), + _anisotropic_mesh ( anisotropic_mesh ){ init();} + + + + + /// Copy constructor. + /** + \param m The copied object -- \b IN. + */ + XMesh ( const XMesh & m ) + : OrthogonalMesh ( m ) , + _r ( m._r ), + _r_min ( m._r_min ), + _r_max ( m._r_max ), + _anisotropic_mesh ( m._anisotropic_mesh ){} + + /// Destructor. + ~XMesh ( void ) + { + _delta_0.clear(); + _Delta_0.clear(); + _delta_min.clear(); + _Delta_min.clear(); + } + + + /// Access to the mesh size parameter delta^k for earch coordinate. + /** + - It is a NOMAD::Point of size \c nc the number of free variables. + \param delta The mesh size parameter delta^k -- \b OUT. + -- \b optional (default = the current mesh index ell_k.) + \return A boolean equal to \c true if all values are + strictly inferior than the associated minimal + mesh size delta_min (stopping criterion MIN_MESH_SIZE). + */ + bool get_delta ( NOMAD::Point & delta ) const ; + + + /// Access to the largest mesh size for earch coordinate. + /** + \return delta_max + */ + NOMAD::Point get_delta_max ( void ) const { return _delta_0;} + + + /// Access to the poll size Delta^k for each coordinate. + /** + - It is a NOMAD::Point of size \c nc the number of free variables. + \param Delta The poll size parameter Delta^k -- \b OUT. + \return A boolean equal to \c true if all values are + strictly inferior than the associated minimal + poll size Delta_min + (stopping criterion MIN_POLL_SIZE). + */ + bool get_Delta ( NOMAD::Point & Delta) const ; + + + /// Update the provided mesh indices (the Mesh is unchanged). + /** + \param success Type of success of the iteration -- \b IN. + \param mesh_indices The mesh indices before and after the update -- \b IN/OUT. + \param dir The direction that is considered (opt) -- \b IN. + */ + void update ( NOMAD::success_type success , NOMAD::Point & mesh_indices, const NOMAD::Direction *dir=NULL ) const ; + + + /// Test if mesh finer than initial. + /** + \return True if mesh size is smaller than initial mesh size for all components; False otherwise. + */ + bool is_finer_than_initial (void) const {return true;} + + + + /// Update the XMesh (poll and mesh sizes). + /** + \param success Type of success of the iteration -- \b IN. + \param dir Direction of the iteration -- \b IN. + */ + void update ( NOMAD::success_type success, const NOMAD::Direction * dir=NULL); + + /// Reset the mesh to its original size (mesh indices). + void reset ( void ) { init() ;} + + + /// Display. + /** + \param out The NOMAD::Display object -- \b IN. + */ + void display ( const NOMAD::Display & out ) const; + + /// Test if r < r_min so far for all coordinates. + /** + \return True if mesh is the finest so far, False otherwise. + */ + bool is_finest ( void ) const; + + + /// Scale and project the ith component of a vector on the mesh + /** + \param i The vector component number -- \b IN. + \param l The vector component value -- \b IN. + \return The ith component of a vector after mesh scaling and projection + */ + NOMAD::Double scale_and_project(int i, const NOMAD::Double & l) const ; + + + /// Check the stopping conditions on the minimal poll and mesh sizes. + /** + \param stop Stop flag -- \b IN/OUT. + \param stop_reason Stop reason -- \b OUT. + */ + void check_min_mesh_sizes ( bool & stop , + NOMAD::stop_type & stop_reason ) const; + + /// Access to the mesh indices per coordinate. + /** + \return A point with the mesh index for each coordinate. + */ + const NOMAD::Point get_mesh_indices ( void ) const { return _r; } + + /// Access to the min mesh indices reached so far. + /** + \return A point with the mesh index for each coordinate. + */ + const NOMAD::Point get_min_mesh_indices ( void ) const { return _r_min; } + + + /// Access to the max mesh indices reached so far. + /** + \return A point with the mesh index for each coordinate. + */ + const NOMAD::Point get_max_mesh_indices ( void ) const { return _r_max; } + + + /// Manually set the mesh index. + /** + \param r The mesh index provided as a point -- \b IN. + */ + void set_mesh_indices ( const NOMAD::Point & r ); + + + + /// Manually set the limit mesh index (termination criterion). + /** + \param l The limit mesh index for all coordinates -- \b IN. + */ + void set_limit_mesh_index ( int l ); + + + + /// Access to the mesh ratios after a success + /** + \return A point with the ratio for each coordinate + */ + NOMAD::Point get_mesh_ratio_if_success ( void ) const; + + + + }; + + /// Display a NOMAD::XMesh object. + /** + \param out The NOMAD::Display object -- \b IN. + \param m The NOMAD::XMesh object to be displayed -- \b IN. + \return The NOMAD::Display object. + */ + inline const NOMAD::Display & operator << ( const NOMAD::Display & out , + const NOMAD::XMesh & m ) + { + m.display ( out ); + return out; + } + +} + +#endif diff --git a/src/defines.hpp b/src/defines.hpp index 5593c1c..511f75e 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -9,7 +9,7 @@ /* Christophe Tribes - Ecole Polytechnique, Montreal */ /* */ /* funded in part by AFOSR and Exxon Mobil */ -/* */ +/* */ /* Author: Sebastien Le Digabel */ /* */ /* Contact information: */ @@ -34,11 +34,11 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file defines.hpp - \brief Definitions - \author Sebastien Le Digabel - \date 2010-03-23 -*/ + \file defines.hpp + \brief Definitions + \author Sebastien Le Digabel + \date 2010-03-23 + */ #ifndef __DEFINES__ #define __DEFINES__ @@ -53,10 +53,10 @@ // #define R_VERSION // defined for the R version only // Matlab version OPTI style (if not defined than GERAD style) -// #define OPTI_VERSION +// #define OPTI_VERSION // Define in order to display debug information -// #define DEBUG +//#define DEBUG // define in order to display memory debug information: //#define MEMORY_DEBUG @@ -76,12 +76,12 @@ #endif -// CASE Linux using gnu compiler +// CASE Linux using gnu compiler #ifdef __gnu_linux__ #define GCC_X #endif -// CASE OSX using gnu compiler +// CASE OSX using gnu compiler #ifdef __APPLE__ #ifdef __GNUC__ #define GCC_X @@ -99,9 +99,10 @@ // CASE Visual Studio C++ compiler #ifdef _MSC_VER #define WINDOWS +#pragma warning(disable:4996) #endif -// For NOMAD random number generator +// For NOMAD random number generator #if !defined(UINT32_MAX) typedef unsigned int uint32_t; #define UINT32_MAX 0xffffffff @@ -122,384 +123,389 @@ typedef unsigned int uint32_t; // #define MODEL_STATS namespace NOMAD { - - /// Current version: - const std::string BASE_VERSION = "3.6.1"; - + + /// Current version: + const std::string BASE_VERSION = "3.7.2"; + #ifdef R_VERSION - const std::string VERSION = BASE_VERSION + ".R"; + const std::string VERSION = BASE_VERSION + ".R"; #else #ifdef USE_MPI #ifdef USE_TGP - const std::string VERSION = BASE_VERSION + ".TGP" + ".MPI"; + const std::string VERSION = BASE_VERSION + ".TGP" + ".MPI"; #else - const std::string VERSION = BASE_VERSION + ".MPI"; + const std::string VERSION = BASE_VERSION + ".MPI"; #endif #else #ifdef USE_TGP - const std::string VERSION = BASE_VERSION + ".TGP"; + const std::string VERSION = BASE_VERSION + ".TGP"; #else - const std::string VERSION = BASE_VERSION; + const std::string VERSION = BASE_VERSION; #endif #endif #endif - - // Directory separator, plus LGPL and user guide files + + // Directory separator, plus LGPL and user guide files #ifdef WINDOWS - const char DIR_SEP = '\\'; ///< Directory separator - const std::string HOME = "%NOMAD_HOME%"; ///< Home directory + const char DIR_SEP = '\\'; ///< Directory separator + const std::string HOME = "%NOMAD_HOME%"; ///< Home directory #else - const char DIR_SEP = '/'; ///< Directory separator - const std::string HOME = "$NOMAD_HOME"; ///< Home directory + const char DIR_SEP = '/'; ///< Directory separator + const std::string HOME = "$NOMAD_HOME"; ///< Home directory #endif - - /// Licence file - const std::string LGPL_FILE = HOME+DIR_SEP+"src"+DIR_SEP+"lgpl.txt"; - - /// User guide file - const std::string USER_GUIDE_FILE = HOME+DIR_SEP+"doc"+DIR_SEP+"user_guide.pdf"; - - /// Examples directory - const std::string EXAMPLES_DIR = HOME+DIR_SEP+"examples"; - - /// Tools directory - const std::string TOOLS_DIR = HOME+DIR_SEP+"tools"; - - /// Tag for valid cache files + + /// Licence file + const std::string LGPL_FILE = HOME+DIR_SEP+"src"+DIR_SEP+"lgpl.txt"; + + /// User guide file + const std::string USER_GUIDE_FILE = HOME+DIR_SEP+"doc"+DIR_SEP+"user_guide.pdf"; + + /// Examples directory + const std::string EXAMPLES_DIR = HOME+DIR_SEP+"examples"; + + /// Tools directory + const std::string TOOLS_DIR = HOME+DIR_SEP+"tools"; + + /// Tag for valid cache files #ifdef GCC_X - const int CACHE_FILE_ID = 77041301; + const int CACHE_FILE_ID = 77041301; #else #ifdef GCC_WINDOWS - const int CACHE_FILE_ID = 77041302; + const int CACHE_FILE_ID = 77041302; #else #ifdef _MSC_VER - const int CACHE_FILE_ID = 77041303; + const int CACHE_FILE_ID = 77041303; #else - const int CACHE_FILE_ID = 77041304; + const int CACHE_FILE_ID = 77041304; #endif #endif #endif - + #ifdef USE_MPI - // MPI constants - const int MAX_REQ_WAIT = 3 ; ///< Maximum time to wait for a request - const char STOP_SIGNAL = 'S'; ///< Stop signal - const char EVAL_SIGNAL = 'X'; ///< Evaluation signal - const char READY_SIGNAL = 'R'; ///< Ready signal - const char RESULT_SIGNAL = 'O'; ///< Result signal - const char WAIT_SIGNAL = 'W'; ///< Wait signal + // MPI constants + const int MAX_REQ_WAIT = 3 ; ///< Maximum time to wait for a request + const char STOP_SIGNAL = 'S'; ///< Stop signal + const char EVAL_SIGNAL = 'X'; ///< Evaluation signal + const char READY_SIGNAL = 'R'; ///< Ready signal + const char RESULT_SIGNAL = 'O'; ///< Result signal + const char WAIT_SIGNAL = 'W'; ///< Wait signal #endif - - /// Maximum number of variables. - const int MAX_DIMENSION = 1000; - - // Mesh index constants - const int L_LIMITS = 50; ///< Limits for the mesh index values - const int UNDEFINED_L = L_LIMITS+1; ///< Undefined value for the mesh index - - /// Default epsilon used by NOMAD::Double - /** Use Parameters::set_EPSILON(), or parameter EPSILON, - or NOMAD::Double::set_epsilon() to change it - */ - const double DEFAULT_EPSILON = 1e-13; - - /// Maximal output value for points used for models. - const double MODEL_MAX_OUTPUT = 1e10; - - /// Default infinity string used by NOMAD::Double - /** Use Parameters::set_INF_STR(), or parameter INF_STR, - or NOMAD::Double::set_inf_str() to change it - */ - const std::string DEFAULT_INF_STR = "inf"; - - /// Default undefined value string used by NOMAD::Double - /** Use Parameters::set_UNDEF_STR(), or parameter UNDEF_STR, - or NOMAD::Double::set_undef_str() to change it - */ - const std::string DEFAULT_UNDEF_STR = "NaN"; - - // VNS constants - const int VNS_HALTON_INDEX_0 = 997; ///< Initial Halton index for the VNS - const int VNS_HALTON_INCR = 17; ///< VNS Halton index increment - - /// log(10) (for display widths.) - const double LOG10 = 2.30258509299; - - const double INF = std::numeric_limits<double>::max(); ///< Infinity - - const double D_INT_MAX = UINT32_MAX; ///< The UINT32_MAX constant as a \c double - - // Singular Value Decomposition (SVD) constants: - const double SVD_EPS = 1e-13; ///< Epsilon for SVD - const int SVD_MAX_MPN = 1500; ///< Matrix maximal size (\c m+n ) - const double SVD_MAX_COND = NOMAD::INF; ///< Max. acceptable cond. number - - /// Default value for parameter POINT_DISPLAY_LIMIT - /** Use Parameters::set_POINT_DISPLAY_LIMIT() or parameter POINT_DISPLAY_LIMIT - or Point::set_display_limit() to change it */ - const int DEFAULT_POINT_DISPLAY_LIMIT = 20; - - // Display precisions. - const int DISPLAY_PRECISION_STD = 10; ///< Standard display precision - const int DISPLAY_PRECISION_BB = 15; ///< Display precision for blackboxes - - /// Constant for blackbox files #1. - const std::string BLACKBOX_INPUT_FILE_PREFIX = "nomad"; - - /// Constant for blackbox files #2. - const std::string BLACKBOX_INPUT_FILE_EXT = "input"; - - /// Constant for blackbox files #3. - const std::string BLACKBOX_OUTPUT_FILE_PREFIX = "nomad"; - - /// Constant for blackbox files #4. - const std::string BLACKBOX_OUTPUT_FILE_EXT = "output"; - - /// Display degree type. - enum dd_type + + /// Maximum number of variables. + const int MAX_DIMENSION = 1000; + + // Old static Mesh index constants + const int L_LIMITS = 50; ///< Limits for the smesh index values + const int UNDEFINED_L = L_LIMITS+1; ///< Undefined value for the smesh index + + // xmesh index constants + const int XL_LIMITS = -50; ///< Limits for the xmesh index values + const int UNDEFINED_XL = XL_LIMITS-1; ///< Undefined value for the xmesh index + + + /// Default epsilon used by NOMAD::Double + /** Use Parameters::set_EPSILON(), or parameter EPSILON, + or NOMAD::Double::set_epsilon() to change it + */ + const double DEFAULT_EPSILON = 1e-13; + + /// Maximal output value for points used for models. + const double MODEL_MAX_OUTPUT = 1e10; + + /// Default infinity string used by NOMAD::Double + /** Use Parameters::set_INF_STR(), or parameter INF_STR, + or NOMAD::Double::set_inf_str() to change it + */ + const std::string DEFAULT_INF_STR = "inf"; + + /// Default undefined value string used by NOMAD::Double + /** Use Parameters::set_UNDEF_STR(), or parameter UNDEF_STR, + or NOMAD::Double::set_undef_str() to change it + */ + const std::string DEFAULT_UNDEF_STR = "NaN"; + + /// log(10) (for display widths.) + const double LOG10 = 2.30258509299; + + const double INF = std::numeric_limits<double>::max(); ///< Infinity + + const double D_INT_MAX = UINT32_MAX; ///< The UINT32_MAX constant as a \c double + + // Singular Value Decomposition (SVD) constants: + const double SVD_EPS = 1e-13; ///< Epsilon for SVD + const int SVD_MAX_MPN = 1500; ///< Matrix maximal size (\c m+n ) + const double SVD_MAX_COND = NOMAD::INF; ///< Max. acceptable cond. number + + /// Default value for parameter POINT_DISPLAY_LIMIT + /** Use Parameters::set_POINT_DISPLAY_LIMIT() or parameter POINT_DISPLAY_LIMIT + or Point::set_display_limit() to change it */ + const int DEFAULT_POINT_DISPLAY_LIMIT = 20; + + // Display precisions. + const int DISPLAY_PRECISION_STD = 10; ///< Standard display precision + const int DISPLAY_PRECISION_BB = 15; ///< Display precision for blackboxes + + /// Constant for blackbox files #1. + const std::string BLACKBOX_INPUT_FILE_PREFIX = "nomad"; + + /// Constant for blackbox files #2. + const std::string BLACKBOX_INPUT_FILE_EXT = "input"; + + /// Constant for blackbox files #3. + const std::string BLACKBOX_OUTPUT_FILE_PREFIX = "nomad"; + + /// Constant for blackbox files #4. + const std::string BLACKBOX_OUTPUT_FILE_EXT = "output"; + + /// Display degree type. + enum dd_type { - NO_DISPLAY , ///< No display - MINIMAL_DISPLAY, ///< Minimal dispay - NORMAL_DISPLAY , ///< Normal display - FULL_DISPLAY ///< Full display + NO_DISPLAY , ///< No display + MINIMAL_DISPLAY, ///< Minimal dispay + NORMAL_DISPLAY , ///< Normal display + FULL_DISPLAY ///< Full display }; - - /// Types of the variables - // (do not modify this order) - enum bb_input_type + + /// Types of the variables + // (do not modify this order) + enum bb_input_type { - CONTINUOUS , ///< Continuous variable (default) (R) - INTEGER , ///< Integer variable (I) - CATEGORICAL , ///< Categorical variable (C) - BINARY ///< Binary variable (B) + CONTINUOUS , ///< Continuous variable (default) (R) + INTEGER , ///< Integer variable (I) + CATEGORICAL , ///< Categorical variable (C) + BINARY ///< Binary variable (B) }; - - /// Blackbox outputs type - enum bb_output_type + + /// Blackbox outputs type + enum bb_output_type { - OBJ , ///< Objective value - EB , ///< Extreme barrier constraint - PB , ///< progressive barrier constraint - // PEB ///< PB constraint that becomes EB once satisfied - PEB_P , ///< PEB constraint, state P (PB) - PEB_E , ///< PEB constraint, state E (EB) - FILTER , ///< Filter constraint - CNT_EVAL , ///< Output set to 0 or 1 to specify to count or not the - ///< blackbox evaluation - STAT_AVG , ///< Stat (average) - STAT_SUM , ///< Stat (sum) - UNDEFINED_BBO ///< Ignored output + OBJ , ///< Objective value + EB , ///< Extreme barrier constraint + PB , ///< progressive barrier constraint + // PEB ///< PB constraint that becomes EB once satisfied + PEB_P , ///< PEB constraint, state P (PB) + PEB_E , ///< PEB constraint, state E (EB) + FILTER , ///< Filter constraint + CNT_EVAL , ///< Output set to 0 or 1 to specify to count or not the + ///< blackbox evaluation + STAT_AVG , ///< Stat (average) + STAT_SUM , ///< Stat (sum) + UNDEFINED_BBO ///< Ignored output }; - - /// Formulation for multi-objective optimization - enum multi_formulation_type + + /// Formulation for multi-objective optimization + enum multi_formulation_type { - NORMALIZED , ///< Normalized formulation - PRODUCT , ///< Product formulation - DIST_L1 , ///< Distance formulation with norm L1 - DIST_L2 , ///< Distance formulation with norm L2 - DIST_LINF , ///< Distance formulation with norm Linf - UNDEFINED_FORMULATION ///< Undefined formulation + NORMALIZED , ///< Normalized formulation + PRODUCT , ///< Product formulation + DIST_L1 , ///< Distance formulation with norm L1 + DIST_L2 , ///< Distance formulation with norm L2 + DIST_LINF , ///< Distance formulation with norm Linf + UNDEFINED_FORMULATION ///< Undefined formulation }; - - /// Poll type - enum poll_type + + /// Poll type + enum poll_type { - PRIMARY , ///< Primary poll - SECONDARY ///< Secondary poll + PRIMARY , ///< Primary poll + SECONDARY ///< Secondary poll }; - - /// Poll center feasibility type - enum poll_center_type + + /// Poll center feasibility type + enum poll_center_type { - FEASIBLE , ///< Feasible poll center type - INFEASIBLE , ///< Infeasible poll center type - UNDEFINED_POLL_CENTER_TYPE ///< Undefined poll center type + FEASIBLE , ///< Feasible poll center type + INFEASIBLE , ///< Infeasible poll center type + UNDEFINED_POLL_CENTER_TYPE ///< Undefined poll center type }; - - /// Search type - enum search_type + + /// Search type + enum search_type { - X0_EVAL , ///< Starting point evaluation - POLL , ///< Poll - EXTENDED_POLL , ///< Extended poll - SEARCH , ///< Generic search - CACHE_SEARCH , ///< Cache search (does not require evals) - SPEC_SEARCH , ///< MADS speculative search (dynamic order in GPS) - LH_SEARCH , ///< Latin Hypercube (LH) search - LH_SEARCH_P1 , ///< Latin Hypercube (LH) search during phase one - MODEL_SEARCH , ///< Model search - VNS_SEARCH , ///< VNS search - P1_SEARCH , ///< Phase one search - ASYNCHRONOUS , ///< Parallel asynchronous final evaluations - USER_SEARCH , ///< User search - UNDEFINED_SEARCH ///< Undefined search + X0_EVAL , ///< Starting point evaluation + POLL , ///< Poll + EXTENDED_POLL , ///< Extended poll + SEARCH , ///< Generic search + CACHE_SEARCH , ///< Cache search (does not require evals) + SPEC_SEARCH , ///< MADS speculative search (dynamic order in GPS) + LH_SEARCH , ///< Latin Hypercube (LH) search + LH_SEARCH_P1 , ///< Latin Hypercube (LH) search during phase one + MODEL_SEARCH , ///< Model search + VNS_SEARCH , ///< VNS search + P1_SEARCH , ///< Phase one search + ASYNCHRONOUS , ///< Parallel asynchronous final evaluations + USER_SEARCH , ///< User search + UNDEFINED_SEARCH ///< Undefined search }; - - /// Model type - enum model_type + + /// Model type + enum model_type { - QUADRATIC_MODEL , ///< Quadratic model - TGP_MODEL , ///< TGP model - NO_MODEL ///< No models + QUADRATIC_MODEL , ///< Quadratic model + TGP_MODEL , ///< TGP model + NO_MODEL ///< No models }; - - /// TGP mode - enum TGP_mode_type + + /// TGP mode + enum TGP_mode_type { - TGP_FAST , ///< TGP fast mode. - TGP_PRECISE , ///< TGP precise mode. - TGP_USER ///< TGP user mode. + TGP_FAST , ///< TGP fast mode. + TGP_PRECISE , ///< TGP precise mode. + TGP_USER ///< TGP user mode. }; - - /// Success type of an iteration - // (do not modify this order) - enum success_type + + /// Success type of an iteration + // (do not modify this order) + enum success_type { - UNSUCCESSFUL , ///< Failure - PARTIAL_SUCCESS , ///< Partial success (improving) - FULL_SUCCESS ///< Full success (dominating) + UNSUCCESSFUL , ///< Failure + PARTIAL_SUCCESS , ///< Partial success (improving) + FULL_SUCCESS ///< Full success (dominating) }; - - /// Quadratic interpolation type - enum interpolation_type + + /// Quadratic interpolation type + enum interpolation_type { - MFN , ///< Minimum Frobenius Norm interpolation. - REGRESSION , ///< Regression. - WP_REGRESSION , ///< Well-poised regression. - UNDEFINED_INTERPOLATION_TYPE ///< Undefined. + MFN , ///< Minimum Frobenius Norm interpolation. + REGRESSION , ///< Regression. + WP_REGRESSION , ///< Well-poised regression. + UNDEFINED_INTERPOLATION_TYPE ///< Undefined. }; - - /// Stopping criteria - enum stop_type + + /// Stopping criteria + enum stop_type { - NO_STOP , ///< No stop - ERROR , ///< Error - UNKNOWN_STOP_REASON , ///< Unknown - CTRL_C , ///< Ctrl-C - USER_STOPPED , ///< User-stopped in Evaluator::update_iteration() - MESH_PREC_REACHED , ///< Mesh minimum precision reached - X0_FAIL , ///< Problem with starting point evaluation - P1_FAIL , ///< Problem with phase one - DELTA_M_MIN_REACHED , ///< Min mesh size - DELTA_P_MIN_REACHED , ///< Min poll size - L_MAX_REACHED , ///< Max mesh index - L_LIMITS_REACHED , ///< Mesh index limits - MAX_TIME_REACHED , ///< Max time - MAX_BB_EVAL_REACHED , ///< Max number of blackbox evaluations - MAX_SGTE_EVAL_REACHED , ///< Max number of surrogate evaluations - MAX_EVAL_REACHED , ///< Max number of evaluations - MAX_SIM_BB_EVAL_REACHED , ///< Max number of sim bb evaluations - MAX_ITER_REACHED , ///< Max number of iterations - MAX_CONS_FAILED_ITER , ///< Max number of consecutive failed iterations - FEAS_REACHED , ///< Feasibility - F_TARGET_REACHED , ///< F_TARGET - STAT_SUM_TARGET_REACHED , ///< STAT_SUM_TARGET - L_CURVE_TARGET_REACHED , ///< L_CURVE_TARGET - MULTI_MAX_BB_REACHED , ///< Max number of blackbox evaluations (multi obj.) - MULTI_NB_MADS_RUNS_REACHED , ///< Max number of MADS runs (multi obj.) - MULTI_STAGNATION , ///< Stagnation criterion (multi obj.) - MULTI_NO_PARETO_PTS , ///< No Pareto points (multi obj.) - MAX_CACHE_MEMORY_REACHED ///< Max cache memory + NO_STOP , ///< No stop + ERROR , ///< Error + UNKNOWN_STOP_REASON , ///< Unknown + CTRL_C , ///< Ctrl-C + USER_STOPPED , ///< User-stopped in Evaluator::update_iteration() + MESH_PREC_REACHED , ///< Mesh minimum precision reached + X0_FAIL , ///< Problem with starting point evaluation + P1_FAIL , ///< Problem with phase one + DELTA_M_MIN_REACHED , ///< Min mesh size + DELTA_P_MIN_REACHED , ///< Min poll size + L_MAX_REACHED , ///< Max mesh index + L_MIN_REACHED , ///< Min mesh index + L_LIMITS_REACHED , ///< Mesh index limits + XL_LIMITS_REACHED , ///< Mesh index limits + MAX_TIME_REACHED , ///< Max time + MAX_BB_EVAL_REACHED , ///< Max number of blackbox evaluations + MAX_SGTE_EVAL_REACHED , ///< Max number of surrogate evaluations + MAX_EVAL_REACHED , ///< Max number of evaluations + MAX_SIM_BB_EVAL_REACHED , ///< Max number of sim bb evaluations + MAX_ITER_REACHED , ///< Max number of iterations + MAX_CONS_FAILED_ITER , ///< Max number of consecutive failed iterations + FEAS_REACHED , ///< Feasibility + F_TARGET_REACHED , ///< F_TARGET + STAT_SUM_TARGET_REACHED , ///< STAT_SUM_TARGET + L_CURVE_TARGET_REACHED , ///< L_CURVE_TARGET + MULTI_MAX_BB_REACHED , ///< Max number of blackbox evaluations (multi obj.) + MULTI_NB_MADS_RUNS_REACHED , ///< Max number of MADS runs (multi obj.) + MULTI_STAGNATION , ///< Stagnation criterion (multi obj.) + MULTI_NO_PARETO_PTS , ///< No Pareto points (multi obj.) + MAX_CACHE_MEMORY_REACHED ///< Max cache memory }; - - /// Type of norm used for the computation of h - enum hnorm_type + + /// Type of norm used for the computation of h + enum hnorm_type { - L1 , ///< norm L1 - L2 , ///< norm L2 - LINF ///< norm Linf + L1 , ///< norm L1 + L2 , ///< norm L2 + LINF ///< norm Linf }; - - /// Types of directions - // (do not modify this order) - enum direction_type + + /// Types of directions + // (do not modify this order) + enum direction_type { - UNDEFINED_DIRECTION , ///< Undefined direction - MODEL_SEARCH_DIR , ///< Model search direction - NO_DIRECTION , ///< No direction - ORTHO_1 , ///< OrthoMADS 1 - ORTHO_2 , ///< OrthoMADS 2 - ORTHO_NP1_QUAD , ///< OrthoMADS n+1 use Quad model to determine n+1-th direction - ORTHO_NP1_NEG , ///< OrthoMADS n+1 use negative sum of n first directions to determine n+1-th direction - DYN_ADDED , ///< Dynamic addition (n+1-th direction added for ORTHO n+1) - ORTHO_2N , ///< OrthoMADS 2n - LT_1 , ///< LT-MADS 1 - LT_2 , ///< LT-MADS 2 - LT_2N , ///< LT-MADS 2n - LT_NP1 , ///< LT-MADS n+1 - GPS_BINARY , ///< GPS for binary variables - GPS_2N_STATIC , ///< GPS 2n static (classic coordinate search) - GPS_2N_RAND , ///< GPS 2n random - GPS_NP1_STATIC_UNIFORM , ///< GPS n+1 static uniform - GPS_NP1_STATIC , ///< GPS n+1 static - GPS_NP1_RAND_UNIFORM , ///< GPS n+1 random uniform - GPS_NP1_RAND , ///< GPS n+1 - PROSPECT_DIR ///< Prospect direction + UNDEFINED_DIRECTION , ///< Undefined direction + MODEL_SEARCH_DIR , ///< Model search direction + NO_DIRECTION , ///< No direction + ORTHO_1 , ///< OrthoMADS 1 + ORTHO_2 , ///< OrthoMADS 2 + ORTHO_NP1_QUAD , ///< OrthoMADS n+1 use Quad model to determine n+1-th direction + ORTHO_NP1_NEG , ///< OrthoMADS n+1 use negative sum of n first directions to determine n+1-th direction + DYN_ADDED , ///< Dynamic addition (n+1-th direction added for ORTHO n+1) + ORTHO_2N , ///< OrthoMADS 2n + LT_1 , ///< LT-MADS 1 + LT_2 , ///< LT-MADS 2 + LT_2N , ///< LT-MADS 2n + LT_NP1 , ///< LT-MADS n+1 + GPS_BINARY , ///< GPS for binary variables + GPS_2N_STATIC , ///< GPS 2n static (classic coordinate search) + GPS_2N_RAND , ///< GPS 2n random + GPS_NP1_STATIC_UNIFORM , ///< GPS n+1 static uniform + GPS_NP1_STATIC , ///< GPS n+1 static + GPS_NP1_RAND_UNIFORM , ///< GPS n+1 random uniform + GPS_NP1_RAND , ///< GPS n+1 + PROSPECT_DIR ///< Prospect direction }; - - /// Type for Eval_Point::check() failures - enum check_failed_type + + /// Type for Eval_Point::check() failures + enum check_failed_type { - CHECK_OK , ///< Correct check - LB_FAIL , ///< LB failure - UB_FAIL , ///< UB failure - FIX_VAR_FAIL , ///< Fixed variables failure - BIN_FAIL , ///< Binary failure - CAT_FAIL , ///< Categorical failure - INT_FAIL ///< Integer failure + CHECK_OK , ///< Correct check + LB_FAIL , ///< LB failure + UB_FAIL , ///< UB failure + FIX_VAR_FAIL , ///< Fixed variables failure + BIN_FAIL , ///< Binary failure + CAT_FAIL , ///< Categorical failure + INT_FAIL ///< Integer failure }; - - /// Type for cache indexes in Cache: - enum cache_index_type + + /// Type for cache indexes in Cache: + enum cache_index_type { - CACHE_1 , ///< Cache index #1 - CACHE_2 , ///< Cache index #2 - CACHE_3 , ///< Cache index #3 - UNDEFINED_CACHE ///< Undefined cache index + CACHE_1 , ///< Cache index #1 + CACHE_2 , ///< Cache index #2 + CACHE_3 , ///< Cache index #3 + UNDEFINED_CACHE ///< Undefined cache index }; - - /// Type for DISPLAY_STATS parameter - // (do not modify this order): - enum display_stats_type + + /// Type for DISPLAY_STATS parameter + // (do not modify this order): + enum display_stats_type { - DS_OBJ , ///< Objective (f) value - // (keep in first position) - DS_SIM_BBE , ///< Number of simulated bb evaluations - DS_BBE , ///< Number of bb evaluations - DS_SGTE , ///< Number of surrogate evaluations - DS_BBO , ///< All blackbox outputs - DS_EVAL , ///< Number of evaluations - DS_TIME , ///< Wall-clock time - DS_MESH_INDEX , ///< Mesh index - DS_MESH_SIZE , ///< Mesh size parameter Delta^m_k - DS_DELTA_M , ///< Same as \c DS_MESH_SIZE - DS_POLL_SIZE , ///< Poll size parameter Delta^p_k - DS_DELTA_P , ///< Same as \c DS_POLL_SIZE - DS_SOL , ///< Solution vector - DS_VAR , ///< One variable - DS_STAT_SUM , ///< Stat sum - DS_STAT_AVG , ///< Stat avg - DS_UNDEFINED ///< Undefined value - // (keep in last position) + DS_OBJ , ///< Objective (f) value + // (keep in first position) + DS_SIM_BBE , ///< Number of simulated bb evaluations + DS_BBE , ///< Number of bb evaluations + DS_BLK_EVA , ///< Number of block evaluation calls + DS_SGTE , ///< Number of surrogate evaluations + DS_BBO , ///< All blackbox outputs + DS_EVAL , ///< Number of evaluations + DS_TIME , ///< Wall-clock time + DS_MESH_INDEX , ///< Mesh index + DS_MESH_SIZE , ///< Mesh size parameter Delta^m_k + DS_DELTA_M , ///< Same as \c DS_MESH_SIZE + DS_POLL_SIZE , ///< Poll size parameter Delta^p_k + DS_DELTA_P , ///< Same as \c DS_POLL_SIZE + DS_SOL , ///< Solution vector + DS_VAR , ///< One variable + DS_STAT_SUM , ///< Stat sum + DS_STAT_AVG , ///< Stat avg + DS_UNDEFINED ///< Undefined value + // (keep in last position) }; - - /// Type for evaluation - enum eval_type + + /// Type for evaluation + enum eval_type { - TRUTH , ///< Truth - SGTE ///< Surrogate + TRUTH , ///< Truth + SGTE ///< Surrogate }; - - /// Type for an evaluation status - enum eval_status_type + + /// Type for an evaluation status + enum eval_status_type { - EVAL_FAIL , ///< Evaluation failure - EVAL_OK , ///< Correct evaluation - EVAL_IN_PROGRESS , ///< Evaluation in progress - UNDEFINED_STATUS ///< Undefined evaluation status + EVAL_FAIL , ///< Evaluation failure + EVAL_USER_REJECT , ///< Evaluation was rejected by user (not failure -> may submitted again) + EVAL_OK , ///< Correct evaluation + EVAL_IN_PROGRESS , ///< Evaluation in progress + UNDEFINED_STATUS ///< Undefined evaluation status }; - + } #endif diff --git a/src/nomad.cpp b/src/nomad.cpp index 88e49b4..250c2a3 100644 --- a/src/nomad.cpp +++ b/src/nomad.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -34,11 +34,11 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*-------------------------------------------------------------------------------------*/ /** - \file nomad.cpp - \brief NOMAD main file - \author Sebastien Le Digabel - \date 2010-04-12 -*/ + \file nomad.cpp + \brief NOMAD main file + \author Sebastien Le Digabel + \date 2010-04-12 + */ #include "nomad.hpp" /*------------------------------------------*/ @@ -46,128 +46,138 @@ /*------------------------------------------*/ int main ( int argc , char ** argv ) { - - // display: - NOMAD::Display out ( std::cout ); - out.precision ( NOMAD::DISPLAY_PRECISION_STD ); - - std::string error; - { - // NOMAD initializations: - NOMAD::begin ( argc , argv ); - - // usage: - if ( argc < 2 ) { - NOMAD::display_usage ( argv[0],std::cerr ); - NOMAD::end(); - return EXIT_FAILURE; - } - - // parameters file: - std::string param_file_name = argv[1]; - std::string opt = param_file_name; - NOMAD::toupper ( opt ); - - // display version if option '-v' has been specified: - if ( opt == "-U" ) { - NOMAD::display_usage ( argv[0], out ); - NOMAD::end(); - return EXIT_SUCCESS; - } - - - // display version if option '-v' has been specified: - if ( opt == "-V" || opt =="-VERSION") { - NOMAD::display_version ( out ); - NOMAD::end(); - return EXIT_SUCCESS; - } - - // display info if option '-i' has been specified: - if ( opt == "-I" || opt == "-INFO" ) { - NOMAD::display_info ( out ); - NOMAD::display_usage ( argv[0], out ); - NOMAD::end(); - return EXIT_SUCCESS; - } - - // parameters creation: - NOMAD::Parameters p ( out ); - - // display help on parameters if option '-h' has been specified: - if ( opt == "-H" || opt == "-HELP" ) { - p.help ( argc , argv ); - NOMAD::end(); - return EXIT_SUCCESS; - } - - // display developer help on parameters if option '-d' has been specified: - if ( opt == "-D" ) { - p.help ( argc , argv,true ); - NOMAD::end(); - return EXIT_SUCCESS; - } - - - // check the number of processess: + + // display: + NOMAD::Display out ( std::cout ); + out.precision ( NOMAD::DISPLAY_PRECISION_STD ); + + + std::string error; + { + // NOMAD initializations: + NOMAD::begin ( argc , argv ); + + // usage: + if ( argc < 2 ) + { + NOMAD::display_usage ( argv[0],std::cerr ); + NOMAD::end(); + return EXIT_FAILURE; + } + + // parameters file: + std::string param_file_name = argv[1]; + std::string opt = param_file_name; + NOMAD::toupper ( opt ); + + // display version if option '-v' has been specified: + if ( opt == "-U" ) + { + NOMAD::display_usage ( argv[0], out ); + NOMAD::end(); + return EXIT_SUCCESS; + } + + + // display version if option '-v' has been specified: + if ( opt == "-V" || opt =="-VERSION") + { + NOMAD::display_version ( out ); + NOMAD::end(); + return EXIT_SUCCESS; + } + + // display info if option '-i' has been specified: + if ( opt == "-I" || opt == "-INFO" ) + { + NOMAD::display_info ( out ); + NOMAD::display_usage ( argv[0], out ); + NOMAD::end(); + return EXIT_SUCCESS; + } + + // parameters creation: + NOMAD::Parameters p ( out ); + + // display help on parameters if option '-h' has been specified: + if ( opt == "-H" || opt == "-HELP" ) + { + p.help ( argc , argv ); + NOMAD::end(); + return EXIT_SUCCESS; + } + + // display developer help on parameters if option '-d' has been specified: + if ( opt == "-D" ) + { + p.help ( argc , argv,true ); + NOMAD::end(); + return EXIT_SUCCESS; + } + + + // check the number of processess: #ifdef USE_MPI - if ( NOMAD::Slave::get_nb_processes() < 2 ) { - std::cerr << "ERROR: Incorrect command to run with MPI." << std::endl; - NOMAD::display_usage ( argv[0], std::cerr ); - NOMAD::end(); - return EXIT_FAILURE; - } + if ( NOMAD::Slave::get_nb_processes() < 2 ) + { + std::cerr << "ERROR: Incorrect command to run with MPI." << std::endl; + NOMAD::display_usage ( argv[0], std::cerr ); + NOMAD::end(); + return EXIT_FAILURE; + } #endif - - try { - - - // read parameters file: - p.read ( param_file_name ); - - // parameters check: - p.check(); - - // display NOMAD info: - if ( p.get_display_degree() > NOMAD::MINIMAL_DISPLAY) - NOMAD::display_info ( out ); - - // parameters display: - if ( NOMAD::Slave::is_master() && - p.get_display_degree() == NOMAD::FULL_DISPLAY ) - out << std::endl - << NOMAD::open_block ( "parameters" ) << std::endl - << p - << NOMAD::close_block(); - - // algorithm creation and execution: - NOMAD::Mads mads ( p , NULL ); - if ( p.get_nb_obj() == 1 ) - mads.run(); - else - mads.multi_run(); - + + try { + + + // read parameters file: + p.read ( param_file_name ); + + // parameters check: + p.check(); + + // display NOMAD info: + if ( p.get_display_degree() > NOMAD::MINIMAL_DISPLAY) + NOMAD::display_info ( out ); + + // parameters display: + if ( NOMAD::Slave::is_master() && + p.get_display_degree() == NOMAD::FULL_DISPLAY ) + out << std::endl + << NOMAD::open_block ( "parameters" ) << std::endl + << p + << NOMAD::close_block(); + + // algorithm creation and execution: + NOMAD::Mads mads ( p , NULL ); + if ( p.get_nb_obj() == 1 ) + mads.run(); + else + mads.multi_run(); + #ifdef MODEL_STATS - mads.display_model_stats ( out ); + mads.display_model_stats ( out ); #endif - - } - catch ( std::exception & e ) { - if ( NOMAD::Slave::is_master() ) { - error = std::string ( "NOMAD has been interrupted: " ) + e.what(); - std::cerr << std::endl << error << std::endl << std::endl; - } + + } + catch ( std::exception & e ) + { + if ( NOMAD::Slave::is_master() ) + { + error = std::string ( "NOMAD has been interrupted: " ) + e.what(); + std::cerr << std::endl << error << std::endl << std::endl; + } + } + + NOMAD::Slave::stop_slaves ( out ); + NOMAD::end(); } - NOMAD::Slave::stop_slaves ( out ); - NOMAD::end(); - } - #ifdef MEMORY_DEBUG - NOMAD::display_cardinalities ( out ); + NOMAD::display_cardinalities ( out ); #endif - - return ( error.empty() ) ? EXIT_SUCCESS : EXIT_FAILURE; + + return ( error.empty() ) ? EXIT_SUCCESS : EXIT_FAILURE; } /*-----------------------------------------------------*/ @@ -176,79 +186,79 @@ int main ( int argc , char ** argv ) #ifdef MEMORY_DEBUG void NOMAD::display_cardinalities ( const NOMAD::Display & out ) { - + #ifdef USE_MPI - if ( !NOMAD::Slave::is_master() ) - return; + if ( !NOMAD::Slave::is_master() ) + return; #endif - - // compute the biggest int value for appropriate display width: - int max = (NOMAD::Double::get_max_cardinality() > NOMAD::Point::get_max_cardinality()) + + // compute the biggest int value for appropriate display width: + int max = (NOMAD::Double::get_max_cardinality() > NOMAD::Point::get_max_cardinality()) ? NOMAD::Double::get_max_cardinality() : NOMAD::Point::get_max_cardinality(); - if ( NOMAD::Direction::get_max_cardinality() > max ) - max = NOMAD::Direction::get_max_cardinality(); - if ( NOMAD::Set_Element<NOMAD::Eval_Point>::get_max_cardinality() > max ) - max = NOMAD::Set_Element<NOMAD::Eval_Point>::get_max_cardinality(); - if ( NOMAD::Set_Element<NOMAD::Signature>::get_max_cardinality() > max ) - max = NOMAD::Set_Element<NOMAD::Signature>::get_max_cardinality(); - if ( NOMAD::Cache_File_Point::get_max_cardinality() > max ) - max = NOMAD::Cache_File_Point::get_max_cardinality(); - - // cardinalities display: - // ---------------------- - out << std::endl - << NOMAD::open_block ( "important objects in memory" ); - - // NOMAD::Signature: - out << "Signature : "; - out.display_int_w ( NOMAD::Signature::get_cardinality() , max ); - out << " (max="; - out.display_int_w ( NOMAD::Signature::get_max_cardinality() , max ); - out << ")" << std::endl; - - // NOMAD::Double: - out << "Double : "; - out.display_int_w ( NOMAD::Double::get_cardinality() , max ); - out << " (max="; - out.display_int_w ( NOMAD::Double::get_max_cardinality() , max ); - out << ")" << std::endl; - - // NOMAD::Point: - out << "Point : "; - out.display_int_w ( NOMAD::Point::get_cardinality() , max ); - out << " (max="; - out.display_int_w ( NOMAD::Point::get_max_cardinality() , max ); - out << ")" << std::endl; - - // NOMAD::Direction: - out << "Direction : "; - out.display_int_w ( NOMAD::Direction::get_cardinality() , max ); - out << " (max="; - out.display_int_w ( NOMAD::Direction::get_max_cardinality() , max ); - out << ")" << std::endl; - - // Set_Element<Eval_Point>: - out << "Set_Element<Eval_Point>: "; - out.display_int_w (NOMAD::Set_Element<NOMAD::Eval_Point>::get_cardinality(), max); - out << " (max="; - out.display_int_w (NOMAD::Set_Element<NOMAD::Eval_Point>::get_max_cardinality(), max); - out << ")" << std::endl; - - // Set_Element<NOMAD::Signature>: - out << "Set_Element<Signature> : "; - out.display_int_w (NOMAD::Set_Element<NOMAD::Signature>::get_cardinality(), max); - out << " (max="; - out.display_int_w (NOMAD::Set_Element<NOMAD::Signature>::get_max_cardinality(), max); - out << ")" << std::endl; - - // NOMAD::Cache_File_Point: - out << "Cache_File_Point : "; - out.display_int_w ( NOMAD::Cache_File_Point::get_cardinality() , max ); - out << " (max="; - out.display_int_w ( NOMAD::Cache_File_Point::get_max_cardinality() , max ); - out << ")" << std::endl; - - out << NOMAD::close_block(); + if ( NOMAD::Direction::get_max_cardinality() > max ) + max = NOMAD::Direction::get_max_cardinality(); + if ( NOMAD::Set_Element<NOMAD::Eval_Point>::get_max_cardinality() > max ) + max = NOMAD::Set_Element<NOMAD::Eval_Point>::get_max_cardinality(); + if ( NOMAD::Set_Element<NOMAD::Signature>::get_max_cardinality() > max ) + max = NOMAD::Set_Element<NOMAD::Signature>::get_max_cardinality(); + if ( NOMAD::Cache_File_Point::get_max_cardinality() > max ) + max = NOMAD::Cache_File_Point::get_max_cardinality(); + + // cardinalities display: + // ---------------------- + out << std::endl + << NOMAD::open_block ( "important objects in memory" ); + + // NOMAD::Signature: + out << "Signature : "; + out.display_int_w ( NOMAD::Signature::get_cardinality() , max ); + out << " (max="; + out.display_int_w ( NOMAD::Signature::get_max_cardinality() , max ); + out << ")" << std::endl; + + // NOMAD::Double: + out << "Double : "; + out.display_int_w ( NOMAD::Double::get_cardinality() , max ); + out << " (max="; + out.display_int_w ( NOMAD::Double::get_max_cardinality() , max ); + out << ")" << std::endl; + + // NOMAD::Point: + out << "Point : "; + out.display_int_w ( NOMAD::Point::get_cardinality() , max ); + out << " (max="; + out.display_int_w ( NOMAD::Point::get_max_cardinality() , max ); + out << ")" << std::endl; + + // NOMAD::Direction: + out << "Direction : "; + out.display_int_w ( NOMAD::Direction::get_cardinality() , max ); + out << " (max="; + out.display_int_w ( NOMAD::Direction::get_max_cardinality() , max ); + out << ")" << std::endl; + + // Set_Element<Eval_Point>: + out << "Set_Element<Eval_Point>: "; + out.display_int_w (NOMAD::Set_Element<NOMAD::Eval_Point>::get_cardinality(), max); + out << " (max="; + out.display_int_w (NOMAD::Set_Element<NOMAD::Eval_Point>::get_max_cardinality(), max); + out << ")" << std::endl; + + // Set_Element<NOMAD::Signature>: + out << "Set_Element<Signature> : "; + out.display_int_w (NOMAD::Set_Element<NOMAD::Signature>::get_cardinality(), max); + out << " (max="; + out.display_int_w (NOMAD::Set_Element<NOMAD::Signature>::get_max_cardinality(), max); + out << ")" << std::endl; + + // NOMAD::Cache_File_Point: + out << "Cache_File_Point : "; + out.display_int_w ( NOMAD::Cache_File_Point::get_cardinality() , max ); + out << " (max="; + out.display_int_w ( NOMAD::Cache_File_Point::get_max_cardinality() , max ); + out << ")" << std::endl; + + out << NOMAD::close_block(); } #endif @@ -258,12 +268,12 @@ void NOMAD::display_cardinalities ( const NOMAD::Display & out ) void NOMAD::display_version ( const NOMAD::Display & out ) { #ifdef USE_MPI - if ( !NOMAD::Slave::is_master() ) - return; + if ( !NOMAD::Slave::is_master() ) + return; #endif - out << std::endl << "NOMAD - version " - << NOMAD::VERSION << " - www.gerad.ca/nomad" - << std::endl << std::endl; + out << std::endl << "NOMAD - version " + << NOMAD::VERSION << " - www.gerad.ca/nomad" + << std::endl << std::endl; } /*------------------------------------------*/ @@ -272,28 +282,28 @@ void NOMAD::display_version ( const NOMAD::Display & out ) void NOMAD::display_info ( const NOMAD::Display & out ) { #ifdef USE_MPI - if ( !NOMAD::Slave::is_master() ) - return; + if ( !NOMAD::Slave::is_master() ) + return; #endif - NOMAD::display_version ( out ); - out << NOMAD::open_block ( "Copyright (C) 2001-2013" ) - << "Mark A. Abramson - The Boeing Company" << std::endl - << "Charles Audet - Ecole Polytechnique de Montreal" << std::endl - << "Gilles Couture - Ecole Polytechnique de Montreal" << std::endl - << "John E. Dennis, Jr. - Rice University" << std::endl - << "Sebastien Le Digabel - Ecole Polytechnique de Montreal" << std::endl - << "Christophe Tribes - Ecole Polytechnique de Montreal" << std::endl - << NOMAD::close_block() - << std::endl - << "Funded in part by AFOSR and Exxon Mobil." << std::endl - << std::endl - << "License : \'" << NOMAD::LGPL_FILE << "\'" << std::endl - << "User guide: \'" << NOMAD::USER_GUIDE_FILE << "\'" << std::endl - << "Examples : \'" << NOMAD::EXAMPLES_DIR << "\'" << std::endl - << "Tools : \'" << NOMAD::TOOLS_DIR << "\'" << std::endl - << std::endl - << "Please report bugs to nomad@gerad.ca" - << std::endl; + NOMAD::display_version ( out ); + out << NOMAD::open_block ( "Copyright (C) 2001-2015" ) + << "Mark A. Abramson - The Boeing Company" << std::endl + << "Charles Audet - Ecole Polytechnique de Montreal" << std::endl + << "Gilles Couture - Ecole Polytechnique de Montreal" << std::endl + << "John E. Dennis, Jr. - Rice University" << std::endl + << "Sebastien Le Digabel - Ecole Polytechnique de Montreal" << std::endl + << "Christophe Tribes - Ecole Polytechnique de Montreal" << std::endl + << NOMAD::close_block() + << std::endl + << "Funded in part by AFOSR and Exxon Mobil." << std::endl + << std::endl + << "License : \'" << NOMAD::LGPL_FILE << "\'" << std::endl + << "User guide: \'" << NOMAD::USER_GUIDE_FILE << "\'" << std::endl + << "Examples : \'" << NOMAD::EXAMPLES_DIR << "\'" << std::endl + << "Tools : \'" << NOMAD::TOOLS_DIR << "\'" << std::endl + << std::endl + << "Please report bugs to nomad@gerad.ca" + << std::endl; } /*------------------------------------------*/ @@ -302,24 +312,24 @@ void NOMAD::display_info ( const NOMAD::Display & out ) void NOMAD::display_usage ( char* exeName, const NOMAD::Display & out ) { #ifdef USE_MPI - if ( !NOMAD::Slave::is_master() ) - return; - out << std::endl - << "Run NOMAD.MPI : mpirun -np p " << exeName << " parameters_file" << std::endl - << "Info : " << exeName << " -i" << std::endl - << "Help : " << exeName << " -h keyword(s) (or 'all')" << std::endl - << "Developer help : " << exeName << " -d keyword(s) (or 'all')" << std::endl - << "Version : " << exeName << " -v" << std::endl - << "Usage : " << exeName << " -u" << std::endl - << std::endl; + if ( !NOMAD::Slave::is_master() ) + return; + out << std::endl + << "Run NOMAD.MPI : mpirun -np p " << exeName << " parameters_file" << std::endl + << "Info : " << exeName << " -i" << std::endl + << "Help : " << exeName << " -h keyword(s) (or 'all')" << std::endl + << "Developer help : " << exeName << " -d keyword(s) (or 'all')" << std::endl + << "Version : " << exeName << " -v" << std::endl + << "Usage : " << exeName << " -u" << std::endl + << std::endl; #else - out << std::endl - << "Run NOMAD : " << exeName << " parameters_file" << std::endl - << "Info : " << exeName << " -i" << std::endl - << "Help : " << exeName << " -h keyword(s) (or 'all')" << std::endl - << "Developer help : " << exeName << " -d keyword(s) (or 'all')" << std::endl - << "Version : " << exeName << " -v" << std::endl - << "Usage : " << exeName << " -u" << std::endl - << std::endl; + out << std::endl + << "Run NOMAD : " << exeName << " parameters_file" << std::endl + << "Info : " << exeName << " -i" << std::endl + << "Help : " << exeName << " -h keyword(s) (or 'all')" << std::endl + << "Developer help : " << exeName << " -d keyword(s) (or 'all')" << std::endl + << "Version : " << exeName << " -v" << std::endl + << "Usage : " << exeName << " -u" << std::endl + << std::endl; #endif } diff --git a/src/nomad.hpp b/src/nomad.hpp index a035a37..5801177 100644 --- a/src/nomad.hpp +++ b/src/nomad.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ diff --git a/src/utils.cpp b/src/utils.cpp index e6a593d..199400f 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -149,6 +149,17 @@ std::string NOMAD::itos ( int i ) return oss.str(); } +/*-----------------------------------------------------------------*/ +/* NOMAD::itos */ +/*-----------------------------------------------------------------*/ +std::string NOMAD::itos ( size_t i ) +{ + std::ostringstream oss; + oss << i; + return oss.str(); +} + + /*-----------------------------------------------------------------*/ /* NOMAD::toupper - 1/2 */ /*-----------------------------------------------------------------*/ @@ -801,20 +812,20 @@ bool NOMAD::string_to_index_range ( const std::string & s , int NOMAD::get_rank(double ** M, - int m, - int n) + size_t m, + size_t n) { double * W = new double [n]; double ** V = new double *[n]; - for (int i = 0 ; i < n ; ++i ) + for (size_t i = 0 ; i < n ; ++i ) { V[i]=new double [n]; } std::string error_msg; - NOMAD::SVD_decomposition ( error_msg , M , W , V , m , n ); + NOMAD::SVD_decomposition ( error_msg , M , W , V , static_cast<int>(m) , static_cast<int>(n) ); - for (int i=0;i<n;++i) + for (size_t i=0;i<n;++i) delete [] V[i]; delete [] V; @@ -826,7 +837,7 @@ int NOMAD::get_rank(double ** M, } int rank=0; - for (int i=0;i<n;i++) + for (size_t i=0;i<n;i++) { if (fabs(W[i])>NOMAD::SVD_EPS) rank++; diff --git a/src/utils.hpp b/src/utils.hpp index 9dceb88..0fd19d5 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -1,7 +1,7 @@ /*-------------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.6.1 */ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct search - version 3.7.2 */ /* */ -/* Copyright (C) 2001-2012 Mark Abramson - the Boeing Company, Seattle */ +/* Copyright (C) 2001-2015 Mark Abramson - the Boeing Company, Seattle */ /* Charles Audet - Ecole Polytechnique, Montreal */ /* Gilles Couture - Ecole Polytechnique, Montreal */ /* John Dennis - Rice University, Houston */ @@ -196,6 +196,13 @@ namespace NOMAD { */ bool dir_is_orthomads ( NOMAD::direction_type dt ); + /// If a NOMAD::direction_type variable corresponds to a Ortho-MADS direction using XMesh. + /** + \param dt The NOMAD::direction_type -- \b IN. + \return A boolean equal to \c true if \c dt corresponds to a Ortho-MADS direction using XMesh. + */ + bool dir_is_orthomads_xmesh ( NOMAD::direction_type dt ); + /// Check if a set of directions include Ortho-MADS direction. /** \param dir_types Set of direction types -- \b IN. @@ -205,7 +212,17 @@ namespace NOMAD { */ bool dirs_have_orthomads ( const std::set<NOMAD::direction_type> & dir_types ); - /// Check if a set of directions include Ortho-MADS N+1 direction. + /// Check if a set of directions include Ortho-MADS direction using XMesh. + /** + \param dir_types Set of direction types -- \b IN. + \return A boolean equal to \c true if at + least one direction in the set is + of type Ortho-MADS+XMesh. + */ + bool dirs_have_orthomads_xmesh ( const std::set<NOMAD::direction_type> & dir_types ); + + + /// Check if a set of direction types include Ortho-MADS N+1 direction. /** \param dir_types Set of direction types -- \b IN. \return A boolean equal to \c true if at @@ -213,8 +230,7 @@ namespace NOMAD { of type Ortho-MADS N+1. */ bool dirs_have_orthomads_np1 ( const std::set<NOMAD::direction_type> & dir_types ); - - + /// Construct the n first prime numbers. /** @@ -269,6 +285,15 @@ namespace NOMAD { */ std::string itos ( int i ); + + /// Transform a unsigned long (size_t) into a string. + /** + \param i The unsigned long -- \b IN. + \return The string. + */ + std::string itos ( size_t i ); + + /// Put a string into upper cases. /** \param s The string -- \b IN/OUT. @@ -353,8 +378,8 @@ namespace NOMAD { \return The rank>0 if the decomposition worked else 0. */ int get_rank(double **M, - int m, - int n); + size_t m, + size_t n); } diff --git a/tools/COOP-MADS/Cache_Server.cpp b/tools/COOP-MADS/Cache_Server.cpp index dd1df4a..2b0d701 100644 --- a/tools/COOP-MADS/Cache_Server.cpp +++ b/tools/COOP-MADS/Cache_Server.cpp @@ -27,796 +27,823 @@ char Cache_Server::EP_SIGNAL = 'E'; /* constructor */ /*-----------------------------------*/ Cache_Server::Cache_Server ( const Display & out , - int rank , - int np , - const Double & h_min , - int max_bbe , - bool allow_multiple_evals ) - : Cache ( out , TRUTH ) , - _rank ( rank ) , - _np ( np ) , - _h_min ( h_min ) , - _max_bbe ( max_bbe ) , - _bf ( NULL ) , - _bi1 ( NULL ) , - _bi2 ( NULL ) , - _multiple_evals ( 0 ) , - _cache_hits ( 0 ) , - _cache_search_pts ( 0 ) , - _waited_pts ( NULL ) , - _clients_ext_pts ( NULL ) { - - // cache server: - if ( _rank == _np - 1 ) { - - _clients_ext_pts = new list<const Eval_Point*> [_np]; - - if ( !allow_multiple_evals ) { - _waited_pts = new Point * [_np]; - for ( int i = 0 ; i < _np ; ++i ) - _waited_pts[i] = NULL; + int rank , + int np , + const Double & h_min , + int max_bbe , + bool allow_multiple_evals ) +: Cache ( out , TRUTH ) , +_rank ( rank ) , +_np ( np ) , +_h_min ( h_min ) , +_max_bbe ( max_bbe ) , +_bf ( NULL ) , +_bi1 ( NULL ) , +_bi2 ( NULL ) , +_multiple_evals ( 0 ) , +_cache_hits ( 0 ) , +_cache_search_pts ( 0 ) , +_waited_pts ( NULL ) , +_clients_ext_pts ( NULL ) { + + // cache server: + if ( _rank == _np - 1 ) { + + _clients_ext_pts = new list<const Eval_Point*> [_np]; + + if ( !allow_multiple_evals ) { + _waited_pts = new Point * [_np]; + for ( int i = 0 ; i < _np ; ++i ) + _waited_pts[i] = NULL; + } } - } } /*-----------------------------------*/ /* destructor */ /*-----------------------------------*/ Cache_Server::~Cache_Server ( void ) { - if ( _waited_pts ) { - for ( int i = 0 ; i < _np ; ++i ) - if ( _waited_pts[i] ) - delete _waited_pts; - delete [] _waited_pts; - } - - if ( _clients_ext_pts ) - delete [] _clients_ext_pts; + if ( _waited_pts ) { + for ( int i = 0 ; i < _np ; ++i ) + if ( _waited_pts[i] ) + delete _waited_pts; + delete [] _waited_pts; + } + + if ( _clients_ext_pts ) + delete [] _clients_ext_pts; } /*-----------------------------------*/ /* start the server (process np-1) */ /*-----------------------------------*/ void Cache_Server::start ( void ) { - - int npm1 = _np-1; - - if ( _rank != npm1 ) - return; - - MPI_Status status; - int nb_stops = 0; - int source; - char signal; - - /*-------------*/ - /* main loop */ - /*-------------*/ - while ( nb_stops != npm1 ) { - - MPI_Recv ( &signal , 1 , MPI_CHAR , MPI_ANY_SOURCE , - Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD , &status ); - source = status.MPI_SOURCE; - - // stop signal: - // ------------ - if ( signal == Cache_Server::STOP_SIGNAL ) { - // cout << "STOP SIGNAL FROM RANK " << source << endl; - ++nb_stops; - } - - // find signal: - // ------------ - else if ( signal == Cache_Server::FIND_SIGNAL ) { - // cout << "FIND SIGNAL FROM RANK " << source << endl; - process_find_signal ( source ); - } - - // insert signal: - // -------------- - else if ( signal == Cache_Server::INSERT_SIGNAL ) { - // cout << "INSERT SIGNAL FROM RANK " << source << endl; - process_insert_signal ( source ); - } - - // number of extern points signal: - // ------------------------------- - else if ( signal == Cache_Server::NB_EP_SIGNAL ) { - // cout << "NB EXTERN POINTS SIGNAL FROM RANK " << source << endl; - int nb_client_extern_pts = _clients_ext_pts[source].size(); - MPI_Rsend ( &nb_client_extern_pts , 1 , MPI_INT , source , - Cache_Server::TAG_NB_EP , MPI_COMM_WORLD ); - } - - // extern point signal: - // -------------------- - else if ( signal == Cache_Server::EP_SIGNAL ) { - // cout << "EXTERN POINT SIGNAL FROM RANK " << source << endl; - process_ep_signal ( source ); + + int npm1 = _np-1; + + if ( _rank != npm1 ) + return; + + MPI_Status status; + int nb_stops = 0; + int source; + char signal; + + /*-------------*/ + /* main loop */ + /*-------------*/ + while ( nb_stops != npm1 ) { + + MPI_Recv ( &signal , 1 , MPI_CHAR , MPI_ANY_SOURCE , + Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD , &status ); + source = status.MPI_SOURCE; + + // stop signal: + // ------------ + if ( signal == Cache_Server::STOP_SIGNAL ) { + //cout << "STOP SIGNAL FROM RANK " << source << endl; + ++nb_stops; + } + + // find signal: + // ------------ + else if ( signal == Cache_Server::FIND_SIGNAL ) { + //cout << "FIND SIGNAL FROM RANK " << source << endl; + process_find_signal ( source ); + } + + // insert signal: + // -------------- + else if ( signal == Cache_Server::INSERT_SIGNAL ) { + //cout << "INSERT SIGNAL FROM RANK " << source << endl; + process_insert_signal ( source ); + } + + // number of extern points signal: + // ------------------------------- + else if ( signal == Cache_Server::NB_EP_SIGNAL ) { + //cout << "NB EXTERN POINTS SIGNAL FROM RANK " << source << endl; + int nb_client_extern_pts = _clients_ext_pts[source].size(); + MPI_Rsend ( &nb_client_extern_pts , 1 , MPI_INT , source , + Cache_Server::TAG_NB_EP , MPI_COMM_WORLD ); + } + + // extern point signal: + // -------------------- + else if ( signal == Cache_Server::EP_SIGNAL ) { + //cout << "EXTERN POINT SIGNAL FROM RANK " << source << endl; + process_ep_signal ( source ); + } } - } } /*---------------------------------*/ /* stop the server (clients) */ /*---------------------------------*/ void Cache_Server::stop ( void ) const { - int npm1 = _np-1; - if ( _rank == npm1 ) - return; - MPI_Send ( &Cache_Server::STOP_SIGNAL , 1 , MPI_CHAR , npm1 , - Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + int npm1 = _np-1; + if ( _rank == npm1 ) + return; + MPI_Send ( &Cache_Server::STOP_SIGNAL , 1 , MPI_CHAR , npm1 , + Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); } /*---------------------------------------*/ /* process the extern point signal */ /*---------------------------------------*/ void Cache_Server::process_ep_signal ( int source ) const { - - int nb_pt = ( _clients_ext_pts[source].size() > 0 ) ? 1 : 0; - - MPI_Rsend ( &nb_pt , 1 , MPI_INT , source , - Cache_Server::TAG_EP , MPI_COMM_WORLD ); - - // send and remove the extern point: - if ( nb_pt > 0 ) { - - const Eval_Point * x = *(_clients_ext_pts[source].begin()); - - ++_cache_search_pts; - - // send the point : - int i , n = x->size() , m = x->get_m(); - int itab[5]; - itab[0] = n; - itab[1] = m; - itab[2] = ( x->is_eval_ok() ) ? 1 : 0; - const int * ell = x->get_mesh_index(); - if ( ell ) { - itab[3] = 1; - itab[4] = *ell; + + int nb_pt = ( _clients_ext_pts[source].size() > 0 ) ? 1 : 0; + + MPI_Rsend ( &nb_pt , 1 , MPI_INT , source , + Cache_Server::TAG_EP , MPI_COMM_WORLD ); + + // send and remove the extern point: + if ( nb_pt > 0 ) { + + const Eval_Point * x = *(_clients_ext_pts[source].begin()); + + ++_cache_search_pts; + + // send the point : + int i , n = x->size() , m = x->get_m(); + int itab[5]; + itab[0] = n; + itab[1] = m; + itab[2] = ( x->is_eval_ok() ) ? 1 : 0; + + if ( x->get_signature() && ((x->get_signature()->get_mesh()->get_mesh_indices())[0]).is_defined() ) + { + itab[3] = 1; + itab[4] = static_cast<int>((x->get_signature()->get_mesh()->get_mesh_indices())[0].value()); + } + else + itab[3] = itab[4] = 0; + + double * rtab = new double[n+2*m]; + for ( i = 0 ; i < n ; ++i ) + rtab[i] = (*x)[i].value(); + + const Point & bbo = x->get_bb_outputs(); + + for ( i = 0 ; i < m ; ++i ) + if ( bbo[i].is_defined() ) { + rtab[2*i+n ] = 1.0; + rtab[2*i+n+1] = bbo[i].value(); + } + else + rtab[2*i+n] = rtab[2*i+n+1] = -1.0; + + MPI_Send ( itab , 5 , MPI_INT , source , + Cache_Server::TAG_X5 , MPI_COMM_WORLD ); + + MPI_Send ( rtab , n+2*m , MPI_DOUBLE , source , + Cache_Server::TAG_X6 , MPI_COMM_WORLD ); + + // remove the point: + _clients_ext_pts[source].pop_front(); } - else - itab[3] = itab[4] = 0; - - double * rtab = new double[n+2*m]; - for ( i = 0 ; i < n ; ++i ) - rtab[i] = (*x)[i].value(); - - const Point & bbo = x->get_bb_outputs(); - - for ( i = 0 ; i < m ; ++i ) - if ( bbo[i].is_defined() ) { - rtab[2*i+n ] = 1.0; - rtab[2*i+n+1] = bbo[i].value(); - } - else - rtab[2*i+n] = rtab[2*i+n+1] = -1.0; - - MPI_Send ( itab , 5 , MPI_INT , source , - Cache_Server::TAG_X5 , MPI_COMM_WORLD ); - - MPI_Send ( rtab , n+2*m , MPI_DOUBLE , source , - Cache_Server::TAG_X6 , MPI_COMM_WORLD ); - - // remove the point: - _clients_ext_pts[source].pop_front(); - } } /*-------------------------------*/ /* process the find signal */ /*-------------------------------*/ void Cache_Server::process_find_signal ( int source ) const { - - MPI_Status status; - int i; - - // receive the point coordinates: - int itab[2]; - MPI_Recv ( itab , 2 , MPI_INT , source , - Cache_Server::TAG_X1 , MPI_COMM_WORLD , &status ); - - int n = itab[0]; - int m = itab[1]; - - double * rtab = new double[n]; - - MPI_Recv ( rtab , n , MPI_DOUBLE , source , - Cache_Server::TAG_X2 , MPI_COMM_WORLD , &status ); - - // create the Eval_Point to search: - Eval_Point * x = new Eval_Point ( n , m ); - - for ( i = 0 ; i < n ; ++i ) - (*x)[i] = rtab[i]; - - delete [] rtab; - - // search in cache, or stop the algorithm: - const Eval_Point * cache_x; - - if ( _max_bbe > 0 && size() >= _max_bbe ) { - Eval_Point * stop_point = new Eval_Point ( n , m ); + + + MPI_Status status; + int i; + + // receive the point coordinates: + int itab[2]; + MPI_Recv ( itab , 2 , MPI_INT , source , + Cache_Server::TAG_X1 , MPI_COMM_WORLD , &status ); + + int n = itab[0]; + int m = itab[1]; + + double * rtab = new double[n]; + + MPI_Recv ( rtab , n , MPI_DOUBLE , source , + Cache_Server::TAG_X2 , MPI_COMM_WORLD , &status ); + + + + // create the Eval_Point to search: + Eval_Point * x = new Eval_Point ( n , m ); + for ( i = 0 ; i < n ; ++i ) - (*stop_point)[i] = (*x)[i]; - stop_point->set_eval_status ( EVAL_FAIL ); - cache_x = stop_point; - } - else - cache_x = Cache::find ( *x ); - - // cache hit signal : - int cache_hit; - - // point in cache : - if ( cache_x ) { - - delete x; - - cache_hit = 1; - - ++_cache_hits; - - MPI_Rsend ( &cache_hit , 1 , MPI_INT , source , - Cache_Server::TAG_CACHE_HIT , MPI_COMM_WORLD ); - - // bb output values, defined values and eval_ok flag: - rtab = new double[m]; - char * ctab = new char [m+1]; - const Point & bbo = cache_x->get_bb_outputs(); - - for ( i = 0 ; i < m ; ++i ) { - if ( bbo[i].is_defined() ) { - rtab[i] = bbo[i].value(); - ctab[i] = '1'; - } - else { - rtab[i] = INF; - ctab[i] = '0'; - } - } - - ctab[m] = ( cache_x->is_eval_ok() ) ? '1' : '0'; - - MPI_Send ( rtab , m , MPI_DOUBLE , source , - Cache_Server::TAG_BBOR, MPI_COMM_WORLD ); + (*x)[i] = rtab[i]; - MPI_Send ( ctab , m+1 , MPI_CHAR , source , - Cache_Server::TAG_BBOC , MPI_COMM_WORLD ); - delete [] rtab; - delete [] ctab; - - // remove this point from _clients_ext_pts: - { - list<const Eval_Point *>::iterator - it = _clients_ext_pts[source].begin() , - end = _clients_ext_pts[source].end (); - while ( it != end ) { - if ( *it == cache_x ) { - _clients_ext_pts[source].erase(it); - break; - } - ++it; - } - } - } - - // point not in cache : - else { - - cache_hit = 0; - - // evaluation in progress ? - if ( _waited_pts ) { - - for ( i = 0 ; i < _np ; ++i ) - if ( _waited_pts[i] && *_waited_pts[i] == *x ) { - cache_hit = -1; - break; - } - - if ( cache_hit == 0 ) - _waited_pts[source] = x; - else - delete x; + + // search in cache, or stop the algorithm: + const Eval_Point * cache_x; + + + + + if ( _max_bbe > 0 && size() >= _max_bbe ) { + Eval_Point * stop_point = new Eval_Point ( n , m ); + for ( i = 0 ; i < n ; ++i ) + (*stop_point)[i] = (*x)[i]; + stop_point->set_eval_status ( EVAL_FAIL ); + cache_x = stop_point; } else - delete x; - - MPI_Rsend ( &cache_hit , 1 , MPI_INT , source , - Cache_Server::TAG_CACHE_HIT , MPI_COMM_WORLD ); - } + cache_x = Cache::find ( *x ); + + + + // cache hit signal : + int cache_hit; + + // point in cache : + if ( cache_x ) { + + delete x; + + cache_hit = 1; + + ++_cache_hits; + + MPI_Rsend ( &cache_hit , 1 , MPI_INT , source , + Cache_Server::TAG_CACHE_HIT , MPI_COMM_WORLD ); + + // bb output values, defined values and eval_ok flag: + rtab = new double[m]; + char * ctab = new char [m+1]; + const Point & bbo = cache_x->get_bb_outputs(); + + for ( i = 0 ; i < m ; ++i ) { + if ( bbo[i].is_defined() ) { + rtab[i] = bbo[i].value(); + ctab[i] = '1'; + } + else { + rtab[i] = INF; + ctab[i] = '0'; + } + } + + ctab[m] = ( cache_x->is_eval_ok() ) ? '1' : '0'; + + MPI_Send ( rtab , m , MPI_DOUBLE , source , + Cache_Server::TAG_BBOR, MPI_COMM_WORLD ); + + MPI_Send ( ctab , m+1 , MPI_CHAR , source , + Cache_Server::TAG_BBOC , MPI_COMM_WORLD ); + + delete [] rtab; + delete [] ctab; + + // remove this point from _clients_ext_pts: + { + list<const Eval_Point *>::iterator + it = _clients_ext_pts[source].begin() , + end = _clients_ext_pts[source].end (); + while ( it != end ) { + if ( *it == cache_x ) { + _clients_ext_pts[source].erase(it); + break; + } + ++it; + } + } + } + + // point not in cache : + else { + + + + cache_hit = 0; + + // evaluation in progress ? + if ( _waited_pts ) { + + for ( i = 0 ; i < _np ; ++i ) + if ( _waited_pts[i] && *_waited_pts[i] == *x ) { + cache_hit = -1; + break; + } + + if ( cache_hit == 0 ) + _waited_pts[source] = x; + else + delete x; + } + else + delete x; + + + MPI_Rsend ( &cache_hit , 1 , MPI_INT , source , + Cache_Server::TAG_CACHE_HIT , MPI_COMM_WORLD ); + + } } /*--------------------*/ /* find a point */ /*--------------------*/ const Eval_Point * Cache_Server::find ( const Eval_Point & x ) const { - - MPI_Status status; - int npm1 = _np-1; - - // server: - if ( _rank == npm1 ) - return Cache::find ( x ); - - // A. search in local cache: - const Eval_Point * cache_x = Cache::find ( x ); - if ( cache_x ) - return cache_x; - - // B. ask the server. - int i , n = x.size() , m = x.get_m(); - int itab[2]; - itab[0] = n; - itab[1] = m; - double * rtab = new double[n]; - for ( i = 0 ; i < n ; ++i ) - rtab[i] = x[i].value(); - - int cache_hit = -1; - MPI_Request req = MPI_REQUEST_NULL; - - while ( cache_hit < 0 ) { - - // B1. send a request for cache_hit: - MPI_Irecv ( &cache_hit , 1 , MPI_INT , npm1 , - Cache_Server::TAG_CACHE_HIT , MPI_COMM_WORLD , &req ); - - // B2. send the find signal: - MPI_Send ( &Cache_Server::FIND_SIGNAL , 1 , MPI_CHAR , - npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); - // B3. send the point coordinates: - MPI_Send ( itab , 2 , MPI_INT , npm1 , - Cache_Server::TAG_X1 , MPI_COMM_WORLD ); - - MPI_Send ( rtab , n , MPI_DOUBLE , npm1 , - Cache_Server::TAG_X2 , MPI_COMM_WORLD ); - - // B4. wait for the cache_hit request: - MPI_Wait ( &req , &status ); - - // cache hit possible values: - // - // -1: point is being evaluated by another process (wait) - // 0: point not in cache server - // 1: point in cache server - } - - delete [] rtab; - - // C. cache hit: receive the point outputs: - if ( cache_hit == 1 ) { - - // C.1. bb output values and eval status: - rtab = new double[m]; - MPI_Recv ( rtab , m , MPI_DOUBLE , npm1 , - Cache_Server::TAG_BBOR , MPI_COMM_WORLD , &status ); - - char * ctab = new char[m+1]; - MPI_Recv ( ctab , m+1 , MPI_CHAR , npm1 , - Cache_Server::TAG_BBOC , MPI_COMM_WORLD , &status ); - - Point bbo(m); - for ( i = 0 ; i < m ; ++i ) - if ( ctab[i]=='1' ) - bbo[i] = rtab[i]; - - delete [] rtab; - - // C.2. eval point construction: - Eval_Point * y = new Eval_Point ( n , m ); - y->set_bb_output ( bbo ); + MPI_Status status; + int npm1 = _np-1; + + // server: + if ( _rank == npm1 ) + return Cache::find ( x ); + + // A. search in local cache: + const Eval_Point * cache_x = Cache::find ( x ); + if ( cache_x ) + return cache_x; + + // B. ask the server. + int i , n = x.size() , m = x.get_m(); + int itab[2]; + itab[0] = n; + itab[1] = m; + double * rtab = new double[n]; for ( i = 0 ; i < n ; ++i ) - (*y)[i] = x[i]; - - y->set_eval_status ( (ctab[m]=='1') ? EVAL_OK : EVAL_FAIL ); - - y->set_current_run ( x.get_current_run() ); - - delete [] ctab; - - cache_x = y; - - // C.3. insertion in local cache: - const_cast<Cache_Server*>(this)->Cache::insert ( *cache_x ); - } - - return cache_x; + rtab[i] = x[i].value(); + + int cache_hit = -1; + MPI_Request req = MPI_REQUEST_NULL; + + while ( cache_hit < 0 ) { + + // B1. send a request for cache_hit: + MPI_Irecv ( &cache_hit , 1 , MPI_INT , npm1 , + Cache_Server::TAG_CACHE_HIT , MPI_COMM_WORLD , &req ); + + // B2. send the find signal: + MPI_Send ( &Cache_Server::FIND_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + + // B3. send the point coordinates: + MPI_Send ( itab , 2 , MPI_INT , npm1 , + Cache_Server::TAG_X1 , MPI_COMM_WORLD ); + + MPI_Send ( rtab , n , MPI_DOUBLE , npm1 , + Cache_Server::TAG_X2 , MPI_COMM_WORLD ); + + // B4. wait for the cache_hit request: + MPI_Wait ( &req , &status ); + + // cache hit possible values: + // + // -1: point is being evaluated by another process (wait) + // 0: point not in cache server + // 1: point in cache server + } + + delete [] rtab; + + // C. cache hit: receive the point outputs: + if ( cache_hit == 1 ) { + + // C.1. bb output values and eval status: + rtab = new double[m]; + MPI_Recv ( rtab , m , MPI_DOUBLE , npm1 , + Cache_Server::TAG_BBOR , MPI_COMM_WORLD , &status ); + + char * ctab = new char[m+1]; + MPI_Recv ( ctab , m+1 , MPI_CHAR , npm1 , + Cache_Server::TAG_BBOC , MPI_COMM_WORLD , &status ); + + Point bbo(m); + for ( i = 0 ; i < m ; ++i ) + if ( ctab[i]=='1' ) + bbo[i] = rtab[i]; + + delete [] rtab; + + // C.2. eval point construction: + Eval_Point * y = new Eval_Point ( n , m ); + y->set_bb_output ( bbo ); + for ( i = 0 ; i < n ; ++i ) + (*y)[i] = x[i]; + + y->set_eval_status ( (ctab[m]=='1') ? EVAL_OK : EVAL_FAIL ); + + y->set_current_run ( x.get_current_run() ); + + delete [] ctab; + + cache_x = y; + + // C.3. insertion in local cache: + const_cast<Cache_Server*>(this)->Cache::insert ( *cache_x ); + } + + return cache_x; } /*------------------------------------*/ /* process the insertion signal */ /*------------------------------------*/ void Cache_Server::process_insert_signal ( int source ) { + + + if ( _waited_pts && _waited_pts[source] ) { + delete _waited_pts[source]; + _waited_pts[source] = NULL; + } + + // receive the evaluation point: + MPI_Status status; + int itab[7]; + MPI_Recv ( itab , 7 , MPI_INT , source , + Cache_Server::TAG_X3 , MPI_COMM_WORLD , &status ); + + + int n = itab[0]; + int m = itab[1]; + + double * rtab = new double[n+2*m+2]; + + MPI_Recv ( rtab , n+2*m+2 , MPI_DOUBLE , source , + Cache_Server::TAG_X4 , MPI_COMM_WORLD , &status ); + + + + // create the Eval_Point to insert: + Eval_Point * x = new Eval_Point ( n , m ); + + int i; + for ( i = 0 ; i < n ; ++i ) + (*x)[i] = rtab[i]; + + for ( i = 0 ; i < m ; ++i ) + if ( rtab[2*i+n] > 0 ) + x->set_bb_output ( i , rtab[2*i+n+1] ); + + if ( itab[5] == 1 ) + x->set_f ( rtab[n+2*m ] ); + + if ( itab[6] == 1 ) + x->set_h ( rtab[n+2*m+1] ); + + delete [] rtab; + + x->set_eval_status ( ( itab[2] == 1 ) ? EVAL_OK : EVAL_FAIL ); + + + if ( itab[3] == 1 && x->get_signature() ) + { + NOMAD::Point mesh_indices(n,NOMAD::Double(itab[4])); + cout << x->get_signature() << endl; - if ( _waited_pts && _waited_pts[source] ) { - delete _waited_pts[source]; - _waited_pts[source] = NULL; - } - - // receive the evaluation point: - MPI_Status status; - int itab[7]; - MPI_Recv ( itab , 7 , MPI_INT , source , - Cache_Server::TAG_X3 , MPI_COMM_WORLD , &status ); - - int n = itab[0]; - int m = itab[1]; - - double * rtab = new double[n+2*m+2]; - - MPI_Recv ( rtab , n+2*m+2 , MPI_DOUBLE , source , - Cache_Server::TAG_X4 , MPI_COMM_WORLD , &status ); - - // create the Eval_Point to insert: - Eval_Point * x = new Eval_Point ( n , m ); - - int i; - for ( i = 0 ; i < n ; ++i ) - (*x)[i] = rtab[i]; - - for ( i = 0 ; i < m ; ++i ) - if ( rtab[2*i+n] > 0 ) - x->set_bb_output ( i , rtab[2*i+n+1] ); - - if ( itab[5] == 1 ) - x->set_f ( rtab[n+2*m ] ); - - if ( itab[6] == 1 ) - x->set_h ( rtab[n+2*m+1] ); - - delete [] rtab; - - x->set_eval_status ( ( itab[2] == 1 ) ? EVAL_OK : EVAL_FAIL ); - - if ( itab[3] == 1 ) - x->set_mesh_index ( &itab[4] ); - - // Eval_Point insertion in cache and multiple_evals detection: - const Eval_Point * cache_x = Cache::find ( *x ); - if ( cache_x ) { - ++_multiple_evals; - delete x; - x = const_cast<Eval_Point *>(cache_x); - } - else - Cache::insert ( *x ); + x->get_signature()->get_mesh()->set_mesh_indices ( mesh_indices); + } - // update the best points: - update_best_points ( *x , source ); + // Eval_Point insertion in cache and multiple_evals detection: + const Eval_Point * cache_x = Cache::find ( *x ); + if ( cache_x ) { + ++_multiple_evals; + delete x; + x = const_cast<Eval_Point *>(cache_x); + } + else + Cache::insert ( *x ); + + // update the best points: + update_best_points ( *x , source ); } /*--------------------*/ /* insert a point */ /*--------------------*/ void Cache_Server::insert ( const NOMAD::Eval_Point & x ) { - - // insertion in local cache : - Cache::insert ( x ); - - int npm1 = _np-1; - if ( _rank == npm1 ) - return; - - // insert signal : - MPI_Send ( &Cache_Server::INSERT_SIGNAL , 1 , MPI_CHAR , - npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); - - // send the point : - int i , n = x.size() , m = x.get_m(); - int itab[7]; - itab[0] = n; - itab[1] = m; - itab[2] = ( x.is_eval_ok() ) ? 1 : 0; - const int * ell = x.get_mesh_index(); - if ( ell ) { - itab[3] = 1; - itab[4] = *ell; - } - else - itab[3] = itab[4] = 0; - - double * rtab = new double[n+2*m+2]; - for ( i = 0 ; i < n ; ++i ) - rtab[i] = x[i].value(); - - const Point & bbo = x.get_bb_outputs(); - - for ( i = 0 ; i < m ; ++i ) - if ( bbo[i].is_defined() ) { - rtab[2*i+n ] = 1.0; - rtab[2*i+n+1] = bbo[i].value(); + + // insertion in local cache : + Cache::insert ( x ); + + int npm1 = _np-1; + if ( _rank == npm1 ) + return; + + // insert signal : + MPI_Send ( &Cache_Server::INSERT_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + + // send the point : + int i , n = x.size() , m = x.get_m(); + int itab[7]; + itab[0] = n; + itab[1] = m; + itab[2] = ( x.is_eval_ok() ) ? 1 : 0; + + if ( x.get_signature() && ((x.get_signature()->get_mesh()->get_mesh_indices())[0]).is_defined() ) + { + itab[3] = 1; + itab[4] = static_cast<int>((x.get_signature()->get_mesh()->get_mesh_indices())[0].value()); } else - rtab[2*i+n] = rtab[2*i+n+1] = -1.0; - - // f and h values: - if ( x.get_f().is_defined() ) { - itab[5 ] = 1; - rtab[n+2*m] = x.get_f().value(); - } - else { - itab[5 ] = 0; - rtab[n+2*m] = INF; - } - if ( x.get_h().is_defined() ) { - itab[6 ] = 1; - rtab[n+2*m+1] = x.get_h().value(); - } - else { - itab[6 ] = 0; - rtab[n+2*m+1] = INF; - } - - MPI_Send ( itab , 7 , MPI_INT , npm1 , - Cache_Server::TAG_X3 , MPI_COMM_WORLD ); - - MPI_Send ( rtab , n+2*m+2 , MPI_DOUBLE , npm1 , - Cache_Server::TAG_X4 , MPI_COMM_WORLD ); - - delete [] rtab; + itab[3] = itab[4] = 0; + + double * rtab = new double[n+2*m+2]; + for ( i = 0 ; i < n ; ++i ) + rtab[i] = x[i].value(); + + const Point & bbo = x.get_bb_outputs(); + + for ( i = 0 ; i < m ; ++i ) + if ( bbo[i].is_defined() ) { + rtab[2*i+n ] = 1.0; + rtab[2*i+n+1] = bbo[i].value(); + } + else + rtab[2*i+n] = rtab[2*i+n+1] = -1.0; + + // f and h values: + if ( x.get_f().is_defined() ) { + itab[5 ] = 1; + rtab[n+2*m] = x.get_f().value(); + } + else { + itab[5 ] = 0; + rtab[n+2*m] = INF; + } + if ( x.get_h().is_defined() ) { + itab[6 ] = 1; + rtab[n+2*m+1] = x.get_h().value(); + } + else { + itab[6 ] = 0; + rtab[n+2*m+1] = INF; + } + + MPI_Send ( itab , 7 , MPI_INT , npm1 , + Cache_Server::TAG_X3 , MPI_COMM_WORLD ); + + MPI_Send ( rtab , n+2*m+2 , MPI_DOUBLE , npm1 , + Cache_Server::TAG_X4 , MPI_COMM_WORLD ); + + delete [] rtab; } /*--------------------------------------*/ /* get and remove an extern point */ /*--------------------------------------*/ const Eval_Point * Cache_Server::get_and_remove_extern_point ( void ) const { - - int npm1 = _np-1; - - if ( _rank == npm1 ) - return NULL; - - // extern point from the client: - // ----------------------------- - if ( Cache::get_nb_extern_points() > 0 ) - return Cache::get_and_remove_extern_point(); - - // extern point from the server: - // ----------------------------- - int nb_pt; - - // send a request for an extern point: - MPI_Request req; - MPI_Irecv ( &nb_pt , 1 , MPI_INT , npm1 , - Cache_Server::TAG_EP , MPI_COMM_WORLD , &req ); - - // extern points signal : - MPI_Send ( &Cache_Server::EP_SIGNAL , 1 , MPI_CHAR , - npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); - - // wait for the request: - MPI_Status status; - MPI_Wait ( &req , &status ); - - if ( nb_pt == 0 ) - return NULL; - - // receive the extern point: - int itab[5]; - MPI_Recv ( itab , 5 , MPI_INT , npm1 , - Cache_Server::TAG_X5 , MPI_COMM_WORLD , &status ); - - int n = itab[0]; - int m = itab[1]; - - double * rtab = new double[n+2*m]; - - MPI_Recv ( rtab , n+2*m , MPI_DOUBLE , npm1 , - Cache_Server::TAG_X6 , MPI_COMM_WORLD , &status ); - - // create the Eval_Point: - Eval_Point * x = new Eval_Point ( n , m ); - - int i; - for ( i = 0 ; i < n ; ++i ) - (*x)[i] = rtab[i]; - - for ( i = 0 ; i < m ; ++i ) - if ( rtab[2*i+n] > 0 ) - x->set_bb_output ( i , rtab[2*i+n+1] ); - - delete [] rtab; - - x->set_eval_status ( ( itab[2] == 1 ) ? EVAL_OK : EVAL_FAIL ); - - if ( itab[3] == 1 ) - x->set_mesh_index ( &itab[4] ); - - // insert the point in local cache: - const Eval_Point * cache_x = Cache::find ( *x ); - if ( cache_x ) { - delete x; - return cache_x; - } - - x->set_current_run ( true ); - const_cast<Cache_Server*>(this)->Cache::insert ( *x ); - x->set_current_run ( false ); - - return x; + + int npm1 = _np-1; + + if ( _rank == npm1 ) + return NULL; + + // extern point from the client: + // ----------------------------- + if ( Cache::get_nb_extern_points() > 0 ) + return Cache::get_and_remove_extern_point(); + + // extern point from the server: + // ----------------------------- + int nb_pt; + + // send a request for an extern point: + MPI_Request req; + MPI_Irecv ( &nb_pt , 1 , MPI_INT , npm1 , + Cache_Server::TAG_EP , MPI_COMM_WORLD , &req ); + + // extern points signal : + MPI_Send ( &Cache_Server::EP_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + + // wait for the request: + MPI_Status status; + MPI_Wait ( &req , &status ); + + if ( nb_pt == 0 ) + return NULL; + + // receive the extern point: + int itab[5]; + MPI_Recv ( itab , 5 , MPI_INT , npm1 , + Cache_Server::TAG_X5 , MPI_COMM_WORLD , &status ); + + int n = itab[0]; + int m = itab[1]; + + double * rtab = new double[n+2*m]; + + MPI_Recv ( rtab , n+2*m , MPI_DOUBLE , npm1 , + Cache_Server::TAG_X6 , MPI_COMM_WORLD , &status ); + + // create the Eval_Point: + Eval_Point * x = new Eval_Point ( n , m ); + + int i; + for ( i = 0 ; i < n ; ++i ) + (*x)[i] = rtab[i]; + + for ( i = 0 ; i < m ; ++i ) + if ( rtab[2*i+n] > 0 ) + x->set_bb_output ( i , rtab[2*i+n+1] ); + + delete [] rtab; + + x->set_eval_status ( ( itab[2] == 1 ) ? EVAL_OK : EVAL_FAIL ); + + if ( itab[3] == 1 && x->get_signature() ) + { + x->get_signature()->get_mesh()->set_mesh_indices ( NOMAD::Point(n,NOMAD::Double(itab[4])) ); + } + + + // insert the point in local cache: + const Eval_Point * cache_x = Cache::find ( *x ); + if ( cache_x ) { + delete x; + return cache_x; + } + + x->set_current_run ( true ); + const_cast<Cache_Server*>(this)->Cache::insert ( *x ); + x->set_current_run ( false ); + + return x; } /*---------------------------------------*/ /* get the number of extern points */ /*---------------------------------------*/ int Cache_Server::get_nb_extern_points ( void ) const { - - int nb_client_extern_pts = Cache::get_nb_extern_points(); - int nb_server_extern_pts = 0; - int npm1 = _np-1; - - if ( _rank != npm1 ) { - - // send a request for the number of extern points: - MPI_Request req; - MPI_Irecv ( &nb_server_extern_pts , 1 , MPI_INT , npm1 , - Cache_Server::TAG_NB_EP , MPI_COMM_WORLD , &req ); - - // number of extern points signal : - MPI_Send ( &Cache_Server::NB_EP_SIGNAL , 1 , MPI_CHAR , - npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); - - // wait for the request: - MPI_Status status; - MPI_Wait ( &req , &status ); - } - - return nb_client_extern_pts + nb_server_extern_pts; + + int nb_client_extern_pts = Cache::get_nb_extern_points(); + int nb_server_extern_pts = 0; + int npm1 = _np-1; + + if ( _rank != npm1 ) { + + // send a request for the number of extern points: + MPI_Request req; + MPI_Irecv ( &nb_server_extern_pts , 1 , MPI_INT , npm1 , + Cache_Server::TAG_NB_EP , MPI_COMM_WORLD , &req ); + + // number of extern points signal : + MPI_Send ( &Cache_Server::NB_EP_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + + // wait for the request: + MPI_Status status; + MPI_Wait ( &req , &status ); + } + + return nb_client_extern_pts + nb_server_extern_pts; } /*---------------------------------*/ /* display the extern points */ /*---------------------------------*/ void Cache_Server::display_extern_pts ( const Display & out ) const { - - int npm1 = _np-1; - - // server: - // ------- - if ( _rank == npm1 ) { - - list<const Eval_Point*>::const_iterator it; - out << endl << open_block ("Clients extern points"); - - for ( int i = 0 ; i < npm1 ; ++i ) { - out.open_block ( "client #"+itos(i) ); - for ( it = _clients_ext_pts[i].begin() ; - it != _clients_ext_pts[i].end () ; - ++it ) { - out << "#" << (*it)->get_tag() << " ( "; - (*it)->Point::display ( out ); - out << " ) " << " [" - << (*it)->get_bb_outputs() << " ] f=" - << (*it)->get_f() << " h=" - << (*it)->get_h() << endl; - } - out.close_block(); + + int npm1 = _np-1; + + // server: + // ------- + if ( _rank == npm1 ) { + + list<const Eval_Point*>::const_iterator it; + out << endl << open_block ("Clients extern points"); + + for ( int i = 0 ; i < npm1 ; ++i ) { + out.open_block ( "client #"+itos(i) ); + for ( it = _clients_ext_pts[i].begin() ; + it != _clients_ext_pts[i].end () ; + ++it ) { + out << "#" << (*it)->get_tag() << " ( "; + (*it)->Point::display ( out ); + out << " ) " << " [" + << (*it)->get_bb_outputs() << " ] f=" + << (*it)->get_f() << " h=" + << (*it)->get_h() << endl; + } + out.close_block(); + } } - } - - // clients: - else { - - out << endl - << open_block ( "Process #" + itos(_rank) + ": extern points" ); - - out << "number of points = " - << get_nb_extern_points() << endl; - - const Eval_Point * extern_pt = get_and_remove_extern_point(); - - while ( extern_pt ) { - - out << "#" << extern_pt->get_tag() << " ( "; - extern_pt->Point::display ( out ); - out << " ) " << " [" - << extern_pt->get_bb_outputs() << " ] f=" - << extern_pt->get_f() << " h=" - << extern_pt->get_h() << endl; - - extern_pt = get_and_remove_extern_point(); + + // clients: + else { + + out << endl + << open_block ( "Process #" + itos(_rank) + ": extern points" ); + + out << "number of points = " + << get_nb_extern_points() << endl; + + const Eval_Point * extern_pt = get_and_remove_extern_point(); + + while ( extern_pt ) { + + out << "#" << extern_pt->get_tag() << " ( "; + extern_pt->Point::display ( out ); + out << " ) " << " [" + << extern_pt->get_bb_outputs() << " ] f=" + << extern_pt->get_f() << " h=" + << extern_pt->get_h() << endl; + + extern_pt = get_and_remove_extern_point(); + } } - } - out << close_block() << endl; + out << close_block() << endl; } /*--------------------------------------*/ /* update and display the best points */ /*--------------------------------------*/ void Cache_Server::update_best_points ( const Eval_Point & x , - int source ) { - const Double & f = x.get_f(); - const Double & h = x.get_h(); - - if ( !f.is_defined() || !h.is_defined() ) - return; - - int i; - bool add_x = false; - - // feasible: - if ( h <= _h_min ) { - - // new best feasible point: - if ( !_bf || f < _bf->get_f() ) { - _bf = &x; - add_x = true; - display_current_solution(); - } - } - - // infeasible: - else { - if ( !_bi1 || h < _bi1->get_h() ) { - _bi1 = &x; - add_x = true; + int source ) { + const Double & f = x.get_f(); + const Double & h = x.get_h(); + + if ( !f.is_defined() || !h.is_defined() ) + return; + + int i; + bool add_x = false; + + // feasible: + if ( h <= _h_min ) { + + // new best feasible point: + if ( !_bf || f < _bf->get_f() ) { + _bf = &x; + add_x = true; + display_current_solution(); + } } - if ( !_bi2 || f < _bi2->get_f() ) { - _bi2 = &x; - add_x = true; + + // infeasible: + else { + if ( !_bi1 || h < _bi1->get_h() ) { + _bi1 = &x; + add_x = true; + } + if ( !_bi2 || f < _bi2->get_f() ) { + _bi2 = &x; + add_x = true; + } } - } - - if ( add_x ) - for ( i = 0 ; i < _np-1 ; ++i ) - if ( i != source ) - _clients_ext_pts[i].push_front ( &x ); + + if ( add_x ) + for ( i = 0 ; i < _np-1 ; ++i ) + if ( i != source ) + _clients_ext_pts[i].push_front ( &x ); } /*-----------------------------------------*/ /* display the current best solution */ /*-----------------------------------------*/ void Cache_Server::display_current_solution ( void ) const { - if ( _rank != _np-1 || !_bf ) - return; - _out << _clock.get_real_time() << "\t" - << size() << "\t" << _bf->get_f() << endl; + if ( _rank != _np-1 || !_bf ) + return; + _out << _clock.get_real_time() << "\t" + << size() << "\t" << _bf->get_f() << endl; } /*-------------------------------*/ /* display the best points */ /*-------------------------------*/ void Cache_Server::display_best_points ( const Display & out ) const { - if ( _rank != _np-1 ) - return; - - // stats: - out << "evaluations : " << size() << endl - << "multiple evaluations : " << _multiple_evals << endl - << "cache hits : " << _cache_hits << endl - << "cache search points : " << _cache_search_pts << endl; - - // best feasible solution: - out << "best feasible solution: "; - if ( _bf ) { - out << "x=( "; - _bf->Point::display(out); - out << " )" - << " F(x)=[ " << _bf->get_bb_outputs() << " ] h=" - << _bf->get_h() << " f=" << _bf->get_f() << endl; - } - else - out << "NULL" << endl; - - // best infeasible solutions: - if ( _bi1 ) { - out << "best infeas. sol. #1 : x=( "; - _bi1->Point::display(out); - out << " )" - << " F(x)=[ " << _bi1->get_bb_outputs() << " ] h=" - << _bi1->get_h() << " f=" << _bi1->get_f() << endl; - } - - if ( _bi2 && _bi2 != _bi1 ) { - out << "best infeas. sol. #2 : x=( "; - _bi2->Point::display(out); - out << " )" - << " F(x)=[ " << _bi2->get_bb_outputs() << " ] h=" - << _bi2->get_h() << " f=" << _bi2->get_f() << endl; - } + if ( _rank != _np-1 ) + return; + + // stats: + out << "evaluations : " << size() << endl + << "multiple evaluations : " << _multiple_evals << endl + << "cache hits : " << _cache_hits << endl + << "cache search points : " << _cache_search_pts << endl; + + // best feasible solution: + out << "best feasible solution: "; + if ( _bf ) { + out << "x=( "; + _bf->Point::display(out); + out << " )" + << " F(x)=[ " << _bf->get_bb_outputs() << " ] h=" + << _bf->get_h() << " f=" << _bf->get_f() << endl; + } + else + out << "NULL" << endl; + + // best infeasible solutions: + if ( _bi1 ) { + out << "best infeas. sol. #1 : x=( "; + _bi1->Point::display(out); + out << " )" + << " F(x)=[ " << _bi1->get_bb_outputs() << " ] h=" + << _bi1->get_h() << " f=" << _bi1->get_f() << endl; + } + + if ( _bi2 && _bi2 != _bi1 ) { + out << "best infeas. sol. #2 : x=( "; + _bi2->Point::display(out); + out << " )" + << " F(x)=[ " << _bi2->get_bb_outputs() << " ] h=" + << _bi2->get_h() << " f=" << _bi2->get_f() << endl; + } } diff --git a/tools/COOP-MADS/main.cpp b/tools/COOP-MADS/main.cpp index 8345748..2b698d0 100644 --- a/tools/COOP-MADS/main.cpp +++ b/tools/COOP-MADS/main.cpp @@ -47,10 +47,8 @@ int main ( int argc , char ** argv ) { p.set_DISPLAY_DEGREE ( NO_DISPLAY ); p.set_DISPLAY_STATS ( "process #" + itos(rank) + " BBE OBJ" ); p.set_SEED ( get_pid() ); - - // these Halton seeds are valid for up to 1000 variables: - if ( rank != 0 ) - p.set_HALTON_SEED ( 7999 + 99*rank ); + + p.set_ANISOTROPIC_MESH(false); // cache search: p.set_CACHE_SEARCH ( USE_CACHE_SEARCH ); diff --git a/tools/COOP-MADS/problems/G2_10/runExample.log b/tools/COOP-MADS/problems/G2_10/runExample.log index 3546193..133b63d 100644 --- a/tools/COOP-MADS/problems/G2_10/runExample.log +++ b/tools/COOP-MADS/problems/G2_10/runExample.log @@ -2,28 +2,22 @@ TIME BBE OBJ 0 1 -0.001746040966254643 -0 2 -0.01019466859856645 -0 3 -0.01262929088633488 -0 4 -0.02737222459485665 -0 6 -0.03633168612260773 -0 8 -0.03649432351615038 -0 10 -0.06795149962330944 -0 13 -0.07360536752310878 -0 14 -0.09066696872825573 -0 25 -0.106549342247164 -0 32 -0.1145527897987842 -1 43 -0.1219426591809022 -1 44 -0.134377704552527 -1 48 -0.1582591392910043 -1 57 -0.1794716687140574 -2 68 -0.1954582060851584 -2 92 -0.1967787148730447 -2 100 -0.2074681592385568 -2 101 -0.2081555540466212 -6 101 -0.2081555540466212 +0 2 -0.08743509125381764 +0 3 -0.09502614738887308 +0 12 -0.1241414508378795 +0 13 -0.1243880456661476 +0 14 -0.1282392319163835 +0 17 -0.1473005317907833 +0 35 -0.150183285112481 +0 46 -0.1572895785336448 +0 65 -0.194312112152985 +1 99 -0.215523726538665 +2 100 -0.215523726538665 -evaluations : 101 +evaluations : 100 multiple evaluations : 0 -cache hits : 1507 -cache search points : 33 -best feasible solution: x=( 3 3 3 7 7 3 3 3 3 7 ) F(x)=[ -750140.25 -33 -0.2081555540466212 ] h=0 f=-0.2081555540466212 +cache hits : 1374 +cache search points : 26 +best feasible solution: x=( 9 8 6 3 6 3.5 3 3 5 3 ) F(x)=[ -3674159.25 -25.5 -0.215523726538665 ] h=0 f=-0.215523726538665 +best infeas. sol. #1 : x=( 6 10 8.5 8.5 7.5 0 5.5 0.5 6.5 3.5 ) F(x)=[ 0.75 -18.5 -0.1232423970453351 ] h=0.75 f=-0.1232423970453351 +best infeas. sol. #2 : x=( 5.5 9 9.5 2.5 6.5 1 0 2 5.5 5 ) F(x)=[ 0.75 -28.5 -0.1303069434264795 ] h=0.75 f=-0.1303069434264795 diff --git a/tools/COOP-MADS/problems/RHEOLOGY/runExample.log b/tools/COOP-MADS/problems/RHEOLOGY/runExample.log index ae57c2b..3342d27 100644 --- a/tools/COOP-MADS/problems/RHEOLOGY/runExample.log +++ b/tools/COOP-MADS/problems/RHEOLOGY/runExample.log @@ -2,125 +2,121 @@ TIME BBE OBJ 0 1 409.067422156616 -0 30 313.290666411087 -0 33 309.645062177308 -0 61 305.603554188662 -0 73 274.349745457906 -1 99 272.250128417616 -1 103 268.037284648273 -1 162 262.043368378846 -1 163 260.97381694916 -1 186 256.09850445141 -1 221 256.020492150343 -1 233 254.953534545783 -1 267 254.8720087317 -1 270 254.656322775826 -1 305 254.543645584072 -2 330 254.400682410755 -2 389 254.388049251401 -2 391 254.353067924927 -2 405 254.242240065196 -2 410 254.176238806978 -2 415 254.152120602604 -2 429 254.149410983437 -2 431 253.918898261246 -2 441 253.639818573328 -2 443 253.55474416257 -2 457 251.141461891318 -2 491 250.248064868682 -2 524 250.244171560004 -2 527 249.849164247345 -2 547 249.567222954085 -2 548 249.366239271189 -3 580 249.155498293568 -3 589 249.047280135277 -3 591 248.252066657473 -3 595 246.518827325057 -3 617 245.800965359953 -3 620 243.882335163937 -3 628 242.422501962147 -3 634 242.276927272015 -3 671 241.954108810511 -3 675 241.010585095445 -3 682 240.459307984963 -3 710 238.836934740093 -3 712 236.774345707808 -3 742 234.62986725466 -3 759 233.935408736368 -3 761 231.87366973145 -3 763 229.965932283635 -3 767 219.750264964398 -3 789 218.765266185861 -3 807 218.764685351186 -4 815 216.792767347362 -4 849 216.495270200364 -4 851 216.10267122674 -4 863 213.554832966872 -4 910 211.268885538006 -4 913 209.197077094276 -4 935 208.431462438035 -4 946 206.720752330144 -4 992 206.548275350849 -4 1013 206.178168852652 -4 1014 206.072252871052 -4 1015 205.053416198016 -4 1021 204.42785503742 -4 1023 202.520104744871 -4 1026 195.391180273313 -4 1029 177.49001293616 -4 1039 160.826983870132 -5 1062 160.272301645993 -5 1072 132.497730491384 -5 1095 132.211409945968 -5 1125 115.126136735852 -5 1142 103.410900663377 -5 1146 85.2425026449348 -5 1199 83.74223201807099 -5 1204 83.598074475476 -5 1230 71.84331120065551 -5 1237 70.29089492791761 -5 1260 66.3415584718624 -6 1309 65.7246434832216 -6 1313 60.1426677896144 -6 1350 58.9447055060385 -6 1351 55.614847308125 -6 1360 53.0178794687419 -6 1388 48.3232738347114 -6 1422 47.6627115940218 -6 1432 42.8248958769611 -6 1443 37.0265396215478 -6 1465 36.6923042836351 -6 1467 35.8124722457898 -7 1515 34.8258600812852 -7 1543 34.2676414158401 -7 1562 34.0364811732794 -7 1563 33.3484189173833 -7 1586 33.0532004059883 -7 1658 33.0035616836186 -7 1664 32.9776044737094 -7 1666 32.9093509482159 -8 1747 32.9056660232471 -8 1750 32.9049205755534 -8 1765 32.9003950798501 -8 1783 32.8983814142292 -8 1784 32.8884427141221 -8 1788 32.8680789470553 -8 1817 32.8557333071788 -8 1819 32.8409646841575 -8 1820 32.8187524114084 -8 1823 32.7593360339631 -8 1883 32.7588840107007 -8 1885 32.7575288245444 -8 1888 32.7521213326056 -8 1937 32.7512802945923 -8 1943 32.7503235466136 -8 1987 32.7498744681357 -8 1989 32.748528115889 -8 2000 32.7481266130554 -9 2001 32.7481266130554 +0 2 407.173143113625 +0 7 326.103515990633 +0 42 325.623426986692 +0 59 295.895440816156 +0 72 293.4555631559 +0 90 279.968263515696 +0 139 275.288266367226 +0 187 275.132352128014 +0 209 275.075795191333 +0 210 274.976333696773 +0 241 274.933105934363 +0 250 274.790628310616 +0 270 274.36972472876 +0 289 274.275563955637 +0 326 274.268484588901 +0 338 274.064933108817 +1 386 274.062269914507 +1 387 274.054281384837 +1 391 274.049026282641 +1 401 273.920837770762 +1 404 273.508720307709 +1 424 273.331822600277 +1 428 273.234004939865 +1 445 272.832477208338 +1 467 272.636358518916 +1 485 272.016936191517 +1 522 271.675223302068 +1 528 271.458245294985 +1 563 271.409843575617 +1 566 271.294040864725 +1 575 271.203751307945 +1 580 270.867285707472 +1 582 270.135910598837 +1 584 268.624704712738 +1 586 264.655640417888 +1 626 264.547329099114 +1 629 264.369411744322 +1 636 259.186132611454 +1 670 259.111109366001 +1 694 258.526885252145 +1 737 258.461782617644 +1 741 258.254128487816 +2 743 257.637827815885 +2 751 257.487467885692 +2 763 256.062079426438 +2 784 255.55667512634 +2 822 255.301356122905 +2 827 255.062123107245 +2 852 254.969793840294 +2 872 254.961280633716 +2 874 254.872629390701 +2 892 254.11730737943 +2 901 252.429482703112 +2 913 247.734161777393 +2 943 246.281383367226 +2 950 244.871940734504 +2 955 243.687522298512 +2 968 240.313783391124 +2 994 225.924186834258 +2 1027 225.375287811551 +2 1030 223.59959141347 +2 1033 214.372939666438 +2 1075 212.392129645385 +2 1079 202.458511181126 +3 1118 201.385729843192 +3 1121 200.414479846749 +3 1122 197.265532908615 +3 1130 196.484237748458 +3 1143 195.363761230687 +3 1150 194.180926892312 +3 1164 186.886694594438 +3 1229 186.775564288857 +3 1235 185.543088875516 +3 1247 184.315879020582 +3 1250 183.591281538454 +3 1251 180.585581615803 +3 1252 176.910717859633 +3 1256 151.835774047001 +3 1288 151.049164181499 +3 1289 143.621877654316 +3 1298 138.52428369358 +3 1300 130.977242901418 +3 1304 100.267474292617 +3 1325 99.71006688112919 +3 1363 94.56656135601661 +3 1379 79.3308117287512 +3 1411 62.8192798819504 +4 1413 57.1236275580665 +4 1433 45.5493739549428 +4 1482 44.5241434513005 +4 1485 42.8758586335358 +4 1494 40.173767108364 +4 1520 35.9160626502317 +4 1541 35.4706065363053 +4 1625 35.3985432229957 +4 1626 34.7705213812039 +4 1648 33.7365638550162 +4 1654 33.2736870837588 +4 1721 33.1821599854517 +4 1756 33.1640101150454 +4 1759 33.1094860838809 +5 1772 33.0242678796706 +5 1817 32.9941537610489 +5 1827 32.993685905707 +5 1860 32.9805924282463 +5 1912 32.9797736631138 +5 1936 32.979572485373 +5 1941 32.9794989828924 +5 1943 32.978674947399 +5 1980 32.9781395291375 +5 1983 32.9779413611568 +5 2001 32.9779413611568 evaluations : 2001 multiple evaluations : 0 -cache hits : 386 -cache search points : 230 -best feasible solution: x=( 5.176711478052312 3.06427162795444 9.47699431007095 ) F(x)=[ 32.7481266130554 ] h=0 f=32.7481266130554 +cache hits : 258 +cache search points : 221 +best feasible solution: x=( 5.167878504178415 3.051154465074881 9.460783454109679 ) F(x)=[ 32.9779413611568 ] h=0 f=32.9779413611568 diff --git a/tools/COOP-MADS/problems/RHEOLOGY/x0.txt b/tools/COOP-MADS/problems/RHEOLOGY/x0.txt index 6597ade..51fdf04 100644 --- a/tools/COOP-MADS/problems/RHEOLOGY/x0.txt +++ b/tools/COOP-MADS/problems/RHEOLOGY/x0.txt @@ -1,3 +1,3 @@ -10 -10 -10 +10 +10 +10 diff --git a/tools/PSD-MADS/Cache_Server.cpp b/tools/PSD-MADS/Cache_Server.cpp index a9568ce..96d4ff9 100644 --- a/tools/PSD-MADS/Cache_Server.cpp +++ b/tools/PSD-MADS/Cache_Server.cpp @@ -237,10 +237,11 @@ void Cache_Server::process_ep_signal ( int source ) const { itab[0] = n; itab[1] = m; itab[2] = ( x->is_eval_ok() ) ? 1 : 0; - const int * ell = x->get_mesh_index(); - if ( ell ) { - itab[3] = 1; - itab[4] = *ell; + + if ( x->get_signature() && (x->get_signature()->get_mesh()->get_mesh_indices())[0].is_defined() ) + { + itab[3]=1; + itab[4]=static_cast<int>((x->get_signature()->get_mesh()->get_mesh_indices())[0].value()); } else itab[3] = itab[4] = 0; @@ -540,9 +541,6 @@ void Cache_Server::process_insert_signal ( int source ) { x->set_eval_status ( ( itab[2] == 1 ) ? EVAL_OK : EVAL_FAIL ); - if ( itab[3] == 1 ) - x->set_mesh_index ( &itab[4] ); - // Eval_Point insertion in cache and multiple_evals detection: const Eval_Point * cache_x = Cache::find ( *x ); if ( cache_x ) { @@ -579,11 +577,12 @@ void Cache_Server::insert ( const NOMAD::Eval_Point & x ) { itab[0] = n; itab[1] = m; itab[2] = ( x.is_eval_ok() ) ? 1 : 0; - const int * ell = x.get_mesh_index(); - if ( ell ) { - itab[3] = 1; - itab[4] = *ell; - } + + if ( x.get_signature() && (x.get_signature()->get_mesh()->get_mesh_indices())[0].is_defined() ) + { + itab[3]=1; + itab[4]=static_cast<int>((x.get_signature()->get_mesh()->get_mesh_indices())[0].value()); + } else itab[3] = itab[4] = 0; @@ -692,9 +691,6 @@ const Eval_Point * Cache_Server::get_and_remove_extern_point ( void ) const { x->set_eval_status ( ( itab[2] == 1 ) ? EVAL_OK : EVAL_FAIL ); - if ( itab[3] == 1 ) - x->set_mesh_index ( &itab[4] ); - // insert the point in local cache: const Eval_Point * cache_x = Cache::find ( *x ); if ( cache_x ) { diff --git a/tools/PSD-MADS/Master_Slaves.cpp b/tools/PSD-MADS/Master_Slaves.cpp index b5229e9..52c5901 100644 --- a/tools/PSD-MADS/Master_Slaves.cpp +++ b/tools/PSD-MADS/Master_Slaves.cpp @@ -19,377 +19,381 @@ char Master_Slaves::OPTI_DATA_SIGNAL = 'D'; /* start the master (process 0) */ /*--------------------------------*/ void Master_Slaves::start ( void ) const { - - if ( _rank != 0 ) - return; - - MPI_Status status; - int source; - char signal; - int n = _p.get_dimension(); - int nb_stops = 0; - int pollster_mesh_index = 0; - bool stop_algo = false; - double * best_feasible = NULL; - - // the first best infeasible point is initialized with x0: - double * best_infeasible = new double [n+2]; - const Point * x0 = (_p.get_x0s())[0]; - for ( int i = 0 ; i < n ; ++i ) - best_infeasible[i] = (*x0)[i].value(); - best_infeasible[n ] = INF; - best_infeasible[n+1] = INF; - - /*-------------*/ - /* main loop */ - /*-------------*/ - while ( nb_stops != _np-2 ) { - - MPI_Recv ( &signal , 1 , MPI_CHAR , MPI_ANY_SOURCE , - Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD , &status ); - source = status.MPI_SOURCE; - - // stop signal: - // ------------ - if ( signal == Master_Slaves::STOP_SIGNAL ) { - if ( _debug ) { - _p.out() << "MASTER: STOP SIGNAL FROM RANK " << source; - if ( source == 1 ) - _p.out() << " (POLLSTER)"; - _p.out() << endl; - } - ++nb_stops; - } - - // optimization data signal: - // ------------------------- - else if ( signal == Master_Slaves::OPTI_DATA_SIGNAL ) { - if ( _debug ) { - _p.out() << "MASTER: receive optimization data request from slave " - << source; - if ( source == 1 ) - _p.out() << " (POLLSTER)"; - _p.out() << endl; - } - - send_optimization_data ( pollster_mesh_index , - stop_algo , - best_feasible , - best_infeasible , - source ); - } - - // optimization result signal: - // --------------------------- - else if ( signal == Master_Slaves::OPTI_RES_SIGNAL ) { - if ( _debug ) { - _p.out() << "MASTER: receive optimization result from slave " - << source; - if ( source == 1 ) - _p.out() << " (POLLSTER)"; - _p.out() << endl; - } - - // pollster: - if ( source == 1 ) - receive_optimization_result ( pollster_mesh_index , - stop_algo , - best_feasible , - best_infeasible , - source ); - - // other slaves: - else { - int tmp1; - bool tmp2; - receive_optimization_result ( tmp1 , - tmp2 , - best_feasible , - best_infeasible , - source ); - } + if ( _rank != 0 ) + return; + + MPI_Status status; + int source; + char signal; + int n = _p.get_dimension(); + int nb_stops = 0; + int pollster_mesh_index = 0; + bool stop_algo = false; + double * best_feasible = NULL; + + // the first best infeasible point is initialized with x0: + double * best_infeasible = new double [n+2]; + const Point * x0 = (_p.get_x0s())[0]; + for ( int i = 0 ; i < n ; ++i ) + best_infeasible[i] = (*x0)[i].value(); + best_infeasible[n ] = INF; + best_infeasible[n+1] = INF; + + /*-------------*/ + /* main loop */ + /*-------------*/ + while ( nb_stops != _np-2 ) { + + MPI_Recv ( &signal , 1 , MPI_CHAR , MPI_ANY_SOURCE , + Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD , &status ); + + source = status.MPI_SOURCE; + + // stop signal: + // ------------ + if ( signal == Master_Slaves::STOP_SIGNAL ) { + if ( _debug ) { + _p.out() << "MASTER: STOP SIGNAL FROM RANK " << source; + if ( source == 1 ) + _p.out() << " (POLLSTER)"; + _p.out() << endl; + } + ++nb_stops; + } + + // optimization data signal: + // ------------------------- + else if ( signal == Master_Slaves::OPTI_DATA_SIGNAL ) { + if ( _debug ) { + _p.out() << "MASTER: receive optimization data request from slave " + << source; + if ( source == 1 ) + _p.out() << " (POLLSTER)"; + _p.out() << endl; + } + + send_optimization_data ( pollster_mesh_index , + stop_algo , + best_feasible , + best_infeasible , + source ); + } + + // optimization result signal: + // --------------------------- + else if ( signal == Master_Slaves::OPTI_RES_SIGNAL ) { + if ( _debug ) { + _p.out() << "MASTER: receive optimization result from slave " + << source; + if ( source == 1 ) + _p.out() << " (POLLSTER)"; + _p.out() << endl; + } + + // pollster: + if ( source == 1 ) + receive_optimization_result ( pollster_mesh_index , + stop_algo , + best_feasible , + best_infeasible , + source ); + + // other slaves: + else { + int tmp1; + bool tmp2; + receive_optimization_result ( tmp1 , + tmp2 , + best_feasible , + best_infeasible , + source ); + } + } } - } - - if ( best_feasible ) - delete [] best_feasible; - if ( best_infeasible ) - delete [] best_infeasible; + + if ( best_feasible ) + delete [] best_feasible; + if ( best_infeasible ) + delete [] best_infeasible; } /*------------------------------------------*/ /* stop the master (processes 1 to _np-2) */ /*------------------------------------------*/ - void Master_Slaves::stop ( void ) const { - if ( _rank == 0 || _rank == _np-1 ) - return; - - MPI_Send ( &Master_Slaves::STOP_SIGNAL , 1 , MPI_CHAR , - 0 , Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD ); +void Master_Slaves::stop ( void ) const { + if ( _rank == 0 || _rank == _np-1 ) + return; + + MPI_Send ( &Master_Slaves::STOP_SIGNAL , 1 , MPI_CHAR , + 0 , Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD ); } /*----------------------------------------*/ /* MADS run */ /*----------------------------------------*/ void Master_Slaves::mads_run ( Cache & cache ) { - - const Eval_Point * best_feasible = NULL; - const Eval_Point * best_infeasible = NULL; - Double old_f = INF; - bool stop_algo = false; - int run_index = 0; - int mesh_index = 0; - double default_eps = Double::get_epsilon(); - int n = _p.get_dimension(); - int * free_vars = new int [_ns]; - Point x0 ( n ) , delta_0 , delta_min; - - /*---------------------*/ - /* main loop */ - /*---------------------*/ - while ( !stop_algo ) { - best_feasible = NULL; - best_infeasible = NULL; - - // random SEED: - _p.set_SEED ( get_pid() + run_index ); - - // Halton seed: - _p.set_HALTON_SEED ( 7999 + 99 * _rank + 20 * run_index ); + const Eval_Point * best_feasible = NULL; + const Eval_Point * best_infeasible = NULL; + Double old_f = INF; + bool stop_algo = false; + int run_index = 0; + int mesh_index = 0; + double default_eps = Double::get_epsilon(); + int n = _p.get_dimension(); + int * free_vars = new int [_ns]; + Point x0 ( n ) , delta_0 , delta_min; - // first run: - if ( run_index == 0 ) { - - // max number of evaluations for regular slaves: - if ( _rank != 1 ) - _p.set_MAX_BB_EVAL ( _bbe ); - - // display: - // p.set_DISPLAY_STATS ( "process #" + itos(_rank) + " BBE OBJ" ); - // p.set_DISPLAY_DEGREE ( FULL_DISPLAY ); - _p.set_DISPLAY_DEGREE ( NO_DISPLAY ); - } - - // force the parameters check: - _p.force_check_flag(); - - /*------------------*/ - /* pollster slave */ - /*------------------*/ - if ( _rank == 1 ) { - - stop_type stop_reason = UNKNOWN_STOP_REASON; - - Mesh::get_delta_m ( delta_0 , - _initial_mesh_size , - _mesh_update_basis , - _initial_mesh_index , - mesh_index ); - - // we set a very small epsilon in order to accept - // very small initial mesh sizes: - Double::set_epsilon ( 1e-16 ); - - if ( !check_delta ( delta_0 ) ) - stop_algo = true; - - else { - - // first run: - if ( run_index == 0 ) { - - // directions: - { - int halton_seed = _p.get_halton_seed(); - bool use_orthomads = _p.has_orthomads_directions(); - _p.reset_directions ( halton_seed ); - _p.set_DIRECTION_TYPE ( (use_orthomads) ? ORTHO_1 : LT_1 ); - } - - // cache search: - _p.set_CACHE_SEARCH ( true ); - _p.set_OPPORTUNISTIC_CACHE_SEARCH ( false ); - } - - // other runs: - else { - - // stop_algo may be set to 'false' here: - receive_optimization_data ( stop_algo , x0 , old_f ); - - // starting point: - _p.reset_X0(); - _p.set_X0 ( x0 ); - } - - if ( !stop_algo ) { - - // pollster mesh: - _p.set_INITIAL_MESH_INDEX ( mesh_index ); - _p.set_MAX_MESH_INDEX ( mesh_index ); - _p.set_INITIAL_MESH_SIZE ( delta_0 ); - _p.set_MIN_MESH_SIZE ( delta_0 ); - - // check the parameters: - _p.check(); - Double::set_epsilon ( default_eps ); - - Mads mads ( _p , NULL , NULL , &cache , NULL ); - stop_reason = mads.run(); - best_feasible = mads.get_best_feasible(); - best_infeasible = mads.get_best_infeasible(); - - bool success = false; - - if ( best_feasible ) { - - success = (best_feasible->get_f() < old_f); - - if ( _debug ) - _p.out() << "POLLSTER: ELL=" - << mesh_index << " BBE=" - << mads.get_stats().get_bb_eval() - << " OLD_F=" << old_f << " NEW_F=" - << best_feasible->get_f() - << " SUCCESS=" << success << endl; - } - - // pollster mesh update: - if ( success ) - --mesh_index; - else - ++mesh_index; - } - } - - send_optimization_result ( mesh_index , - stop_algo , - best_feasible , - best_infeasible , - stop_reason ); + /*---------------------*/ + /* main loop */ + /*---------------------*/ + while ( !stop_algo ) { + + best_feasible = NULL; + best_infeasible = NULL; + + // Seed: + _p.set_SEED ( 99 * _rank + 20 * run_index ); + + // first run: + if ( run_index == 0 ) { + + // max number of evaluations for regular slaves: + if ( _rank != 1 ) + _p.set_MAX_BB_EVAL ( _bbe ); + + // display: + // p.set_DISPLAY_STATS ( "process #" + itos(_rank) + " BBE OBJ" ); + // p.set_DISPLAY_DEGREE ( FULL_DISPLAY ); + _p.set_DISPLAY_DEGREE ( NO_DISPLAY ); + } + + // force the parameters check: + _p.force_check_flag(); + + /*------------------*/ + /* pollster slave */ + /*------------------*/ + if ( _rank == 1 ) { + + stop_type stop_reason = UNKNOWN_STOP_REASON; + + _p.check(); // must do check to get a valid signature + _p.get_signature()->get_mesh()->set_mesh_indices( NOMAD::Point( n,mesh_index ) ); + delta_0=_p.get_signature()->get_mesh()->get_delta ( ); + + + + // we set a very small epsilon in order to accept + // very small initial mesh sizes: + Double::set_epsilon ( 1e-16 ); + + if ( !check_delta ( delta_0 ) ) + stop_algo = true; + + else { + + // first run: + if ( run_index == 0 ) { + + // directions: + { + bool use_orthomads = _p.has_orthomads_directions(); + _p.reset_directions ( ); + _p.set_DIRECTION_TYPE ( (use_orthomads) ? ORTHO_1 : LT_1 ); + } + + // cache search: + _p.set_CACHE_SEARCH ( true ); + _p.set_OPPORTUNISTIC_CACHE_SEARCH ( false ); + } + + // other runs: + else { + + // stop_algo may be set to 'false' here: + receive_optimization_data ( stop_algo , x0 , old_f ); + + // starting point: + _p.reset_X0(); + _p.set_X0 ( x0 ); + } + + if ( !stop_algo ) { + + // check the parameters: + _p.check(); + + _p.get_signature()->get_mesh()->set_min_mesh_sizes( delta_0 ); + + if ( mesh_index <= 0 ) + _p.get_signature()->get_mesh()->set_limit_mesh_index ( mesh_index ); + else + _p.get_signature()->get_mesh()->set_limit_mesh_index ( 0 ); + + Double::set_epsilon ( default_eps ); + + Mads mads ( _p , NULL , NULL , &cache , NULL ); + stop_reason = mads.run(); + best_feasible = mads.get_best_feasible(); + best_infeasible = mads.get_best_infeasible(); + + bool success = false; + + if ( best_feasible ) { + + success = (best_feasible->get_f() < old_f); + + if ( _debug ) + _p.out() << "POLLSTER: ELL=" + << mesh_index << " BBE=" + << mads.get_stats().get_bb_eval() + << " OLD_F=" << old_f << " NEW_F=" + << best_feasible->get_f() + << " SUCCESS=" << success << endl; + } + + // pollster mesh update: + if ( success ) + ++mesh_index; + else + --mesh_index; + + } + } + + send_optimization_result ( mesh_index , + stop_algo , + best_feasible , + best_infeasible , + stop_reason ); + } + + /*------------------*/ + /* regular slaves */ + /*------------------*/ + else { + + int i , j , pollster_mesh_index; + + receive_optimization_data ( stop_algo , + x0 , + old_f , + pollster_mesh_index , + free_vars ); + + if ( _debug ) { + _p.out() << "SLAVE #" << _rank + << ": OPTIM. DATA: [STOP=" << stop_algo + << "] [POLLSTER_MESH_INDEX=" << pollster_mesh_index + << "] [X0=" << x0 << " ] [f(X0)=" + << old_f << "] [FREE VARS= "; + for ( i = 0 ; i < _ns ; ++i ) + _p.out() << free_vars[i] << " "; + _p.out() << " ]" << endl; + } + + if ( !stop_algo ) { + + // starting point: + _p.reset_X0(); + _p.set_X0 ( x0 ); + + // mesh of the regular slave: + int ell_0 = 0; + if ( pollster_mesh_index > ell_0 ) + ell_0 = pollster_mesh_index; + + _p.check(); // Must do check to access signature + _p.get_signature()->get_mesh()->set_mesh_indices( NOMAD::Point( n,ell_0 ) ); + delta_0=_p.get_signature()->get_mesh()->get_delta(); + + _p.get_signature()->get_mesh()->set_mesh_indices( NOMAD::Point( n ,pollster_mesh_index ) ); + delta_min=_p.get_signature()->get_mesh()->get_delta(); + + + + Double::set_epsilon ( 1e-16 ); + if ( !check_delta ( delta_0 ) || !check_delta ( delta_min ) ) + stop_algo = true; + + else { + + + + // free variables: + { + _p.reset_fixed_variables(); + bool fix_var; + for ( i = 0 ; i < n ; ++i ) { + fix_var = true; + for ( j = 0 ; j < _ns ; ++j ) + if ( free_vars[j] == i ) { + fix_var = false; + break; + } + if ( fix_var ) + _p.set_FIXED_VARIABLE ( i ); + } + } + + // check the parameters: + _p.check(); + + // modify mesh termination criterions + _p.get_signature()->get_mesh()->set_mesh_indices( NOMAD::Point( n,ell_0 ) ); + + if ( pollster_mesh_index <=0 ) + _p.get_signature()->get_mesh()->set_limit_mesh_index( pollster_mesh_index ); + else + _p.get_signature()->get_mesh()->set_limit_mesh_index( 0 ); + + _p.get_signature()->get_mesh()->set_min_mesh_sizes( delta_min ); + _p.get_signature()->get_mesh()->set_delta_0 ( delta_0 ); + + + + Double::set_epsilon ( default_eps ); + + // MADS run: + Mads mads ( _p , NULL , NULL , &cache , NULL ); + mads.run(); + best_feasible = mads.get_best_feasible(); + best_infeasible = mads.get_best_infeasible(); + + if ( _debug && best_feasible ) { + _p.out() << "RANK #" << _rank << ": POLLSTER_ELL=" + << pollster_mesh_index << " VARS = ["; + for ( i = 0 ; i < _ns ; ++i ) + _p.out() << free_vars[i] << " "; + _p.out() << " ] BBE=" << mads.get_stats().get_bb_eval() + << " OLD_F=" << old_f << " NEW_F=" + << best_feasible->get_f() + << " SUCCESS=" + << (best_feasible->get_f() < old_f) + << endl; + } + } + } + + { + int tmp1 = -1; + bool tmp2 = false; + stop_type tmp3 = UNKNOWN_STOP_REASON; + send_optimization_result ( tmp1 , + tmp2 , + best_feasible , + best_infeasible , + tmp3 ); + } + } + + // loop increment: + ++run_index; } - /*------------------*/ - /* regular slaves */ - /*------------------*/ - else { - - int i , j , pollster_mesh_index; - - receive_optimization_data ( stop_algo , - x0 , - old_f , - pollster_mesh_index , - free_vars ); - - if ( _debug ) { - _p.out() << "SLAVE #" << _rank - << ": OPTIM. DATA: [STOP=" << stop_algo - << "] [POLLSTER_MESH_INDEX=" << pollster_mesh_index - << "] [X0=" << x0 << " ] [f(X0)=" - << old_f << "] [FREE VARS= "; - for ( i = 0 ; i < _ns ; ++i ) - _p.out() << free_vars[i] << " "; - _p.out() << " ]" << endl; - } - - if ( !stop_algo ) { - - // starting point: - _p.reset_X0(); - _p.set_X0 ( x0 ); - - // mesh of the regular slave: - int ell_0 = 0; - if ( pollster_mesh_index < ell_0 ) - ell_0 = pollster_mesh_index; - - - Mesh::get_delta_m ( delta_0 , - _initial_mesh_size , - _mesh_update_basis , - _initial_mesh_index , - ell_0 ); - - Mesh::get_delta_m ( delta_min , - _initial_mesh_size , - _mesh_update_basis , - _initial_mesh_index , - pollster_mesh_index ); - - - Double::set_epsilon ( 1e-16 ); - if ( !check_delta ( delta_0 ) || !check_delta ( delta_min ) ) - stop_algo = true; - - else { - - // mesh of the regular slave: - _p.set_INITIAL_MESH_INDEX ( ell_0 ); - _p.set_MAX_MESH_INDEX ( pollster_mesh_index ); - _p.set_INITIAL_MESH_SIZE ( delta_0 ); - _p.set_MIN_MESH_SIZE ( delta_min ); - - // free variables: - { - _p.reset_fixed_variables(); - bool fix_var; - for ( i = 0 ; i < n ; ++i ) { - fix_var = true; - for ( j = 0 ; j < _ns ; ++j ) - if ( free_vars[j] == i ) { - fix_var = false; - break; - } - if ( fix_var ) - _p.set_FIXED_VARIABLE ( i ); - } - } - - // check the parameters: - _p.check(); - Double::set_epsilon ( default_eps ); - - // MADS run: - Mads mads ( _p , NULL , NULL , &cache , NULL ); - mads.run(); - best_feasible = mads.get_best_feasible(); - best_infeasible = mads.get_best_infeasible(); - - if ( _debug && best_feasible ) { - _p.out() << "RANK #" << _rank << ": POLLSTER_ELL=" - << pollster_mesh_index << " VARS = ["; - for ( i = 0 ; i < _ns ; ++i ) - _p.out() << free_vars[i] << " "; - _p.out() << " ] BBE=" << mads.get_stats().get_bb_eval() - << " OLD_F=" << old_f << " NEW_F=" - << best_feasible->get_f() - << " SUCCESS=" - << (best_feasible->get_f() < old_f) - << endl; - } - } - } - - { - int tmp1 = -1; - bool tmp2 = false; - stop_type tmp3 = UNKNOWN_STOP_REASON; - send_optimization_result ( tmp1 , - tmp2 , - best_feasible , - best_infeasible , - tmp3 ); - } - } - - // loop increment: - ++run_index; - } - - delete [] free_vars; + delete [] free_vars; } /*----------------------------------------------------*/ @@ -397,155 +401,155 @@ void Master_Slaves::mads_run ( Cache & cache ) { /* POLLSTER --> MASTER */ /*----------------------------------------------------*/ void Master_Slaves::receive_optimization_result - ( int & pollster_mesh_index , - bool & stop_algo , - double *& best_feasible , - double *& best_infeasible , - int source ) const { - - int itab[5]; - MPI_Status status; - - MPI_Recv ( itab , 5 , MPI_INT , source , - Master_Slaves::TAG_I1 , MPI_COMM_WORLD , &status ); - - pollster_mesh_index = itab[0]; - - // stop the algorithm ? - stop_algo = ( itab[4] == 1 ); - - if ( !stop_algo ) { - - stop_type stop_reason = static_cast<stop_type>(itab[1]); - - switch ( stop_reason ) { - case ERROR: - case UNKNOWN_STOP_REASON: - case CTRL_C: - case MESH_PREC_REACHED: - case X0_FAIL: - case P1_FAIL: - case L_MAX_REACHED: - case L_LIMITS_REACHED: - case MAX_TIME_REACHED: - case MAX_BB_EVAL_REACHED: - case MAX_SGTE_EVAL_REACHED: - case MAX_EVAL_REACHED: - case MAX_SIM_BB_EVAL_REACHED: - case MAX_ITER_REACHED: - case FEAS_REACHED: - case F_TARGET_REACHED: - case STAT_SUM_TARGET_REACHED: - case L_CURVE_TARGET_REACHED: - case MULTI_MAX_BB_REACHED: - case MULTI_NB_MADS_RUNS_REACHED: - case MULTI_STAGNATION: - case MULTI_NO_PARETO_PTS: - case MAX_CACHE_MEMORY_REACHED: - stop_algo = true; - default: - stop_algo = false; - } - } - - int i , nb_pts = 0; - if ( itab[2] == 1 ) - ++nb_pts; - if ( itab[3] == 1 ) - ++nb_pts; - - // itab[2] == 1 --> bf != NULL - // itab[3] == 1 --> bi != NULL - - if ( nb_pts > 0 ) { - - int n = _p.get_dimension(); - double * rtab = new double [(n+2)*nb_pts]; - - MPI_Recv ( rtab , (n+2)*nb_pts , MPI_DOUBLE , source , - Master_Slaves::TAG_R1 , MPI_COMM_WORLD , &status ); - - if ( nb_pts == 2 ) { - - // best feasible and infeasible updates: - bool update = false; - - if ( best_feasible ) { - Double old_f = best_feasible[n+1]; - Double new_f = rtab [n+1]; - if ( new_f < old_f ) - update = true; - } - else { - best_feasible = new double[n+2]; - update = true; - } - - if ( update ) { - for ( i = 0 ; i < n ; ++i ) - best_feasible[i] = rtab[i]; - best_feasible[n ] = rtab[n]; - best_feasible[n+1] = rtab[n+1]; - } - - update = false; - - if ( best_infeasible ) { - - Double old_h = best_infeasible[n]; - Double new_h = rtab [2*n+2]; - if ( new_h < old_h ) - update = true; - } - else { - best_infeasible = new double[n+2]; - update = true; - } - - if ( update ) { - int cur = n+2; - for ( i = 0 ; i < n ; ++i ) - best_infeasible[i] = rtab[cur++]; - best_infeasible[n ] = rtab[cur++]; - best_infeasible[n+1] = rtab[cur]; - } - delete [] rtab; +( int & pollster_mesh_index , + bool & stop_algo , + double *& best_feasible , + double *& best_infeasible , + int source ) const { + + int itab[5]; + MPI_Status status; + + MPI_Recv ( itab , 5 , MPI_INT , source , + Master_Slaves::TAG_I1 , MPI_COMM_WORLD , &status ); + + pollster_mesh_index = itab[0]; + + // stop the algorithm ? + stop_algo = ( itab[4] == 1 ); + + if ( !stop_algo ) { + + stop_type stop_reason = static_cast<stop_type>(itab[1]); + + switch ( stop_reason ) { + case ERROR: + case UNKNOWN_STOP_REASON: + case CTRL_C: + case MESH_PREC_REACHED: + case X0_FAIL: + case P1_FAIL: + case L_MAX_REACHED: + case L_LIMITS_REACHED: + case MAX_TIME_REACHED: + case MAX_BB_EVAL_REACHED: + case MAX_SGTE_EVAL_REACHED: + case MAX_EVAL_REACHED: + case MAX_SIM_BB_EVAL_REACHED: + case MAX_ITER_REACHED: + case FEAS_REACHED: + case F_TARGET_REACHED: + case STAT_SUM_TARGET_REACHED: + case L_CURVE_TARGET_REACHED: + case MULTI_MAX_BB_REACHED: + case MULTI_NB_MADS_RUNS_REACHED: + case MULTI_STAGNATION: + case MULTI_NO_PARETO_PTS: + case MAX_CACHE_MEMORY_REACHED: + stop_algo = true; + default: + stop_algo = false; + } } - else { - - // best feasible update: - if ( itab[2] == 1 ) { - if ( best_feasible ) { - Double old_f = best_feasible[n+1]; - Double new_f = rtab [n+1]; - if ( new_f < old_f ) { - delete [] best_feasible; - best_feasible = rtab; - } - else - delete [] rtab; - } - else - best_feasible = rtab; - } - - // best infeasible update: - else { - if ( best_infeasible ) { - Double old_h = best_infeasible[n]; - Double new_h = rtab [n]; - if ( new_h < old_h ) { - delete [] best_infeasible; - best_infeasible = rtab; - } - else - delete [] rtab; - } - else - best_infeasible = rtab; - } + + int i , nb_pts = 0; + if ( itab[2] == 1 ) + ++nb_pts; + if ( itab[3] == 1 ) + ++nb_pts; + + // itab[2] == 1 --> bf != NULL + // itab[3] == 1 --> bi != NULL + + if ( nb_pts > 0 ) { + + int n = _p.get_dimension(); + double * rtab = new double [(n+2)*nb_pts]; + + MPI_Recv ( rtab , (n+2)*nb_pts , MPI_DOUBLE , source , + Master_Slaves::TAG_R1 , MPI_COMM_WORLD , &status ); + + if ( nb_pts == 2 ) { + + // best feasible and infeasible updates: + bool update = false; + + if ( best_feasible ) { + Double old_f = best_feasible[n+1]; + Double new_f = rtab [n+1]; + if ( new_f < old_f ) + update = true; + } + else { + best_feasible = new double[n+2]; + update = true; + } + + if ( update ) { + for ( i = 0 ; i < n ; ++i ) + best_feasible[i] = rtab[i]; + best_feasible[n ] = rtab[n]; + best_feasible[n+1] = rtab[n+1]; + } + + update = false; + + if ( best_infeasible ) { + + Double old_h = best_infeasible[n]; + Double new_h = rtab [2*n+2]; + if ( new_h < old_h ) + update = true; + } + else { + best_infeasible = new double[n+2]; + update = true; + } + + if ( update ) { + int cur = n+2; + for ( i = 0 ; i < n ; ++i ) + best_infeasible[i] = rtab[cur++]; + best_infeasible[n ] = rtab[cur++]; + best_infeasible[n+1] = rtab[cur]; + } + delete [] rtab; + } + else { + + // best feasible update: + if ( itab[2] == 1 ) { + if ( best_feasible ) { + Double old_f = best_feasible[n+1]; + Double new_f = rtab [n+1]; + if ( new_f < old_f ) { + delete [] best_feasible; + best_feasible = rtab; + } + else + delete [] rtab; + } + else + best_feasible = rtab; + } + + // best infeasible update: + else { + if ( best_infeasible ) { + Double old_h = best_infeasible[n]; + Double new_h = rtab [n]; + if ( new_h < old_h ) { + delete [] best_infeasible; + best_infeasible = rtab; + } + else + delete [] rtab; + } + else + best_infeasible = rtab; + } + } } - } } /*---------------------------------------------*/ @@ -553,67 +557,67 @@ void Master_Slaves::receive_optimization_result /* POLLSTER --> MASTER */ /*---------------------------------------------*/ void Master_Slaves::send_optimization_result - ( int pollster_mesh_index , - bool stop_algo , - const Eval_Point * bf , - const Eval_Point * bi , - stop_type st ) const { - - // send a signal to the master: - MPI_Send ( &Master_Slaves::OPTI_RES_SIGNAL , 1 , MPI_CHAR , - 0 , Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD ); - - // send the data: - int itab[5]; - - itab[0] = pollster_mesh_index; - itab[1] = static_cast<int>(st); - - int nb_pts = 0; - if ( bf ) { - ++nb_pts; - itab[2] = 1; - } - else - itab[2] = 0; - - if ( bi ) { - ++nb_pts; - itab[3] = 1; - } - else - itab[3] = 0; - - itab[4] = (stop_algo) ? 1 : 0; - - MPI_Send ( itab , 5 , MPI_INT , 0 , - Master_Slaves::TAG_I1 , MPI_COMM_WORLD ); - - if ( nb_pts > 0 ) { - - int n = _p.get_dimension(); - double * rtab = new double [(n+2)*nb_pts]; - - int i , cur = 0; +( int pollster_mesh_index , + bool stop_algo , + const Eval_Point * bf , + const Eval_Point * bi , + stop_type st ) const { + + // send a signal to the master: + MPI_Send ( &Master_Slaves::OPTI_RES_SIGNAL , 1 , MPI_CHAR , + 0 , Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD ); + + // send the data: + int itab[5]; + + itab[0] = pollster_mesh_index; + itab[1] = static_cast<int>(st); + + int nb_pts = 0; if ( bf ) { - for ( i = 0 ; i < n ; ++i ) - rtab[cur++] = (*bf)[i].value(); - rtab[cur++] = bf->get_h().value(); - rtab[cur++] = bf->get_f().value(); + ++nb_pts; + itab[2] = 1; } - + else + itab[2] = 0; + if ( bi ) { - for ( i = 0 ; i < n ; ++i ) - rtab[cur++] = (*bi)[i].value(); - rtab[cur++] = bi->get_h().value(); - rtab[cur ] = bi->get_f().value(); + ++nb_pts; + itab[3] = 1; + } + else + itab[3] = 0; + + itab[4] = (stop_algo) ? 1 : 0; + + MPI_Send ( itab , 5 , MPI_INT , 0 , + Master_Slaves::TAG_I1 , MPI_COMM_WORLD ); + + if ( nb_pts > 0 ) { + + int n = _p.get_dimension(); + double * rtab = new double [(n+2)*nb_pts]; + + int i , cur = 0; + if ( bf ) { + for ( i = 0 ; i < n ; ++i ) + rtab[cur++] = (*bf)[i].value(); + rtab[cur++] = bf->get_h().value(); + rtab[cur++] = bf->get_f().value(); + } + + if ( bi ) { + for ( i = 0 ; i < n ; ++i ) + rtab[cur++] = (*bi)[i].value(); + rtab[cur++] = bi->get_h().value(); + rtab[cur ] = bi->get_f().value(); + } + + MPI_Send ( rtab , cur , MPI_DOUBLE , 0 , + Master_Slaves::TAG_R1 , MPI_COMM_WORLD ); + + delete [] rtab; } - - MPI_Send ( rtab , cur , MPI_DOUBLE , 0 , - Master_Slaves::TAG_R1 , MPI_COMM_WORLD ); - - delete [] rtab; - } } /*---------------------------------------------*/ @@ -622,37 +626,37 @@ void Master_Slaves::send_optimization_result /*---------------------------------------------*/ void Master_Slaves::receive_optimization_data ( bool & stop_algo , - Point & x0 , - Double & fx0 , - int & pollster_mesh_index , - int * free_vars ) const { - - // step 1/2: receive common pollster data: - receive_optimization_data ( stop_algo , x0 , fx0 ); - - int i; - - // step 2/2: receive additional data for regular slaves: - if ( !stop_algo ) { - - int * itab = new int [_ns+1]; - MPI_Status status; - - MPI_Recv ( itab , _ns+1 , MPI_INT , 0 , - Master_Slaves::TAG_I2 , MPI_COMM_WORLD , &status ); - - for ( i = 0 ; i < _ns ; ++i ) - free_vars[i] = itab[i]; - - pollster_mesh_index = itab[_ns]; - - delete [] itab; - } - else { - pollster_mesh_index = -1; - for ( i = 0 ; i < _ns ; ++i ) - free_vars[i] = -1; - } + Point & x0 , + Double & fx0 , + int & pollster_mesh_index , + int * free_vars ) const { + + // step 1/2: receive common pollster data: + receive_optimization_data ( stop_algo , x0 , fx0 ); + + int i; + + // step 2/2: receive additional data for regular slaves: + if ( !stop_algo ) { + + int * itab = new int [_ns+1]; + MPI_Status status; + + MPI_Recv ( itab , _ns+1 , MPI_INT , 0 , + Master_Slaves::TAG_I2 , MPI_COMM_WORLD , &status ); + + for ( i = 0 ; i < _ns ; ++i ) + free_vars[i] = itab[i]; + + pollster_mesh_index = itab[_ns]; + + delete [] itab; + } + else { + pollster_mesh_index = 1; + for ( i = 0 ; i < _ns ; ++i ) + free_vars[i] = -1; + } } /*---------------------------------------------*/ @@ -660,82 +664,82 @@ void Master_Slaves::receive_optimization_data /* MASTER --> POLLSTER */ /*---------------------------------------------*/ void Master_Slaves::receive_optimization_data ( bool & stop_algo , - Point & x0 , - Double & fx0 ) const { - char c_stop; - MPI_Status status; - MPI_Request req = MPI_REQUEST_NULL; - int i , n = _p.get_dimension(); - - // send a request for c_stop: - MPI_Irecv ( &c_stop , 1 , MPI_CHAR , 0 , - Master_Slaves::TAG_CSTOP , MPI_COMM_WORLD , &req ); - - // send a signal to the master: - MPI_Send ( &Master_Slaves::OPTI_DATA_SIGNAL , 1 , MPI_CHAR , - 0 , Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD ); - - MPI_Wait ( &req , &status ); - - // stop: - if ( c_stop == '1' ) { - stop_algo = true; - x0.reset(); - } - - // continue: - else { - - stop_algo = false; - double * rtab = new double [n+2]; + Point & x0 , + Double & fx0 ) const { + char c_stop; + MPI_Status status; + MPI_Request req = MPI_REQUEST_NULL; + int i , n = _p.get_dimension(); - MPI_Recv ( rtab , n+2 , MPI_DOUBLE , 0 , - Master_Slaves::TAG_D1 , MPI_COMM_WORLD , &status ); - - for ( i = 0 ; i < n ; ++i ) - x0[i] = rtab[i]; + // send a request for c_stop: + MPI_Irecv ( &c_stop , 1 , MPI_CHAR , 0 , + Master_Slaves::TAG_CSTOP , MPI_COMM_WORLD , &req ); - Double h = rtab[n]; - fx0 = ( h <= _p.get_h_min() ) ? rtab[n+1] : INF; - - // get the best feasible point from the cache server: - { - char pt_flag; - int npm1 = _np-1; - MPI_Irecv ( &pt_flag , 1 , MPI_CHAR , npm1 , - Cache_Server::TAG_BF , MPI_COMM_WORLD , &req ); - - MPI_Send ( &Cache_Server::BF_SIGNAL , 1 , MPI_CHAR , - npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); - - MPI_Wait ( &req , &status ); - - if ( pt_flag == '1' ) { - - MPI_Recv ( rtab , n+2 , MPI_DOUBLE , npm1 , - Cache_Server::TAG_X7 , MPI_COMM_WORLD , &status ); - - for ( i = 0 ; i < n ; ++i ) - x0[i] = rtab[i]; - - Double h = rtab[n]; - fx0 = ( h <= _p.get_h_min() ) ? rtab[n+1] : INF; - - } + // send a signal to the master: + MPI_Send ( &Master_Slaves::OPTI_DATA_SIGNAL , 1 , MPI_CHAR , + 0 , Master_Slaves::TAG_SIGNAL , MPI_COMM_WORLD ); + + MPI_Wait ( &req , &status ); + + // stop: + if ( c_stop == '1' ) { + stop_algo = true; + x0.reset(); } - delete [] rtab; - - // check the bounds: - const Point & lb = _p.get_lb(); - const Point & ub = _p.get_ub(); - - for ( i = 0 ; i < n ; ++i ) { - if ( lb[i].is_defined() && x0[i].value() < lb[i].value() ) - x0[i] = lb[i]; - if ( ub[i].is_defined() && x0[i].value() > ub[i].value() ) - x0[i] = ub[i]; + + // continue: + else { + + stop_algo = false; + double * rtab = new double [n+2]; + + MPI_Recv ( rtab , n+2 , MPI_DOUBLE , 0 , + Master_Slaves::TAG_D1 , MPI_COMM_WORLD , &status ); + + for ( i = 0 ; i < n ; ++i ) + x0[i] = rtab[i]; + + Double h = rtab[n]; + fx0 = ( h <= _p.get_h_min() ) ? rtab[n+1] : INF; + + // get the best feasible point from the cache server: + { + char pt_flag; + int npm1 = _np-1; + MPI_Irecv ( &pt_flag , 1 , MPI_CHAR , npm1 , + Cache_Server::TAG_BF , MPI_COMM_WORLD , &req ); + + MPI_Send ( &Cache_Server::BF_SIGNAL , 1 , MPI_CHAR , + npm1 , Cache_Server::TAG_SIGNAL , MPI_COMM_WORLD ); + + MPI_Wait ( &req , &status ); + + if ( pt_flag == '1' ) { + + MPI_Recv ( rtab , n+2 , MPI_DOUBLE , npm1 , + Cache_Server::TAG_X7 , MPI_COMM_WORLD , &status ); + + for ( i = 0 ; i < n ; ++i ) + x0[i] = rtab[i]; + + Double h = rtab[n]; + fx0 = ( h <= _p.get_h_min() ) ? rtab[n+1] : INF; + + } + } + delete [] rtab; + + // check the bounds: + const Point & lb = _p.get_lb(); + const Point & ub = _p.get_ub(); + + for ( i = 0 ; i < n ; ++i ) { + if ( lb[i].is_defined() && x0[i].value() < lb[i].value() ) + x0[i] = lb[i]; + if ( ub[i].is_defined() && x0[i].value() > ub[i].value() ) + x0[i] = ub[i]; + } } - } } /*-----------------------------------------------------*/ @@ -744,61 +748,61 @@ void Master_Slaves::receive_optimization_data ( bool & stop_algo , /*-----------------------------------------------------*/ void Master_Slaves::send_optimization_data ( int pollster_mesh_index , - bool stop_algo , - const double * best_feasible , - const double * best_infeasible , - int source ) const { - - char c_stop = (stop_algo) ? '1' : '0'; - - MPI_Rsend ( &c_stop , 1 , MPI_CHAR , source , - Master_Slaves::TAG_CSTOP , MPI_COMM_WORLD ); - - // continue: - if ( !stop_algo ) { + bool stop_algo , + const double * best_feasible , + const double * best_infeasible , + int source ) const { - int n = _p.get_dimension(); - - // data for pollster and regular slaves: - if ( best_feasible ) - MPI_Send ( const_cast<double*>(best_feasible) , n+2 , MPI_DOUBLE , - source , Master_Slaves::TAG_D1 , MPI_COMM_WORLD ); - else - MPI_Send ( const_cast<double*>(best_infeasible) , n+2 , MPI_DOUBLE , - source , Master_Slaves::TAG_D1 , MPI_COMM_WORLD ); - - // additional data for regular slaves: - if ( source != 1 ) { - - int * itab = new int [_ns+1]; - - // choose the free varables: - { - Random_Pickup rp ( n ); - - for ( int i = 0 ; i < _ns ; ++i ) - itab[i] = rp.pickup(); // index of the ith free variable - } - - itab[_ns] = pollster_mesh_index; - - MPI_Send ( itab , _ns+1 , MPI_INT , source , - Master_Slaves::TAG_I2 , MPI_COMM_WORLD ); - - delete [] itab; + char c_stop = (stop_algo) ? '1' : '0'; + + MPI_Rsend ( &c_stop , 1 , MPI_CHAR , source , + Master_Slaves::TAG_CSTOP , MPI_COMM_WORLD ); + + // continue: + if ( !stop_algo ) { + + int n = _p.get_dimension(); + + // data for pollster and regular slaves: + if ( best_feasible ) + MPI_Send ( const_cast<double*>(best_feasible) , n+2 , MPI_DOUBLE , + source , Master_Slaves::TAG_D1 , MPI_COMM_WORLD ); + else + MPI_Send ( const_cast<double*>(best_infeasible) , n+2 , MPI_DOUBLE , + source , Master_Slaves::TAG_D1 , MPI_COMM_WORLD ); + + // additional data for regular slaves: + if ( source != 1 ) { + + int * itab = new int [_ns+1]; + + // choose the free varables: + { + Random_Pickup rp ( n ); + + for ( int i = 0 ; i < _ns ; ++i ) + itab[i] = rp.pickup(); // index of the ith free variable + } + + itab[_ns] = pollster_mesh_index; + + MPI_Send ( itab , _ns+1 , MPI_INT , source , + Master_Slaves::TAG_I2 , MPI_COMM_WORLD ); + + delete [] itab; + } } - } } /*-----------------------------------------------*/ /* check the initial mesh size values */ /*-----------------------------------------------*/ bool Master_Slaves::check_delta ( const Point & delta ) { - int n = delta.size(); - for ( int i = 0 ; i < n ; ++i ) - if ( delta[i].value() < Double::get_epsilon() || - delta[i].value() <= 0.0 ) - return false; - return true; + int n = delta.size(); + for ( int i = 0 ; i < n ; ++i ) + if ( delta[i].value() < Double::get_epsilon() || + delta[i].value() <= 0.0 ) + return false; + return true; } - + diff --git a/tools/PSD-MADS/Master_Slaves.hpp b/tools/PSD-MADS/Master_Slaves.hpp index ef298ed..33eb386 100644 --- a/tools/PSD-MADS/Master_Slaves.hpp +++ b/tools/PSD-MADS/Master_Slaves.hpp @@ -20,10 +20,6 @@ private: Parameters & _p; // parameters bool _debug; // debug display flag - Point _initial_mesh_size; // used for mesh sizes computations - double _mesh_update_basis; - int _initial_mesh_index; - static const int TAG_SIGNAL; static const int TAG_I1; static const int TAG_I2; @@ -83,10 +79,7 @@ public: _bbe ( bbe ) , _ns ( ns ) , _p ( p ) , - _debug ( debug ) , - _initial_mesh_size ( p.get_initial_mesh_size() ) , - _mesh_update_basis ( p.get_mesh_update_basis().value() ) , - _initial_mesh_index ( p.get_initial_mesh_index() ) {} + _debug ( debug ) {} // Destructor: virtual ~Master_Slaves ( void ) {} diff --git a/tools/PSD-MADS/main.cpp b/tools/PSD-MADS/main.cpp index 516c8f6..5d9122b 100644 --- a/tools/PSD-MADS/main.cpp +++ b/tools/PSD-MADS/main.cpp @@ -65,6 +65,11 @@ int main ( int argc , char ** argv ) { // read the parameters file: p.read ( argv[1] ); + + + // Force anisotropy(false) to have a single mesh_index (XMesh) + p.set_ANISOTROPIC_MESH ( false ); + // check the parameters: p.check(); diff --git a/tools/PSD-MADS/problems/G2_10/runExample.log b/tools/PSD-MADS/problems/G2_10/runExample.log index d19b8d8..77b68db 100644 --- a/tools/PSD-MADS/problems/G2_10/runExample.log +++ b/tools/PSD-MADS/problems/G2_10/runExample.log @@ -1,107 +1,34 @@ - mpirun -np 4 ../../psdmads.exe param.txt 2 3 TIME BBE OBJ 0 1 -0.001746040966254643 -0 2 -0.02813866582027356 -0 4 -0.03246494243742246 -0 5 -0.03500916329442131 -0 6 -0.03979188572323358 -0 7 -0.04911024464431659 -0 8 -0.0624744264055816 -0 15 -0.07048573066714986 -0 17 -0.07913640207892171 -0 18 -0.2767691552979534 -0 32 -0.2840652234097061 -1 37 -0.3467264619146415 -1 47 -0.3616531939153783 -1 51 -0.3629746044080329 -1 53 -0.3784626616521393 -1 67 -0.4007959643190014 -1 76 -0.4011229010993316 -1 84 -0.4032331127256472 -1 87 -0.403470848334701 -1 90 -0.4037279807054211 -1 95 -0.4041302132836239 -1 100 -0.4048613086583342 -1 107 -0.4053884600639073 -1 120 -0.4069087605072449 -1 131 -0.4072285704612035 -2 151 -0.4077863530293669 -2 152 -0.4086685803184945 -2 158 -0.4130919348061188 -2 170 -0.4137304728713846 -2 172 -0.4148496666566134 -2 176 -0.4191250251192655 -2 182 -0.4200033998088014 -2 205 -0.4208641998228952 -3 206 -0.4225719140558536 -3 215 -0.4228472348980148 -3 217 -0.424356641202593 -3 218 -0.4257196697168721 -3 224 -0.4353114259472481 -3 235 -0.4384297542906666 -3 249 -0.4428448864268232 -3 259 -0.4452338309063813 -3 268 -0.4454447130476139 -3 274 -0.4463397444771921 -3 276 -0.44789418940056 -3 284 -0.4480311333354084 -3 294 -0.4518803988674263 -3 310 -0.4541110520311777 -4 338 -0.4554487138353737 -4 349 -0.4555011463355874 -4 371 -0.4671811067309874 -4 376 -0.4681242182210517 -4 379 -0.4682305982863977 -4 385 -0.470523423605836 -4 397 -0.4736991861621658 -5 407 -0.4795311288186103 -5 408 -0.4831426791267522 -5 422 -0.4858641762962093 -5 424 -0.4879898135606146 -5 432 -0.4887503548786935 -5 433 -0.4890297740218854 -5 437 -0.4940686510588005 -5 441 -0.4994879542195462 -5 453 -0.4996398710974662 -5 467 -0.5120558920079147 -5 486 -0.5156106481361489 -5 494 -0.5184315095785024 -5 496 -0.5226683626664205 -6 509 -0.5280449547858778 -6 512 -0.5383933309117888 -6 523 -0.5429439408280063 -6 533 -0.5543908904333605 -6 537 -0.5632007867272643 -6 541 -0.5671878178220834 -7 583 -0.5761420295747868 -7 604 -0.6084769206498875 -8 610 -0.6113445698633692 -8 639 -0.6144597698235708 -8 645 -0.629444227845865 -8 647 -0.6313958500255352 -8 648 -0.6360620644111428 -8 651 -0.6422846491448985 -8 654 -0.6459778341618972 -8 663 -0.6460135265779767 -8 674 -0.6465276784852958 -8 680 -0.6505834588791414 -8 690 -0.659017324207901 -9 716 -0.6629043685717967 -10 758 -0.6846542316250898 -11 799 -0.6848344023953686 -11 800 -0.6853069561564632 -11 801 -0.6861970681378093 -11 804 -0.6878053210464737 -11 805 -0.6916807972008618 -11 810 -0.6993985430379386 -14 872 -0.7015922046101486 -18 964 -0.7038488494934669 -18 968 -0.7044602723295867 -18 969 -0.7058578026145313 -20 1000 -0.7058578026145313 -evaluations: 1000 -cache hits : 323 -best feasible solution: x=( 3.0462646484375 3.1387939453125 3.0379638671875 2.962646484375 0.6630859375 1.3421630859375 0.35400390625 0.1610107421875 0.398193359375 0.4324951171875 ) F(x)=[ -0.001806557213181849 -59.46337890625 -0.7058578026145313 ] h=0 f=-0.7058578026145313 - +0 2 -0.1020265638285207 +0 6 -0.1441632798005752 +0 15 -0.1542510749518172 +0 22 -0.1577316768630335 +0 37 -0.183989373943974 +0 38 -0.2020008666180557 +0 39 -0.2129271506181529 +0 40 -0.2361644054928127 +1 75 -0.2374148796747058 +1 94 -0.2603035160235741 +1 116 -0.2684048733308141 +2 174 -0.2821001936977113 +3 212 -0.2866228068210581 +4 298 -0.2898075435824587 +4 322 -0.316703796586124 +5 350 -0.338651875099582 +6 412 -0.3480692693344858 +7 506 -0.4056438193796689 +8 550 -0.4404750660164174 +9 598 -0.4453605848005951 +11 758 -0.4502266934808508 +12 780 -0.4606308402126712 +12 794 -0.4678396551609023 +12 804 -0.4864410201396533 +13 836 -0.5028952047514585 +15 961 -0.513267791679749 +29 1001 -0.513267791679749 +evaluations: 1001 +cache hits : 14460 +best feasible solution: x=( 3.125 3.125 3.25 1.5 2.375 0.25 2.625 0.125 0.5 0.875 ) F(x)=[ -3.307846963405609 -57.25 -0.513267791679749 ] h=0 f=-0.513267791679749 diff --git a/tools/SENSITIVITY/detailed_analysis/detailed_analysis.cpp b/tools/SENSITIVITY/detailed_analysis/detailed_analysis.cpp index c2d03c7..b8db6f5 100644 --- a/tools/SENSITIVITY/detailed_analysis/detailed_analysis.cpp +++ b/tools/SENSITIVITY/detailed_analysis/detailed_analysis.cpp @@ -332,7 +332,6 @@ void create_new_parameters ( const NOMAD::Parameters & p0 , p.set_ADD_SEED_TO_FILE_NAMES ( p0.get_add_seed_to_file_names() ); p.set_DIRECTION_TYPE ( p0.get_direction_types() ); p.set_SEC_POLL_DIR_TYPE ( p0.get_sec_poll_dir_types() ); - p.set_HALTON_SEED ( p0.get_halton_seed() ); p.set_OPPORTUNISTIC_EVAL ( p0.get_opportunistic_eval() ); p.set_OPPORTUNISTIC_MIN_NB_SUCCESS ( p0.get_opportunistic_min_nb_success() ); p.set_OPPORTUNISTIC_MIN_EVAL ( p0.get_opportunistic_min_eval() ); diff --git a/tools/SENSITIVITY/problems/cube/detailed/param.txt b/tools/SENSITIVITY/problems/cube/detailed/param.txt index 8939c25..849595d 100644 --- a/tools/SENSITIVITY/problems/cube/detailed/param.txt +++ b/tools/SENSITIVITY/problems/cube/detailed/param.txt @@ -6,5 +6,5 @@ LOWER_BOUND [0 0 0] UPPER_BOUND [2 2 2] # tmp_dir /tmp #max_bb_eval 500 -#multi_overall_bb_eval 500 +multi_overall_bb_eval 500 #multi_nb_mads_runs 5 diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/RungeKutta.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/RungeKutta.cpp index e9112bd..53236ea 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/RungeKutta.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/RungeKutta.cpp @@ -1,80 +1,80 @@ -#include "RungeKutta.hpp" - -#include <iomanip> - -using namespace std; - -template <class E> -RungeKutta<E>::RungeKutta(int dim) -{ - m = dim; - k1 = new double[m]; - k2 = new double[m]; - k3 = new double[m]; - k4 = new double[m]; - y = new double[m]; - y_tmp = new double[m]; -} - -template <class E> -RungeKutta<E>::~RungeKutta() -{ - delete [] k1; - delete [] k2; - delete [] k3; - delete [] k4; - delete [] y; - delete [] y_tmp; -} - -template <class E> -void RungeKutta<E>::set ( E * tmp , double * y0 , double beg , double end ) -{ - unit=tmp; - x0=beg; xn=end; - x=x0; - h=double(xn-x0)/double(N_INTER); - for (i=0;i<m;i++) {y[i]=y0[i];} - success=true; -} - -template <class E> -bool RungeKutta<E>::run() { - for(j=0;j<MAX_ITER_RK;j++) { - //Avoid going out of x interval - if (x+h >xn) { - h = xn-x; - j = MAX_ITER_RK; - } - - //Compute k1, k2, k3, k4 - for(i=0;i<m;i++) - k1[i] = h*unit->f(i, x, y); - for(i=0;i<m;i++) - y_tmp[i] = y[i]+k1[i]/2.0; - for(i=0;i<m;i++) - k2[i] = h*unit->f(i, x+h/2.0, y_tmp); - for(i=0;i<m;i++) - y_tmp[i] = y[i]+k2[i]/2.0; - for(i=0;i<m;i++) - k3[i] = h*unit->f(i, x+h/2.0, y_tmp); - for(i=0;i<m;i++) - y_tmp[i] = y[i]+k3[i]; - for ( i = 0 ; i < m ; i++ ) - k4[i] = h*unit->f ( i , x+h , y_tmp ); - //Compute the new y - for(i=0;i<m;i++) - y[i]+=(k1[i]+2*k2[i]+2*k3[i]+k4[i])/6.0; - x += h; - } - - if ( x < xn-EPS ) {// MODIF SEB (le EPS) - success=false; - - // cout.setf(ios::fixed); - // cout << setprecision(12); - // cout << "x=" << x << " < xn=" << xn << " diff=" << xn-x << endl; - } - - return success; -} +#include "RungeKutta.hpp" + +#include <iomanip> + +using namespace std; + +template <class E> +RungeKutta<E>::RungeKutta(int dim) +{ + m = dim; + k1 = new double[m]; + k2 = new double[m]; + k3 = new double[m]; + k4 = new double[m]; + y = new double[m]; + y_tmp = new double[m]; +} + +template <class E> +RungeKutta<E>::~RungeKutta() +{ + delete [] k1; + delete [] k2; + delete [] k3; + delete [] k4; + delete [] y; + delete [] y_tmp; +} + +template <class E> +void RungeKutta<E>::set ( E * tmp , double * y0 , double beg , double end ) +{ + unit=tmp; + x0=beg; xn=end; + x=x0; + h=double(xn-x0)/double(N_INTER); + for (i=0;i<m;i++) {y[i]=y0[i];} + success=true; +} + +template <class E> +bool RungeKutta<E>::run() { + for(j=0;j<MAX_ITER_RK;j++) { + //Avoid going out of x interval + if (x+h >xn) { + h = xn-x; + j = MAX_ITER_RK; + } + + //Compute k1, k2, k3, k4 + for(i=0;i<m;i++) + k1[i] = h*unit->f(i, x, y); + for(i=0;i<m;i++) + y_tmp[i] = y[i]+k1[i]/2.0; + for(i=0;i<m;i++) + k2[i] = h*unit->f(i, x+h/2.0, y_tmp); + for(i=0;i<m;i++) + y_tmp[i] = y[i]+k2[i]/2.0; + for(i=0;i<m;i++) + k3[i] = h*unit->f(i, x+h/2.0, y_tmp); + for(i=0;i<m;i++) + y_tmp[i] = y[i]+k3[i]; + for ( i = 0 ; i < m ; i++ ) + k4[i] = h*unit->f ( i , x+h , y_tmp ); + //Compute the new y + for(i=0;i<m;i++) + y[i]+=(k1[i]+2*k2[i]+2*k3[i]+k4[i])/6.0; + x += h; + } + + if ( x < xn-EPS ) {// MODIF SEB (le EPS) + success=false; + + // cout.setf(ios::fixed); + // cout << setprecision(12); + // cout << "x=" << x << " < xn=" << xn << " diff=" << xn-x << endl; + } + + return success; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/RungeKutta.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/RungeKutta.hpp index db2b3c2..2400753 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/RungeKutta.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/RungeKutta.hpp @@ -1,37 +1,37 @@ -/* -To use the Runge-Kutta solver for systems of first order differential equations, - (the parametric object E must have public function such as E->f(i,x,y), - where i is the index of the function to evaluate, x is the time and - y is a point such as y(x), returns values of differential equation i) - - 1- construct the solver : solver = new RungeKutta<objet>(int); //the integer is the dimension of x - 2- set the solver : solver->set(unit, y0, x0, xn); //unit is usually the pointer *this, y0 are the initial conditions, and x0 and xn is the time interval - 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed???????????????????????????? - 4- delete the solver : delete solver; -(ref :Fortin) -*/ -#ifndef RUNGEKUTTA_H -#define RUNGEKUTTA_H - -#include "defines.hpp" -using namespace std; - -template <class E> -class RungeKutta -{ -private: - double *k1, *k2, *k3, *k4, *y_tmp, *y; - // double k1[MAX_DIM], k2[MAX_DIM], k3[MAX_DIM], k4[MAX_DIM], y_tmp[MAX_DIM], y[MAX_DIM]; - double h, x0, xn, x; - int i, j, m; - bool success; - E *unit; - -public: - RungeKutta(int); - ~RungeKutta(); - void set(E*, double*, double, double); - double dx(){return h;} - bool run(); -}; -#endif +/* +To use the Runge-Kutta solver for systems of first order differential equations, + (the parametric object E must have public function such as E->f(i,x,y), + where i is the index of the function to evaluate, x is the time and + y is a point such as y(x), returns values of differential equation i) + + 1- construct the solver : solver = new RungeKutta<objet>(int); //the integer is the dimension of x + 2- set the solver : solver->set(unit, y0, x0, xn); //unit is usually the pointer *this, y0 are the initial conditions, and x0 and xn is the time interval + 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed???????????????????????????? + 4- delete the solver : delete solver; +(ref :Fortin) +*/ +#ifndef RUNGEKUTTA_H +#define RUNGEKUTTA_H + +#include "defines.hpp" +using namespace std; + +template <class E> +class RungeKutta +{ +private: + double *k1, *k2, *k3, *k4, *y_tmp, *y; + // double k1[MAX_DIM], k2[MAX_DIM], k3[MAX_DIM], k4[MAX_DIM], y_tmp[MAX_DIM], y[MAX_DIM]; + double h, x0, xn, x; + int i, j, m; + bool success; + E *unit; + +public: + RungeKutta(int); + ~RungeKutta(); + void set(E*, double*, double, double); + double dx(){return h;} + bool run(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/bissection.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/bissection.cpp index 60e3d38..d23a939 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/bissection.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/bissection.cpp @@ -1,27 +1,27 @@ -#include "bissection.hpp" -using namespace std; - -template <class E> -bool bissection<E>::run() -{ - for (i=1; i<MAX_ITER_BISSECTION; i++) - { - xm=(x1+x2)/2; - // if(DEBUG) cout<<endl<<x1<<" "<<xm<<" "<<x2; - if (fabs(x1-x2)/fabs(xm) < TOL_BISSECTION) - { - i=MAX_ITER_BISSECTION; - OK=true; - } - else - { - f1 = unit->f(x1); - fm = unit->f(xm); - f2 = unit->f(x2); - if (f1*fm < 0.0) x2 = xm; - if (fm*f2 < 0.0) x1 = xm; - } - } - // if (DEBUG) system("pause"); - return OK; -} +#include "bissection.hpp" +using namespace std; + +template <class E> +bool bissection<E>::run() +{ + for (i=1; i<MAX_ITER_BISSECTION; i++) + { + xm=(x1+x2)/2; + // if(DEBUG) cout<<endl<<x1<<" "<<xm<<" "<<x2; + if (fabs(x1-x2)/fabs(xm) < TOL_BISSECTION) + { + i=MAX_ITER_BISSECTION; + OK=true; + } + else + { + f1 = unit->f(x1); + fm = unit->f(xm); + f2 = unit->f(x2); + if (f1*fm < 0.0) x2 = xm; + if (fm*f2 < 0.0) x1 = xm; + } + } + // if (DEBUG) system("pause"); + return OK; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/bissection.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/bissection.hpp index c277e29..18d4ee6 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/bissection.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/bissection.hpp @@ -1,31 +1,31 @@ -/* -To use the bissection solver to find the root of a scalar function -when the secant solver fails. - (the parametric object E must have public function such as E->f(x), - where x is the point at which evaluate f.) - 1- construct the solver : solver = new bissect<E>(); - 2- set the solver : solver->set(unit, x0, x1); //unit is usually the pointer *this, and x0 and x1 are the interval's bounds - 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed -*/ -#ifndef BISSECTION_H -#define BISSECTION_H - -#include "defines.hpp" -using namespace std; - -template <class E> -class bissection { -private: - double x1, xm, x2; - double f1, fm, f2; - int i; - bool OK; - E *unit; - -public: - bissection(){x1=xm=x2=f1=fm=f2=0; OK=false;} - void set(E* tmp, double xx1, double xx2) {unit=tmp; x1=xx1; x2=xx2;} - bool run(); - ~bissection(){} -}; -#endif +/* +To use the bissection solver to find the root of a scalar function +when the secant solver fails. + (the parametric object E must have public function such as E->f(x), + where x is the point at which evaluate f.) + 1- construct the solver : solver = new bissect<E>(); + 2- set the solver : solver->set(unit, x0, x1); //unit is usually the pointer *this, and x0 and x1 are the interval's bounds + 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed +*/ +#ifndef BISSECTION_H +#define BISSECTION_H + +#include "defines.hpp" +using namespace std; + +template <class E> +class bissection { +private: + double x1, xm, x2; + double f1, fm, f2; + int i; + bool OK; + E *unit; + +public: + bissection(){x1=xm=x2=f1=fm=f2=0; OK=false;} + void set(E* tmp, double xx1, double xx2) {unit=tmp; x1=xx1; x2=xx2;} + bool run(); + ~bissection(){} +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/burner.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/burner.cpp index eb8a223..1b6f36b 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/burner.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/burner.cpp @@ -1,287 +1,287 @@ -#include "burner.hpp" -using namespace std; - -/*----------------------------------------------------------*/ -/* arrondi pour ne conserver que n chiffres significatifs */ -/*----------------------------------------------------------*/ -double arrondi ( double x , int n ) { - if (fabs(x) < EPS) - return 0.0; - double m = pow ( 10 , ceil(-log10(x)) + n - 1 ); - return round(m*x)/m; -} - -/*---------------------------------------------------------------*/ -burner::burner ( int nb , chemical ** chem ) { - - rem_nb = nb; - - NO=NO2=N2O=CO=0.0; - m = new double[nb]; - can_burn = new bool[nb]; - - // combustion.prop : - // ----------------- - // 64-17-5 3 2 3 - // 74-82-8 2 1 2 - // 1333-74-0 0.5 0 1 - // 100-42-5 10 8 4 - // 74-85-1 3 2 2 - // 108-88-3 9 7 4 - // 100-41-4 10.5 8 5 - // 71-43-2 7.5 6 3 - - for ( i = 0 ; i < nb ; i++ ) { - - can_burn[i] = false; - - if ( chem[i]->CAS == "64-17-5" || - chem[i]->CAS == "74-82-8" || - chem[i]->CAS == "1333-74-0" || - chem[i]->CAS == "100-42-5" || - chem[i]->CAS == "74-85-1" || - chem[i]->CAS == "108-88-3" || - chem[i]->CAS == "100-41-4" || - chem[i]->CAS == "71-43-2" ) - can_burn[i] = true; - } - - O2 = new chemical ("7782-44-7"); - N2 = new chemical ("7727-37-9"); - CO2 = new chemical ("124-38-9"); - H2O = new chemical ("7732-18-5"); - - // Construct the rx array; - rx = new combrx * [nb]; - for ( i = 0 ; i < nb ; i++ ) { - if ( can_burn[i] ) - rx[i] = new combrx ( chem[i]->CAS ); - else - rx[i] = NULL; - } -} - -/*---------------------------------------------------------------*/ -burner::~burner ( void ) { - - delete [] m; - delete [] can_burn; - - for ( i = 0 ; i < rem_nb ; i++ ) - if (rx[i]) - delete rx[i]; - delete [] rx; - - delete O2; - delete N2; - delete CO2; - delete H2O; -} - -/*---------------------------------------------------------------*/ -bool burner::solve(double * y) -{ - OK=true; - //perform mass balance (neglect pollutants flows) - out->m = 0.0; - for(i=0;i<in->nb;i++) - { - if (!can_burn[i]) { - out->chem[i]->m = in->chem[i]->m; - out->m+=out->chem[i]->m; - } - else { - out->chem[i]->m=0.0; - O2->m+=rx[i]->O2_flow()*in->chem[i]->n(); - N2->m+=rx[i]->N2_flow()*in->chem[i]->n(); - CO2->m+=rx[i]->CO2_flow()*in->chem[i]->n(); - H2O->m+=rx[i]->H2O_flow()*in->chem[i]->n(); - } - } - N2->m*=(1.0+eta); - O2->m*=(1.0+eta); - //perform energy balance to find Tout - T = in->T; - - step=10; - Q=1; - // find temperature - while (fabs(step)>TOL_BURN && fabs(Q)>TOL_BURN && T<MAX_TEMP) - { - T+=step; - - if(T>MAX_TEMP) - T=MAX_TEMP; - Q = 0.0; - for ( i = 0 ; i < in->nb ; i++ ) - Q += in->chem[i]->dH ( in->T , T , in->P ) * in->chem[i]->n(); - - for ( i = 0 ; i < in->nb ; i++ ) - if ( can_burn[i] ) - Q += rx[i]->Hcomb(T) * in->chem[i]->n(); - - Q += O2->dH ( 293 , T , in->P ) * O2->n(); - Q += N2->dH ( 293 , T , in->P ) * N2->n(); - - - if (step/fabs(step)*Q >0) - step*= -0.1; - else if (fabs(Q)<10) - step*=0.25; - - } - - - - out->set_thermo(in->thermo); - // out->thermo = in->thermo; - - out->set(in->P, T); - O2->P=in->P; O2->T=T; O2->state=1; O2->find_v(); - N2->P=in->P; N2->T=T; N2->state=1; N2->find_v(); - CO2->P=in->P; CO2->T=T; CO2->state=1; CO2->find_v(); - H2O->P=in->P; H2O->T=T; H2O->state=1; H2O->find_v(); - //check if mixture can burn - m_can_burn = 0.0; - for(i=0;i<in->nb;i++) if(can_burn[i]) m_can_burn+=in->chem[i]->n(); - LFLmix=0.0; - for(i=0;i<in->nb;i++) if(can_burn[i]) LFLmix+=in->chem[i]->n()/m_can_burn*rx[i]->LFL(in->P,T); - UFLmix=0.0; - for(i=0;i<in->nb;i++) if(can_burn[i]) UFLmix+=in->chem[i]->n()/m_can_burn*rx[i]->UFL(in->P,T); - num = 0.0; - buff=in->T; in->set(in->P, T); - for(i=0;i<in->nb;i++) if(can_burn[i]) num+=in->chem[i]->n()/in->n()*in->v; - in->set(in->P, buff); - den = O2->v+N2->v+out->v; - composition = num/den; - if(!(LFLmix<=composition && composition<=UFLmix) || T==MAX_TEMP) - { -// logf.open(MESSAGES,ios::app); -// logf<<" --> Warning <-- Mixture in "<<name<<" can't burn (LFL="<<LFLmix -// <<" UFL="<<UFLmix<<" x="<<composition<<").\n"; -// logf.close(); - T=in->T; - filename = out->name; - *out=*in; - out->set(filename); - // out->write(); // WRITE TOTO - OK=false; - } - else - { - O2->P=in->P; O2->T=T; O2->state=1; O2->find_v(); - N2->P=in->P; N2->T=T; N2->state=1; N2->find_v(); - // out->write(); // WRITE TOTO - } - if(OK) //compute the pollutants production - { - fill_K_array(); - NO = 1e6*sqrt(K[0]*(N2->n()/den)*(O2->n()/den))*den*0.03/(O2->m+N2->m+out->m+H2O->m+CO2->m); - N2O = 1e6*K[1]*(N2->n()/den)*sqrt(O2->n()/den)*den*0.044/(O2->m+N2->m+out->m+H2O->m+CO2->m); - NO2 = 1e6*K[2]*sqrt(N2->n()/den)*(O2->n()/den)*den*0.046/(O2->m+N2->m+out->m+H2O->m+CO2->m); - CO = 1e6*K[3]*(CO2->n()/den)*den/sqrt(O2->n()/den)*0.028/(O2->m+N2->m+out->m+H2O->m+CO2->m); - } -// logf.open(MESSAGES,ios::app); - if (NO>EPS && NO2>EPS && N2O>EPS) { - // logf<<" --> Warning <-- Presence of NOx: "<<(NO+NO2+N2O)<<" ppm in "<<name<<".\n"; - y[7] = NO+NO2+N2O; - - if (ARRONDI) - y[7] = arrondi ( y[7] , 6 ); - - } - if (CO>EPS) { - // logf<<" --> Warning <-- Presence of CO: "<<CO<<" ppm in "<<name<<".\n"; - y[8] = CO; - if (ARRONDI) - y[8] = arrondi ( y[8] , 6 ); - - } -// logf.close(); - return OK; -} - -void burner::fill_K_array() -{ - a[0]=1.0; a[1]=1.0; a[2]=0.5; a[3]=1.0; - b[0]=1.0; b[1]=0.5; b[2]=1.0; b[3]=-0.5; - c[0]=2.0; c[1]=1.0; c[2]=1.0; c[3]=1.0; - K[0] = exp(-120.27*(173.38-T*0.012)/T); - K[1] = exp(-120.27*(103.64+T*0.074)/T); - K[2] = exp(-120.27*(51.96+T*0.061)/T); - K[3] = exp(-120.27*(283.84-T*0.087)/T); - for(i=0;i<4;i++) - K[i]*=pow(1000, c[i]-a[i]-b[i]); -} - -void burner::write() { - - cout << setprecision(6); - - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout << "\t>> " << name; - cout << endl << "\t>> stream in : " << in->name; - cout << endl << "\t>> streams out : " << out->name; - cout << endl << "\t>> P = " << in->P << " atm, T(in) = " << in->T - << " T(out) = " << T << " K"; - O2->P = 1; - O2->T = 293; - O2->state = 1; - O2->find_v(); - N2->P=1; - N2->T=293; - N2->state=1; - N2->find_v(); - cout << endl << "\t>> Required air flow = " - << (O2->m+N2->m) << " kg/s (" << (O2->v+N2->v) << " m3/s)"; - O2->P=in->P; - O2->T=T; - O2->state=1; - O2->find_v(); - N2->P=in->P; - N2->T=T; - N2->state=1; - N2->find_v(); - step=(eta*O2->v/(1+eta)+N2->v+H2O->v+CO2->v+out->v); - cout << endl << "\t>> Total flue gases = " - << (out->m+CO2->m+H2O->m+N2->m+eta*O2->m/(1+eta)) - <<" kg/s (" << step << " m3/s)"; - cout << "\n\tEND\n\n"; - cost(); -} - - -double burner::get_cost ( void ) { - - - O2->P = 1; - O2->T = 293; - O2->state = 1; - O2->find_v(); - N2->P=1; - N2->T=293; - N2->state=1; - N2->find_v(); - O2->P=in->P; - O2->T=T; - O2->state=1; - O2->find_v(); - N2->P=in->P; - N2->T=T; - N2->state=1; - N2->find_v(); - step=(eta*O2->v/(1+eta)+N2->v+H2O->v+CO2->v+out->v); - - buff = 3.1761-0.1373*log10(step) + 0.3414*pow(log10(step),2); - buff = 2.7*pow(10, buff); - buff = buff*MS_YEAR/MS_2001; - - return buff; -} - - -void burner::cost ( void ) { - cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} +#include "burner.hpp" +using namespace std; + +/*----------------------------------------------------------*/ +/* arrondi pour ne conserver que n chiffres significatifs */ +/*----------------------------------------------------------*/ +double arrondi ( double x , int n ) { + if (fabs(x) < EPS) + return 0.0; + double m = pow ( 10 , ceil(-log10(x)) + n - 1 ); + return round(m*x)/m; +} + +/*---------------------------------------------------------------*/ +burner::burner ( int nb , chemical ** chem ) { + + rem_nb = nb; + + NO=NO2=N2O=CO=0.0; + m = new double[nb]; + can_burn = new bool[nb]; + + // combustion.prop : + // ----------------- + // 64-17-5 3 2 3 + // 74-82-8 2 1 2 + // 1333-74-0 0.5 0 1 + // 100-42-5 10 8 4 + // 74-85-1 3 2 2 + // 108-88-3 9 7 4 + // 100-41-4 10.5 8 5 + // 71-43-2 7.5 6 3 + + for ( i = 0 ; i < nb ; i++ ) { + + can_burn[i] = false; + + if ( chem[i]->CAS == "64-17-5" || + chem[i]->CAS == "74-82-8" || + chem[i]->CAS == "1333-74-0" || + chem[i]->CAS == "100-42-5" || + chem[i]->CAS == "74-85-1" || + chem[i]->CAS == "108-88-3" || + chem[i]->CAS == "100-41-4" || + chem[i]->CAS == "71-43-2" ) + can_burn[i] = true; + } + + O2 = new chemical ("7782-44-7"); + N2 = new chemical ("7727-37-9"); + CO2 = new chemical ("124-38-9"); + H2O = new chemical ("7732-18-5"); + + // Construct the rx array; + rx = new combrx * [nb]; + for ( i = 0 ; i < nb ; i++ ) { + if ( can_burn[i] ) + rx[i] = new combrx ( chem[i]->CAS ); + else + rx[i] = NULL; + } +} + +/*---------------------------------------------------------------*/ +burner::~burner ( void ) { + + delete [] m; + delete [] can_burn; + + for ( i = 0 ; i < rem_nb ; i++ ) + if (rx[i]) + delete rx[i]; + delete [] rx; + + delete O2; + delete N2; + delete CO2; + delete H2O; +} + +/*---------------------------------------------------------------*/ +bool burner::solve(double * y) +{ + OK=true; + //perform mass balance (neglect pollutants flows) + out->m = 0.0; + for(i=0;i<in->nb;i++) + { + if (!can_burn[i]) { + out->chem[i]->m = in->chem[i]->m; + out->m+=out->chem[i]->m; + } + else { + out->chem[i]->m=0.0; + O2->m+=rx[i]->O2_flow()*in->chem[i]->n(); + N2->m+=rx[i]->N2_flow()*in->chem[i]->n(); + CO2->m+=rx[i]->CO2_flow()*in->chem[i]->n(); + H2O->m+=rx[i]->H2O_flow()*in->chem[i]->n(); + } + } + N2->m*=(1.0+eta); + O2->m*=(1.0+eta); + //perform energy balance to find Tout + T = in->T; + + step=10; + Q=1; + // find temperature + while (fabs(step)>TOL_BURN && fabs(Q)>TOL_BURN && T<MAX_TEMP) + { + T+=step; + + if(T>MAX_TEMP) + T=MAX_TEMP; + Q = 0.0; + for ( i = 0 ; i < in->nb ; i++ ) + Q += in->chem[i]->dH ( in->T , T , in->P ) * in->chem[i]->n(); + + for ( i = 0 ; i < in->nb ; i++ ) + if ( can_burn[i] ) + Q += rx[i]->Hcomb(T) * in->chem[i]->n(); + + Q += O2->dH ( 293 , T , in->P ) * O2->n(); + Q += N2->dH ( 293 , T , in->P ) * N2->n(); + + + if (step/fabs(step)*Q >0) + step*= -0.1; + else if (fabs(Q)<10) + step*=0.25; + + } + + + + out->set_thermo(in->thermo); + // out->thermo = in->thermo; + + out->set(in->P, T); + O2->P=in->P; O2->T=T; O2->state=1; O2->find_v(); + N2->P=in->P; N2->T=T; N2->state=1; N2->find_v(); + CO2->P=in->P; CO2->T=T; CO2->state=1; CO2->find_v(); + H2O->P=in->P; H2O->T=T; H2O->state=1; H2O->find_v(); + //check if mixture can burn + m_can_burn = 0.0; + for(i=0;i<in->nb;i++) if(can_burn[i]) m_can_burn+=in->chem[i]->n(); + LFLmix=0.0; + for(i=0;i<in->nb;i++) if(can_burn[i]) LFLmix+=in->chem[i]->n()/m_can_burn*rx[i]->LFL(in->P,T); + UFLmix=0.0; + for(i=0;i<in->nb;i++) if(can_burn[i]) UFLmix+=in->chem[i]->n()/m_can_burn*rx[i]->UFL(in->P,T); + num = 0.0; + buff=in->T; in->set(in->P, T); + for(i=0;i<in->nb;i++) if(can_burn[i]) num+=in->chem[i]->n()/in->n()*in->v; + in->set(in->P, buff); + den = O2->v+N2->v+out->v; + composition = num/den; + if(!(LFLmix<=composition && composition<=UFLmix) || T==MAX_TEMP) + { +// logf.open(MESSAGES,ios::app); +// logf<<" --> Warning <-- Mixture in "<<name<<" can't burn (LFL="<<LFLmix +// <<" UFL="<<UFLmix<<" x="<<composition<<").\n"; +// logf.close(); + T=in->T; + filename = out->name; + *out=*in; + out->set(filename); + // out->write(); // WRITE TOTO + OK=false; + } + else + { + O2->P=in->P; O2->T=T; O2->state=1; O2->find_v(); + N2->P=in->P; N2->T=T; N2->state=1; N2->find_v(); + // out->write(); // WRITE TOTO + } + if(OK) //compute the pollutants production + { + fill_K_array(); + NO = 1e6*sqrt(K[0]*(N2->n()/den)*(O2->n()/den))*den*0.03/(O2->m+N2->m+out->m+H2O->m+CO2->m); + N2O = 1e6*K[1]*(N2->n()/den)*sqrt(O2->n()/den)*den*0.044/(O2->m+N2->m+out->m+H2O->m+CO2->m); + NO2 = 1e6*K[2]*sqrt(N2->n()/den)*(O2->n()/den)*den*0.046/(O2->m+N2->m+out->m+H2O->m+CO2->m); + CO = 1e6*K[3]*(CO2->n()/den)*den/sqrt(O2->n()/den)*0.028/(O2->m+N2->m+out->m+H2O->m+CO2->m); + } +// logf.open(MESSAGES,ios::app); + if (NO>EPS && NO2>EPS && N2O>EPS) { + // logf<<" --> Warning <-- Presence of NOx: "<<(NO+NO2+N2O)<<" ppm in "<<name<<".\n"; + y[7] = NO+NO2+N2O; + + if (ARRONDI) + y[7] = arrondi ( y[7] , 6 ); + + } + if (CO>EPS) { + // logf<<" --> Warning <-- Presence of CO: "<<CO<<" ppm in "<<name<<".\n"; + y[8] = CO; + if (ARRONDI) + y[8] = arrondi ( y[8] , 6 ); + + } +// logf.close(); + return OK; +} + +void burner::fill_K_array() +{ + a[0]=1.0; a[1]=1.0; a[2]=0.5; a[3]=1.0; + b[0]=1.0; b[1]=0.5; b[2]=1.0; b[3]=-0.5; + c[0]=2.0; c[1]=1.0; c[2]=1.0; c[3]=1.0; + K[0] = exp(-120.27*(173.38-T*0.012)/T); + K[1] = exp(-120.27*(103.64+T*0.074)/T); + K[2] = exp(-120.27*(51.96+T*0.061)/T); + K[3] = exp(-120.27*(283.84-T*0.087)/T); + for(i=0;i<4;i++) + K[i]*=pow(1000, c[i]-a[i]-b[i]); +} + +void burner::write() { + + cout << setprecision(6); + + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout << "\t>> " << name; + cout << endl << "\t>> stream in : " << in->name; + cout << endl << "\t>> streams out : " << out->name; + cout << endl << "\t>> P = " << in->P << " atm, T(in) = " << in->T + << " T(out) = " << T << " K"; + O2->P = 1; + O2->T = 293; + O2->state = 1; + O2->find_v(); + N2->P=1; + N2->T=293; + N2->state=1; + N2->find_v(); + cout << endl << "\t>> Required air flow = " + << (O2->m+N2->m) << " kg/s (" << (O2->v+N2->v) << " m3/s)"; + O2->P=in->P; + O2->T=T; + O2->state=1; + O2->find_v(); + N2->P=in->P; + N2->T=T; + N2->state=1; + N2->find_v(); + step=(eta*O2->v/(1+eta)+N2->v+H2O->v+CO2->v+out->v); + cout << endl << "\t>> Total flue gases = " + << (out->m+CO2->m+H2O->m+N2->m+eta*O2->m/(1+eta)) + <<" kg/s (" << step << " m3/s)"; + cout << "\n\tEND\n\n"; + cost(); +} + + +double burner::get_cost ( void ) { + + + O2->P = 1; + O2->T = 293; + O2->state = 1; + O2->find_v(); + N2->P=1; + N2->T=293; + N2->state=1; + N2->find_v(); + O2->P=in->P; + O2->T=T; + O2->state=1; + O2->find_v(); + N2->P=in->P; + N2->T=T; + N2->state=1; + N2->find_v(); + step=(eta*O2->v/(1+eta)+N2->v+H2O->v+CO2->v+out->v); + + buff = 3.1761-0.1373*log10(step) + 0.3414*pow(log10(step),2); + buff = 2.7*pow(10, buff); + buff = buff*MS_YEAR/MS_2001; + + return buff; +} + + +void burner::cost ( void ) { + cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/burner.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/burner.hpp index 3d83403..310df0d 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/burner.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/burner.hpp @@ -1,59 +1,59 @@ -/* -This unit simulates a burner. The user must provide the air excess -and all combustion data as defined in data\\combustion.prop : - CAS nb_moles_O2 nb_moles_CO2 nb_moles_H2O -Then, mass and energy balances are performed and flows of common -combustion pollutants are estimated. -(reference : Crowl & Louvar) - -Structure in the .process file: -burner {name} {index of input stream} {index of output stream} {air excess >0 (ex.: 1.2 is a 120% excess)} - -How to use: - 1- Call the constructor: burn = new burner(in, out); burner(nb_in, chem_list) - ->set(in, out) - 2- Set the air excess : burn->set(excess); - 3- Set the name of the unit: burn->set(name); - 4- Solve: bool=burn->solve(); -*/ -#ifndef BURNER_H -#define BURNER_H -#include "stream.hpp" -#include "combrx.hpp" -using namespace std; - -class burner -{ -private: - - string filename; - int rem_nb; - stream *in, *out; - chemical *O2, *N2, *CO2, *H2O; - combrx **rx; - bool *can_burn, stop, OK; - double eta, NO, NO2, N2O, CO; - double T, LFLmix, UFLmix, composition; - string name; - double * m; - double a[4], b[4], c[4], K[4]; - int i; - double buff, Q, m_can_burn, step, num, den; - ifstream data; - // ofstream logf, results; - // terminator *end; - void fill_K_array(); - -public: - // burner(){}; - burner ( int , chemical ** ); - void set ( stream * s1 , stream * s2 ) { in=s1; out=s2; for(i=0;i<in->nb;i++) m[i] = in->chem[i]->m;} - void set ( const string & n ) { name = n; } - void set(double e) {eta = e;} - bool solve(double * y); - void write(); - void cost(); - double get_cost ( void ); - ~burner(); -}; -#endif +/* +This unit simulates a burner. The user must provide the air excess +and all combustion data as defined in data\\combustion.prop : + CAS nb_moles_O2 nb_moles_CO2 nb_moles_H2O +Then, mass and energy balances are performed and flows of common +combustion pollutants are estimated. +(reference : Crowl & Louvar) + +Structure in the .process file: +burner {name} {index of input stream} {index of output stream} {air excess >0 (ex.: 1.2 is a 120% excess)} + +How to use: + 1- Call the constructor: burn = new burner(in, out); burner(nb_in, chem_list) + ->set(in, out) + 2- Set the air excess : burn->set(excess); + 3- Set the name of the unit: burn->set(name); + 4- Solve: bool=burn->solve(); +*/ +#ifndef BURNER_H +#define BURNER_H +#include "stream.hpp" +#include "combrx.hpp" +using namespace std; + +class burner +{ +private: + + string filename; + int rem_nb; + stream *in, *out; + chemical *O2, *N2, *CO2, *H2O; + combrx **rx; + bool *can_burn, stop, OK; + double eta, NO, NO2, N2O, CO; + double T, LFLmix, UFLmix, composition; + string name; + double * m; + double a[4], b[4], c[4], K[4]; + int i; + double buff, Q, m_can_burn, step, num, den; + ifstream data; + // ofstream logf, results; + // terminator *end; + void fill_K_array(); + +public: + // burner(){}; + burner ( int , chemical ** ); + void set ( stream * s1 , stream * s2 ) { in=s1; out=s2; for(i=0;i<in->nb;i++) m[i] = in->chem[i]->m;} + void set ( const string & n ) { name = n; } + void set(double e) {eta = e;} + bool solve(double * y); + void write(); + void cost(); + double get_cost ( void ); + ~burner(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/cashflow.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/cashflow.cpp index c7174f6..a35a767 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/cashflow.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/cashflow.cpp @@ -1,114 +1,114 @@ -#include "cashflow.hpp" -using namespace std; - -cashflow::cashflow(int n) -{ - N=n+1; - Inv = new double[N]; - Coper = new double[N]; - Amort = new double[N]; - Rev = new double[N]; - Flow = new double[N]; - Flowact = new double[N]; - Itot=Ctot=Rtot=i_rate=a_rate=0.0; - - - yield_tab[ 0] = 0.515; - yield_tab[ 1] = 0.778; - yield_tab[ 2] = 0.812; - yield_tab[ 3] = 0.893; - yield_tab[ 4] = 0.985; - yield_tab[ 5] = 0.837; - yield_tab[ 6] = 0.849; - yield_tab[ 7] = 0.746; - yield_tab[ 8] = 0.812; - yield_tab[ 9] = 0.954; - yield_tab[10] = 0.999; - yield_tab[11] = 0.961; - yield_tab[12] = 0.815; - yield_tab[13] = 0.886; - yield_tab[14] = 0.922; - -} - -cashflow::~cashflow ( void ) { - delete [] Inv; - delete [] Coper; - delete [] Amort; - delete [] Rev; - delete [] Flow; - delete [] Flowact; -} - -bool cashflow::run() -{ - if(Itot<EPS || Ctot<EPS || Rtot<EPS || i_rate<EPS || a_rate<EPS) - OK=false; - else - { - //if(!MUTE)cout<<endl<<" investments flow... OK"; - set_Inv(); - //if(!MUTE)cout<<endl<<" depreciation flow... OK"; - set_Amort(); - set_C_R(); - //if(!MUTE)cout<<endl<<" costs flow... OK"; - //if(!MUTE)cout<<endl<<" revenus flow... OK"; - for(i=0;i<N;i++) - { - Flow[i] = (Rev[i]-Coper[i])*(1.0-a_rate)-(Inv[i]-a_rate*Amort[i]); - Flowact[i] = Flow[i]/pow(1.0+i_rate, i); - } - //if(!MUTE)cout<<endl<<" cash flow... OK"; - //if(!MUTE)cout<<endl<<" actualizing cash flow... OK"; - OK=true; - -// cout<<endl<<endl<<" CASH FLOW DETAILS"<<endl; -// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; -// cout<<endl<<" "<<" i "<<" Investment "<<" Deprec. " -// <<" Expenses "<<" Revenus "<<" Cash flow "<<" Act. flow "; -// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; -// cout<<setfill(' ')<<setiosflags(ios::fixed)<<setprecision(0); -// for(i=0;i<N;i++) -// cout<<endl -// <<" "<<setw(2)<<i<<" "<<setw(11) -// <<Inv[i]<<" "<<setw(11)<<Amort[i]<<" " -// <<setw(11)<<Coper[i]<<" "<<setw(11)<<Rev[i]<<" "<<setw(11)<<Flow[i]<<" "<<setw(11)<<Flowact[i]; -// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; - } - return OK; -} - -void cashflow::set_Amort() -{ - Amort[0] = 0.0; - temp=Itot; - for(i=1;i<N-1;i++) - { - temp+=Inv[i]; - Amort[i] = temp/double(N-i); - temp-=Amort[i]; - } - Amort[N-1]=Amort[N-2]; -} - -void cashflow::set_Inv() -{ - Inv[0] = Itot; - for(i=1;i<N-1;i++) - { - if((i)%5==0) Inv[i]=0.1*Itot; - else Inv[i]=0.0; - } - Inv[N-1]=0.0; - for(i=0;i<N-1;i++) Inv[N-1]-=0.1*Inv[i]; -} - -void cashflow::set_C_R() -{ - Coper[0] = Rev[0] = 0.0; - for(i=1;i<N;i++) - { - Coper[i] = yield(i)*Ctot; - Rev[i] = yield(i)*Rtot; - } -} +#include "cashflow.hpp" +using namespace std; + +cashflow::cashflow(int n) +{ + N=n+1; + Inv = new double[N]; + Coper = new double[N]; + Amort = new double[N]; + Rev = new double[N]; + Flow = new double[N]; + Flowact = new double[N]; + Itot=Ctot=Rtot=i_rate=a_rate=0.0; + + + yield_tab[ 0] = 0.515; + yield_tab[ 1] = 0.778; + yield_tab[ 2] = 0.812; + yield_tab[ 3] = 0.893; + yield_tab[ 4] = 0.985; + yield_tab[ 5] = 0.837; + yield_tab[ 6] = 0.849; + yield_tab[ 7] = 0.746; + yield_tab[ 8] = 0.812; + yield_tab[ 9] = 0.954; + yield_tab[10] = 0.999; + yield_tab[11] = 0.961; + yield_tab[12] = 0.815; + yield_tab[13] = 0.886; + yield_tab[14] = 0.922; + +} + +cashflow::~cashflow ( void ) { + delete [] Inv; + delete [] Coper; + delete [] Amort; + delete [] Rev; + delete [] Flow; + delete [] Flowact; +} + +bool cashflow::run() +{ + if(Itot<EPS || Ctot<EPS || Rtot<EPS || i_rate<EPS || a_rate<EPS) + OK=false; + else + { + //if(!MUTE)cout<<endl<<" investments flow... OK"; + set_Inv(); + //if(!MUTE)cout<<endl<<" depreciation flow... OK"; + set_Amort(); + set_C_R(); + //if(!MUTE)cout<<endl<<" costs flow... OK"; + //if(!MUTE)cout<<endl<<" revenus flow... OK"; + for(i=0;i<N;i++) + { + Flow[i] = (Rev[i]-Coper[i])*(1.0-a_rate)-(Inv[i]-a_rate*Amort[i]); + Flowact[i] = Flow[i]/pow(1.0+i_rate, i); + } + //if(!MUTE)cout<<endl<<" cash flow... OK"; + //if(!MUTE)cout<<endl<<" actualizing cash flow... OK"; + OK=true; + +// cout<<endl<<endl<<" CASH FLOW DETAILS"<<endl; +// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; +// cout<<endl<<" "<<" i "<<" Investment "<<" Deprec. " +// <<" Expenses "<<" Revenus "<<" Cash flow "<<" Act. flow "; +// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; +// cout<<setfill(' ')<<setiosflags(ios::fixed)<<setprecision(0); +// for(i=0;i<N;i++) +// cout<<endl +// <<" "<<setw(2)<<i<<" "<<setw(11) +// <<Inv[i]<<" "<<setw(11)<<Amort[i]<<" " +// <<setw(11)<<Coper[i]<<" "<<setw(11)<<Rev[i]<<" "<<setw(11)<<Flow[i]<<" "<<setw(11)<<Flowact[i]; +// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; + } + return OK; +} + +void cashflow::set_Amort() +{ + Amort[0] = 0.0; + temp=Itot; + for(i=1;i<N-1;i++) + { + temp+=Inv[i]; + Amort[i] = temp/double(N-i); + temp-=Amort[i]; + } + Amort[N-1]=Amort[N-2]; +} + +void cashflow::set_Inv() +{ + Inv[0] = Itot; + for(i=1;i<N-1;i++) + { + if((i)%5==0) Inv[i]=0.1*Itot; + else Inv[i]=0.0; + } + Inv[N-1]=0.0; + for(i=0;i<N-1;i++) Inv[N-1]-=0.1*Inv[i]; +} + +void cashflow::set_C_R() +{ + Coper[0] = Rev[0] = 0.0; + for(i=1;i<N;i++) + { + Coper[i] = yield(i)*Ctot; + Rev[i] = yield(i)*Rtot; + } +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/cashflow.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/cashflow.hpp index a71b7ab..5aa5f70 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/cashflow.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/cashflow.hpp @@ -1,33 +1,33 @@ -#ifndef CASHFLOW_H -#define CASHFLOW_H -#include "defines.hpp" -// #include <iomanip> -using namespace std; - -class cashflow -{ - private: - // char name[31], filename[41]; - // ifstream in; - // ofstream out; - double Itot, Ctot, Rtot; - void set_Inv(), set_Amort(), set_C_R(); - double temp; - int i, j, counter; - bool OK; - double yield_tab[15]; - - double yield ( int k ) const { return yield_tab[(k==15) ? 14 : k%15]; } - -public: - double *Inv, *Coper, *Amort, *Rev, *Flow, *Flowact; - double i_rate, a_rate; - int N; - cashflow(int); - ~cashflow(); - // void set(char n[31]) {strcpy(name, n);} - void set_rates(double d1, double d2){i_rate=d1; a_rate=d2;} - void set_basics(double d1, double d2, double d3){Itot=d1; Ctot=d2; Rtot=d3;} - bool run(); -}; -#endif +#ifndef CASHFLOW_H +#define CASHFLOW_H +#include "defines.hpp" +// #include <iomanip> +using namespace std; + +class cashflow +{ + private: + // char name[31], filename[41]; + // ifstream in; + // ofstream out; + double Itot, Ctot, Rtot; + void set_Inv(), set_Amort(), set_C_R(); + double temp; + int i, j, counter; + bool OK; + double yield_tab[15]; + + double yield ( int k ) const { return yield_tab[(k==15) ? 14 : k%15]; } + +public: + double *Inv, *Coper, *Amort, *Rev, *Flow, *Flowact; + double i_rate, a_rate; + int N; + cashflow(int); + ~cashflow(); + // void set(char n[31]) {strcpy(name, n);} + void set_rates(double d1, double d2){i_rate=d1; a_rate=d2;} + void set_basics(double d1, double d2, double d3){Itot=d1; Ctot=d2; Rtot=d3;} + bool run(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/chemical.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/chemical.cpp index 3c155a1..ad29297 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/chemical.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/chemical.cpp @@ -1,529 +1,529 @@ -#include "chemical.hpp" -using namespace std; - -void chemical::check_error ( void ) { - if (error>MAX_ERROR) { - cout << "ERROR 2\n\n"; - exit(0); - } - if (warning>MAX_WARNING) { - cout << "ERROR 3\n\n"; - exit(0); - } -} - -// copy-constr. : -chemical::chemical ( const chemical & chem ) { - - CAS = chem.CAS; - name = chem.name; - M = chem.M; - - state = chem.state; - Tm = chem.Tm; - Tb = chem.Tb; - Tc = chem.Tc; - Pc = chem.Pc; - Ho = chem.Ho; - rho_liq = chem.rho_liq; - dHvap = chem.dHvap; - - mu_param[0] = chem.mu_param[0]; - mu_param[1] = chem.mu_param[1]; - Cp_param[0] = chem.Cp_param[0]; - Cp_param[1] = chem.Cp_param[1]; - Cp_param[2] = chem.Cp_param[2]; - Cp_param[3] = chem.Cp_param[3]; - Cp_liq = chem.Cp_liq; - Psat_param[0] = chem.Psat_param[0]; - Psat_param[1] = chem.Psat_param[1]; - Psat_param[2] = chem.Psat_param[2]; - - thermo = new thermolib(); - thermo->send(Pc,Tc, omega()); - - P = chem.P; - T = chem.T; - m = chem.m; - v = chem.v; - - warning = chem.warning; - error = chem.error; - tmp = chem.tmp; -} - -chemical::chemical ( const string & chem_name ) { - - CAS = chem_name; - - // C. Tribes add initialization for more robustness (variables may be initialized uncorrectly dependent on the execution) - P=T=m=v=0.0; - - // 1/12 : - if (CAS=="100-41-4") { - name = "ethylbenzene"; - M = 106.17; - state = 0; - Tm = 178.2; - Tb = 409.3; - Tc = 617.1; - Pc = 35.6; - Ho = 29.79; - rho_liq = 867.0; - dHvap = 35.56; - mu_param[0] = 472.82; - mu_param[1] = 264.22; - Cp_param[0] = -43.069; - Cp_param[1] = 7.067e-01; - Cp_param[2] = -4.807e-04; - Cp_param[3] = 1.30e-07; - Cp_liq = 190.23; - Psat_param[0] = 16.0195; - Psat_param[1] = 3279.47; - Psat_param[2] = -59.95; - } - - // 2/12 : - else if (CAS=="1333-74-0") { - name = "hydrogen"; - M = 2.02; - state = 1; - Tm = 14.0; - Tb = 20.4; - Tc = 33.2; - Pc = 12.8; - Ho = 0.0; - rho_liq = 71.0; - dHvap = 0.9; - mu_param[0] = 13.82; - mu_param[1] = 5.39; - Cp_param[0] = 27.124; - Cp_param[1] = 9.267e-03; - Cp_param[2] = -1.380e-05; - Cp_param[3] = 7.64e-09; - Cp_liq = 0.0; - Psat_param[0] = 13.6333; - Psat_param[1] = 164.90; - Psat_param[2] = 3.19; - } - - // 3/12 : - else if (CAS=="108-88-3") { - name = "toluene"; - M =92.14; - state = 0; - Tm = 178.0; - Tb = 383.8; - Tc = 591.7; - Pc = 40.6; - Ho = 50.0; - rho_liq = 867; - dHvap = 33.18; - mu_param[0] = 467.33; - mu_param[1] = 255.24; - Cp_param[0] = -24.338; - Cp_param[1] = 5.121e-1; - Cp_param[2] = -2.763e-4; - Cp_param[3] = 4.91e-8; - Cp_liq = 159.85; - Psat_param[0] = 16.0137; - Psat_param[1] = 3096.52; - Psat_param[2] = -53.67; - } - - // 4/12 : - else if (CAS=="74-82-8") { - name = "methane"; - M =16.04; - state =1; - Tm = 90.7; - Tb = 111.7; - Tc = 190.6; - Pc = 45.4; - Ho = -74.85; - rho_liq = 425; - dHvap = 8.18; - mu_param[0] = 114.14; - mu_param[1] = 57.60; - Cp_param[0] = 19.238; - Cp_param[1] = 5.209e-02; - Cp_param[2] = 1.197e-05; - Cp_param[3] = -1.13e-08; - Cp_liq = 0.0; - Psat_param[0] = 15.2243; - Psat_param[1] = 897.84; - Psat_param[2] = -7.16; - } - - // 5/12 : - else if (CAS=="71-43-2") { - name = "benzene"; - M = 78.11; - state = 0; - Tm = 278.7; - Tb = 353.3; - Tc = 562.1; - Pc = 48.3; - Ho = 82.93; - rho_liq = 885; - dHvap = 30.76; - mu_param[0] = 545.64; - mu_param[1] = 265.24; - Cp_param[0] = 33.894; - Cp_param[1] = 4.74e-1; - Cp_param[2] = -3.015e-4; - Cp_param[3] = 7.13e-8; - Cp_liq = 116.03; - Psat_param[0] = 15.9008; - Psat_param[1] = 2788.51; - Psat_param[2] = -52.36; - } - - // 6/12 : - else if (CAS=="74-85-1") { - name = "ethylene"; - M = 28.05; - state =1; - Tm = 104.0; - Tb = 169.4; - Tc = 282.4; - Pc = 49.7; - Ho =52.3; - rho_liq = 577.0; - dHvap = 13.54; - mu_param[0] = 168.98; - mu_param[1] = 93.94; - Cp_param[0] = 3.803; - Cp_param[1] = 1.565e-01; - Cp_param[2] = -8.343e-05; - Cp_param[3] = 1.75e-08; - Cp_liq = 0.0; - Psat_param[0] =15.5368; - Psat_param[1] = 1347.01; - Psat_param[2] = -18.15; - } - - // 7/12 : - else if (CAS=="100-42-5") { - name = "styrene"; - M =104.15; - state = 0; - Tm = 242.5; - Tb = 418.3; - Tc =647.0; - Pc =39.4; - Ho =147.36; - rho_liq =906.0; - dHvap = 36.82; - mu_param[0] = 528.64; - mu_param[1] = 276.71; - Cp_param[0] =-28.229; - Cp_param[1] =6.155e-01; - Cp_param[2] = -4.020e-04; - Cp_param[3] = 9.93e-08; - Cp_liq =166.13; - Psat_param[0] = 16.0193; - Psat_param[1] = 3328.57; - Psat_param[2] =-63.72; - } - - // 8/12 : - else if (CAS=="7782-44-7") { - name = "oxygen"; - M = 32.00; - state = 1; - Tm = 54.4; - Tb = 90.2; - Tc = 154.6; - Pc = 49.8; - Ho =0.0 ; - rho_liq =1149.1 ; - dHvap =6.82 ; - mu_param[0] = 85.68; - mu_param[1] = 51.50; - Cp_param[0] = 28.087; - Cp_param[1] = -3.678e-06 ; - Cp_param[2] = 1.745e-05; - Cp_param[3] = -1.06e-08; - Cp_liq =0.0 ; - Psat_param[0] = 15.4075; - Psat_param[1] = 734.55 ; - Psat_param[2] =-6.45 ; - } - - // 9/12 : - else if (CAS=="7727-37-9") { - name = "nitrogen"; - M = 28.01; - state = 1; - Tm = 63.3; - Tb = 77.4; - Tc = 126.2; - Pc = 33.5; - Ho = 0.0; - rho_liq = 804.0; - dHvap = 5.58; - mu_param[0] = 90.30; - mu_param[1] = 46.41; - Cp_param[0] = 31.128; - Cp_param[1] = -1.356e-02 ; - Cp_param[2] = 2.678e-05; - Cp_param[3] =-1.17e-08 ; - Cp_liq = 0.0; - Psat_param[0] = 14.9342; - Psat_param[1] = 588.72; - Psat_param[2] = -6.60; - } - - // 10/12 : - else if (CAS=="124-38-9") { - name = "carbon-dioxide"; - M =44.01; - state = 1; - Tm = 216.6; - Tb = 194.4; - Tc = 304.2; - Pc = 72.8; - Ho = -393.41; - rho_liq = 777.0; - dHvap = 17.15; - mu_param[0] = 578.08; - mu_param[1] = 185.24 ; - Cp_param[0] = 19.782; - Cp_param[1] = 7.339e-02; - Cp_param[2] = -5.598e-05; - Cp_param[3] = 1.71e-08; - Cp_liq = 0.0; - Psat_param[0] = 22.5898; - Psat_param[1] =3103.39 ; - Psat_param[2] = -0.16; - } - - // 11/12 : - else if (CAS=="7732-18-5") { - name = "water"; - M =18.02; - state = 0; - Tm = 273.15; - Tb = 373.15; - Tc = 647.4; - Pc = 217.6; - Ho = -241.83; - rho_liq = 998 ; - dHvap = 40.66; - mu_param[0] = 658.25; - mu_param[1] = 283.16; - Cp_param[0] = 32.220; - Cp_param[1] = 1.923e-03 ; - Cp_param[2] = 1.055e-05; - Cp_param[3] = -3.59e-09; - Cp_liq = 75.24; - Psat_param[0] = 18.3036; - Psat_param[1] = 3816.44; - Psat_param[2] = -46.13; - } - - // 12/12 : - else if (CAS=="64-17-5") { - name = "ethanol"; - M =46.07; - state =0 ; - Tm =159.1 ; - Tb = 351.5; - Tc = 516.2; - Pc =63.0 ; - Ho = -234.8; - rho_liq = 789.0; - dHvap =38.74 ; - mu_param[0] = 686.64; - mu_param[1] = 300.88; - Cp_param[0] = 9.008; - Cp_param[1] = 2.139e-01; - Cp_param[2] = -8.385e-05 ; - Cp_param[3] = 1.37e-09; - Cp_liq = 2.22; - Psat_param[0] = 18.9119; - Psat_param[1] = 3803.98; - Psat_param[2] = -41.68; - } - - else { - cout << "ERROR 1\n\n"; - exit(0); - } - - thermo = new thermolib(); - thermo->send(Pc,Tc, omega()); - - -} - -double chemical::K() -{ - thermo->set(P,T,v,n()); - return thermo->K(); -} - -double chemical::mu() -{ - // Returns the fluid's viscosity in Pa.s - if (Tm<=T && T<=Tboil(P)) - return pow(10,(mu_param[0]*(1.0/T-1.0/mu_param[1])-3)); - else - { - ofstream logf; - logf.open(MESSAGES, ios::app); - logf<<" --> Warning <-- Cannot compute viscosity of "<<name<<".\n"; - logf.close(); - warning++; - check_error(); - return 1.0; - } -} - -double chemical::rho() -{ - // Returns the fluid's density in kg/m3, wether it's liquid or gas - if(state==0) tmp= rho_liq; - if(state==1) - { - find_v(); - if (v>EPS) tmp= m/v; - else tmp= 0.0; - } - return tmp; -} - -double chemical::Cp() { - // cout<<endl<<"Cp de "<<name<<" a "<<T; - // Returns the fluid's Cp in J/mol.K - if(state==0) { - - // tmp = Cp_liq; // BUG : boucle infinie !!! - return Cp_liq; // SEB - - } - if(state==1 || T>Tboil(P)) { - tmp=0; - for (int i=0;i<4;i++) - tmp+=Cp_param[i]*pow(T,i); - } - else { - T=Tb; - - tmp = Cp(); // ici boucle infinie si state==0 !!! - - } - return tmp; -} - -double chemical::Cp(bool q) -{ - // Returns the fluid's Cp in J/mol.K - if(q==0) tmp=Cp_liq; - if(q==1) - { - tmp=0; - for (int i=0;i<4;i++) tmp+=Cp_param[i]*pow(T,i); - } - return tmp; -} - -double chemical::Psat() -{ - // Returns the fluid's vapor pressure in atm, using Antoine's equation - if(Tm<=T && T<=Tc) - return (exp(Psat_param[0]-Psat_param[1]/(T+Psat_param[2]))/760.01); - else - { - - return Psat(Tb); - } -} -double chemical::Psat(double t) -{ - // Returns the fluid's vapor pressure in atm, using Antoine's equation - return (exp(Psat_param[0]-Psat_param[1]/(t+Psat_param[2]))/760.01); -} - -double chemical::dH(double T1,double T2, double pres) -{ - //Enthalpy variation in kJ/mol. Does not affect any attributes of current object. - double energy=0, TT=Tboil(pres), vap=Hvap(TT); - int sign=1, i; - if (T2<T1) {sign = -1; energy=T1; T1=T2; T2=energy; energy=0;} - if (T1==T2) energy = 0.0; - if (T2<TT) energy = Cp_liq*(T2-T1)/1000; - if (TT<T1) for (i=1;i<=4;i++) energy+=Cp_param[i-1]*(pow(T2,i)-pow(T1,i))/i/1000; - if(T1<=TT && TT<=T2) - { - energy=Cp_liq*(TT-T1)/1000; - energy+=vap; - for (i=1;i<=4;i++) energy+=Cp_param[i-1]*(pow(T2,i)-pow(TT,i))/i/1000; - } - return energy*sign; -} - -void chemical::find_T() -{ - if(n()>EPS && P>EPS) - { - thermo->set(P,T,v,n()); - T=thermo->T(); - } - else - { - ofstream logf; - logf.open(MESSAGES, ios::app); - logf<<" --> Warning <-- Cannot find T of "<<name<<".\n"; - logf.close(); - warning++; - } - check_error(); -} - -void chemical::find_P() -{ - if(n()>EPS && T>EPS) - { - thermo->set(P,T,v,n()); - P=thermo->P(); - } - else - { - ofstream logf; - logf.open(MESSAGES, ios::app); - logf<<" --> Warning <-- Cannot find P of "<<name<<".\n"; - logf.close(); - warning++; - } - check_error(); -} - -void chemical::find_v() -{ - - if(state==0) v=m/rho_liq; - if(state==1 && P>EPS && T>EPS && m>EPS) - { - thermo->set(P,T,v,n()); - v=thermo->v(); - } -} - -void chemical::find_state() -{ - ofstream logf; - if (T>Tc || P>Pc) state = 1; //T or P is bigger than Tc or Pc - if (T<=Tm) //T is smaller than melting point - { - ofstream logf; - logf.open(MESSAGES, ios::app); - logf<<" --> Warning <-- The chemical "<<name<<" is solid.\n"; - logf.close(); - warning++; - } - check_error(); - if (T<Tboil(P)) state=0; - else state=1; -} +#include "chemical.hpp" +using namespace std; + +void chemical::check_error ( void ) { + if (error>MAX_ERROR) { + cout << "ERROR 2\n\n"; + exit(0); + } + if (warning>MAX_WARNING) { + cout << "ERROR 3\n\n"; + exit(0); + } +} + +// copy-constr. : +chemical::chemical ( const chemical & chem ) { + + CAS = chem.CAS; + name = chem.name; + M = chem.M; + + state = chem.state; + Tm = chem.Tm; + Tb = chem.Tb; + Tc = chem.Tc; + Pc = chem.Pc; + Ho = chem.Ho; + rho_liq = chem.rho_liq; + dHvap = chem.dHvap; + + mu_param[0] = chem.mu_param[0]; + mu_param[1] = chem.mu_param[1]; + Cp_param[0] = chem.Cp_param[0]; + Cp_param[1] = chem.Cp_param[1]; + Cp_param[2] = chem.Cp_param[2]; + Cp_param[3] = chem.Cp_param[3]; + Cp_liq = chem.Cp_liq; + Psat_param[0] = chem.Psat_param[0]; + Psat_param[1] = chem.Psat_param[1]; + Psat_param[2] = chem.Psat_param[2]; + + thermo = new thermolib(); + thermo->send(Pc,Tc, omega()); + + P = chem.P; + T = chem.T; + m = chem.m; + v = chem.v; + + warning = chem.warning; + error = chem.error; + tmp = chem.tmp; +} + +chemical::chemical ( const string & chem_name ) { + + CAS = chem_name; + + // C. Tribes add initialization for more robustness (variables may be initialized uncorrectly dependent on the execution) + P=T=m=v=0.0; + + // 1/12 : + if (CAS=="100-41-4") { + name = "ethylbenzene"; + M = 106.17; + state = 0; + Tm = 178.2; + Tb = 409.3; + Tc = 617.1; + Pc = 35.6; + Ho = 29.79; + rho_liq = 867.0; + dHvap = 35.56; + mu_param[0] = 472.82; + mu_param[1] = 264.22; + Cp_param[0] = -43.069; + Cp_param[1] = 7.067e-01; + Cp_param[2] = -4.807e-04; + Cp_param[3] = 1.30e-07; + Cp_liq = 190.23; + Psat_param[0] = 16.0195; + Psat_param[1] = 3279.47; + Psat_param[2] = -59.95; + } + + // 2/12 : + else if (CAS=="1333-74-0") { + name = "hydrogen"; + M = 2.02; + state = 1; + Tm = 14.0; + Tb = 20.4; + Tc = 33.2; + Pc = 12.8; + Ho = 0.0; + rho_liq = 71.0; + dHvap = 0.9; + mu_param[0] = 13.82; + mu_param[1] = 5.39; + Cp_param[0] = 27.124; + Cp_param[1] = 9.267e-03; + Cp_param[2] = -1.380e-05; + Cp_param[3] = 7.64e-09; + Cp_liq = 0.0; + Psat_param[0] = 13.6333; + Psat_param[1] = 164.90; + Psat_param[2] = 3.19; + } + + // 3/12 : + else if (CAS=="108-88-3") { + name = "toluene"; + M =92.14; + state = 0; + Tm = 178.0; + Tb = 383.8; + Tc = 591.7; + Pc = 40.6; + Ho = 50.0; + rho_liq = 867; + dHvap = 33.18; + mu_param[0] = 467.33; + mu_param[1] = 255.24; + Cp_param[0] = -24.338; + Cp_param[1] = 5.121e-1; + Cp_param[2] = -2.763e-4; + Cp_param[3] = 4.91e-8; + Cp_liq = 159.85; + Psat_param[0] = 16.0137; + Psat_param[1] = 3096.52; + Psat_param[2] = -53.67; + } + + // 4/12 : + else if (CAS=="74-82-8") { + name = "methane"; + M =16.04; + state =1; + Tm = 90.7; + Tb = 111.7; + Tc = 190.6; + Pc = 45.4; + Ho = -74.85; + rho_liq = 425; + dHvap = 8.18; + mu_param[0] = 114.14; + mu_param[1] = 57.60; + Cp_param[0] = 19.238; + Cp_param[1] = 5.209e-02; + Cp_param[2] = 1.197e-05; + Cp_param[3] = -1.13e-08; + Cp_liq = 0.0; + Psat_param[0] = 15.2243; + Psat_param[1] = 897.84; + Psat_param[2] = -7.16; + } + + // 5/12 : + else if (CAS=="71-43-2") { + name = "benzene"; + M = 78.11; + state = 0; + Tm = 278.7; + Tb = 353.3; + Tc = 562.1; + Pc = 48.3; + Ho = 82.93; + rho_liq = 885; + dHvap = 30.76; + mu_param[0] = 545.64; + mu_param[1] = 265.24; + Cp_param[0] = 33.894; + Cp_param[1] = 4.74e-1; + Cp_param[2] = -3.015e-4; + Cp_param[3] = 7.13e-8; + Cp_liq = 116.03; + Psat_param[0] = 15.9008; + Psat_param[1] = 2788.51; + Psat_param[2] = -52.36; + } + + // 6/12 : + else if (CAS=="74-85-1") { + name = "ethylene"; + M = 28.05; + state =1; + Tm = 104.0; + Tb = 169.4; + Tc = 282.4; + Pc = 49.7; + Ho =52.3; + rho_liq = 577.0; + dHvap = 13.54; + mu_param[0] = 168.98; + mu_param[1] = 93.94; + Cp_param[0] = 3.803; + Cp_param[1] = 1.565e-01; + Cp_param[2] = -8.343e-05; + Cp_param[3] = 1.75e-08; + Cp_liq = 0.0; + Psat_param[0] =15.5368; + Psat_param[1] = 1347.01; + Psat_param[2] = -18.15; + } + + // 7/12 : + else if (CAS=="100-42-5") { + name = "styrene"; + M =104.15; + state = 0; + Tm = 242.5; + Tb = 418.3; + Tc =647.0; + Pc =39.4; + Ho =147.36; + rho_liq =906.0; + dHvap = 36.82; + mu_param[0] = 528.64; + mu_param[1] = 276.71; + Cp_param[0] =-28.229; + Cp_param[1] =6.155e-01; + Cp_param[2] = -4.020e-04; + Cp_param[3] = 9.93e-08; + Cp_liq =166.13; + Psat_param[0] = 16.0193; + Psat_param[1] = 3328.57; + Psat_param[2] =-63.72; + } + + // 8/12 : + else if (CAS=="7782-44-7") { + name = "oxygen"; + M = 32.00; + state = 1; + Tm = 54.4; + Tb = 90.2; + Tc = 154.6; + Pc = 49.8; + Ho =0.0 ; + rho_liq =1149.1 ; + dHvap =6.82 ; + mu_param[0] = 85.68; + mu_param[1] = 51.50; + Cp_param[0] = 28.087; + Cp_param[1] = -3.678e-06 ; + Cp_param[2] = 1.745e-05; + Cp_param[3] = -1.06e-08; + Cp_liq =0.0 ; + Psat_param[0] = 15.4075; + Psat_param[1] = 734.55 ; + Psat_param[2] =-6.45 ; + } + + // 9/12 : + else if (CAS=="7727-37-9") { + name = "nitrogen"; + M = 28.01; + state = 1; + Tm = 63.3; + Tb = 77.4; + Tc = 126.2; + Pc = 33.5; + Ho = 0.0; + rho_liq = 804.0; + dHvap = 5.58; + mu_param[0] = 90.30; + mu_param[1] = 46.41; + Cp_param[0] = 31.128; + Cp_param[1] = -1.356e-02 ; + Cp_param[2] = 2.678e-05; + Cp_param[3] =-1.17e-08 ; + Cp_liq = 0.0; + Psat_param[0] = 14.9342; + Psat_param[1] = 588.72; + Psat_param[2] = -6.60; + } + + // 10/12 : + else if (CAS=="124-38-9") { + name = "carbon-dioxide"; + M =44.01; + state = 1; + Tm = 216.6; + Tb = 194.4; + Tc = 304.2; + Pc = 72.8; + Ho = -393.41; + rho_liq = 777.0; + dHvap = 17.15; + mu_param[0] = 578.08; + mu_param[1] = 185.24 ; + Cp_param[0] = 19.782; + Cp_param[1] = 7.339e-02; + Cp_param[2] = -5.598e-05; + Cp_param[3] = 1.71e-08; + Cp_liq = 0.0; + Psat_param[0] = 22.5898; + Psat_param[1] =3103.39 ; + Psat_param[2] = -0.16; + } + + // 11/12 : + else if (CAS=="7732-18-5") { + name = "water"; + M =18.02; + state = 0; + Tm = 273.15; + Tb = 373.15; + Tc = 647.4; + Pc = 217.6; + Ho = -241.83; + rho_liq = 998 ; + dHvap = 40.66; + mu_param[0] = 658.25; + mu_param[1] = 283.16; + Cp_param[0] = 32.220; + Cp_param[1] = 1.923e-03 ; + Cp_param[2] = 1.055e-05; + Cp_param[3] = -3.59e-09; + Cp_liq = 75.24; + Psat_param[0] = 18.3036; + Psat_param[1] = 3816.44; + Psat_param[2] = -46.13; + } + + // 12/12 : + else if (CAS=="64-17-5") { + name = "ethanol"; + M =46.07; + state =0 ; + Tm =159.1 ; + Tb = 351.5; + Tc = 516.2; + Pc =63.0 ; + Ho = -234.8; + rho_liq = 789.0; + dHvap =38.74 ; + mu_param[0] = 686.64; + mu_param[1] = 300.88; + Cp_param[0] = 9.008; + Cp_param[1] = 2.139e-01; + Cp_param[2] = -8.385e-05 ; + Cp_param[3] = 1.37e-09; + Cp_liq = 2.22; + Psat_param[0] = 18.9119; + Psat_param[1] = 3803.98; + Psat_param[2] = -41.68; + } + + else { + cout << "ERROR 1\n\n"; + exit(0); + } + + thermo = new thermolib(); + thermo->send(Pc,Tc, omega()); + + +} + +double chemical::K() +{ + thermo->set(P,T,v,n()); + return thermo->K(); +} + +double chemical::mu() +{ + // Returns the fluid's viscosity in Pa.s + if (Tm<=T && T<=Tboil(P)) + return pow(10,(mu_param[0]*(1.0/T-1.0/mu_param[1])-3)); + else + { + ofstream logf; + logf.open(MESSAGES, ios::app); + logf<<" --> Warning <-- Cannot compute viscosity of "<<name<<".\n"; + logf.close(); + warning++; + check_error(); + return 1.0; + } +} + +double chemical::rho() +{ + // Returns the fluid's density in kg/m3, wether it's liquid or gas + if(state==0) tmp= rho_liq; + if(state==1) + { + find_v(); + if (v>EPS) tmp= m/v; + else tmp= 0.0; + } + return tmp; +} + +double chemical::Cp() { + // cout<<endl<<"Cp de "<<name<<" a "<<T; + // Returns the fluid's Cp in J/mol.K + if(state==0) { + + // tmp = Cp_liq; // BUG : boucle infinie !!! + return Cp_liq; // SEB + + } + if(state==1 || T>Tboil(P)) { + tmp=0; + for (int i=0;i<4;i++) + tmp+=Cp_param[i]*pow(T,i); + } + else { + T=Tb; + + tmp = Cp(); // ici boucle infinie si state==0 !!! + + } + return tmp; +} + +double chemical::Cp(bool q) +{ + // Returns the fluid's Cp in J/mol.K + if(q==0) tmp=Cp_liq; + if(q==1) + { + tmp=0; + for (int i=0;i<4;i++) tmp+=Cp_param[i]*pow(T,i); + } + return tmp; +} + +double chemical::Psat() +{ + // Returns the fluid's vapor pressure in atm, using Antoine's equation + if(Tm<=T && T<=Tc) + return (exp(Psat_param[0]-Psat_param[1]/(T+Psat_param[2]))/760.01); + else + { + + return Psat(Tb); + } +} +double chemical::Psat(double t) +{ + // Returns the fluid's vapor pressure in atm, using Antoine's equation + return (exp(Psat_param[0]-Psat_param[1]/(t+Psat_param[2]))/760.01); +} + +double chemical::dH(double T1,double T2, double pres) +{ + //Enthalpy variation in kJ/mol. Does not affect any attributes of current object. + double energy=0, TT=Tboil(pres), vap=Hvap(TT); + int sign=1, i; + if (T2<T1) {sign = -1; energy=T1; T1=T2; T2=energy; energy=0;} + if (T1==T2) energy = 0.0; + if (T2<TT) energy = Cp_liq*(T2-T1)/1000; + if (TT<T1) for (i=1;i<=4;i++) energy+=Cp_param[i-1]*(pow(T2,i)-pow(T1,i))/i/1000; + if(T1<=TT && TT<=T2) + { + energy=Cp_liq*(TT-T1)/1000; + energy+=vap; + for (i=1;i<=4;i++) energy+=Cp_param[i-1]*(pow(T2,i)-pow(TT,i))/i/1000; + } + return energy*sign; +} + +void chemical::find_T() +{ + if(n()>EPS && P>EPS) + { + thermo->set(P,T,v,n()); + T=thermo->T(); + } + else + { + ofstream logf; + logf.open(MESSAGES, ios::app); + logf<<" --> Warning <-- Cannot find T of "<<name<<".\n"; + logf.close(); + warning++; + } + check_error(); +} + +void chemical::find_P() +{ + if(n()>EPS && T>EPS) + { + thermo->set(P,T,v,n()); + P=thermo->P(); + } + else + { + ofstream logf; + logf.open(MESSAGES, ios::app); + logf<<" --> Warning <-- Cannot find P of "<<name<<".\n"; + logf.close(); + warning++; + } + check_error(); +} + +void chemical::find_v() +{ + + if(state==0) v=m/rho_liq; + if(state==1 && P>EPS && T>EPS && m>EPS) + { + thermo->set(P,T,v,n()); + v=thermo->v(); + } +} + +void chemical::find_state() +{ + ofstream logf; + if (T>Tc || P>Pc) state = 1; //T or P is bigger than Tc or Pc + if (T<=Tm) //T is smaller than melting point + { + ofstream logf; + logf.open(MESSAGES, ios::app); + logf<<" --> Warning <-- The chemical "<<name<<" is solid.\n"; + logf.close(); + warning++; + } + check_error(); + if (T<Tboil(P)) state=0; + else state=1; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/chemical.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/chemical.hpp index 71b28a9..344bd01 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/chemical.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/chemical.hpp @@ -1,48 +1,48 @@ -#ifndef CHEMICAL_H -#define CHEMICAL_H - -#include "thermolib.hpp" -#include <string> -using namespace std; - -class chemical -{ - public: - string name; - string CAS; - double M; //molar weight, in g/mol - bool state; //current state : 0=liquid 1=gas - double P, T, m, v; //current values : P in atm, T in K, m in kg/s, v in m3/s - - double n() {return 1000.0*m/M;} //mole flow in mol/s - double Hvap(double t) {return dHvap*pow((Tc-t)/(Tc-Tb),0.38);} //vaporization heat at specific T (Watson correlation) - double omega() {return ((-1.0)*log10(Psat(0.7*Tc)/Pc) -1.0);} //Pitzer acentric factor - double Tboil(double p) {return (Psat_param[1]/(Psat_param[0]-log(760.01*p))-Psat_param[2]);} //boiling tempararure at specific P - double mu(), rho(), Cp(), Cp(bool), Psat(), Psat(double); //T-dependant properties - double K(); //liquid-vapor equilibrium constant - double gamma(){return Cp(true)/(Cp(true)-8.3144);}//compressibility ratio =Cp/Cv - double dH(double, double, double); //enthalpy variation kJ/mol - void find_T(), find_P(), find_v(), find_state(); //for gases only - double Tm, Tb, Tc, Pc; //melting, boiling and critical temp. (K); critical pressure (atm) - double Ho;//standard formation heat in kJ/mol - - //private: - int warning, error; - void check_error(); - double dHvap, tmp; //vaporization heat (kJ/mol) - double mu_param[2], Cp_param[4], Cp_liq, Psat_param[3], rho_liq; //correlations parameters - thermolib *thermo; - - // public: - // chemical() {}; - - // copy-constr. : - chemical ( const chemical & chem ); - - chemical ( const string & chem_name ); //Contructor : initializes fields and reads CAS in the data file - void purge() {P=T=m=v=0.0; state=false;} - ~chemical(){delete thermo;}; -}; - -#endif - +#ifndef CHEMICAL_H +#define CHEMICAL_H + +#include "thermolib.hpp" +#include <string> +using namespace std; + +class chemical +{ + public: + string name; + string CAS; + double M; //molar weight, in g/mol + bool state; //current state : 0=liquid 1=gas + double P, T, m, v; //current values : P in atm, T in K, m in kg/s, v in m3/s + + double n() {return 1000.0*m/M;} //mole flow in mol/s + double Hvap(double t) {return dHvap*pow((Tc-t)/(Tc-Tb),0.38);} //vaporization heat at specific T (Watson correlation) + double omega() {return ((-1.0)*log10(Psat(0.7*Tc)/Pc) -1.0);} //Pitzer acentric factor + double Tboil(double p) {return (Psat_param[1]/(Psat_param[0]-log(760.01*p))-Psat_param[2]);} //boiling tempararure at specific P + double mu(), rho(), Cp(), Cp(bool), Psat(), Psat(double); //T-dependant properties + double K(); //liquid-vapor equilibrium constant + double gamma(){return Cp(true)/(Cp(true)-8.3144);}//compressibility ratio =Cp/Cv + double dH(double, double, double); //enthalpy variation kJ/mol + void find_T(), find_P(), find_v(), find_state(); //for gases only + double Tm, Tb, Tc, Pc; //melting, boiling and critical temp. (K); critical pressure (atm) + double Ho;//standard formation heat in kJ/mol + + //private: + int warning, error; + void check_error(); + double dHvap, tmp; //vaporization heat (kJ/mol) + double mu_param[2], Cp_param[4], Cp_liq, Psat_param[3], rho_liq; //correlations parameters + thermolib *thermo; + + // public: + // chemical() {}; + + // copy-constr. : + chemical ( const chemical & chem ); + + chemical ( const string & chem_name ); //Contructor : initializes fields and reads CAS in the data file + void purge() {P=T=m=v=0.0; state=false;} + ~chemical(){delete thermo;}; +}; + +#endif + diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/column.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/column.cpp index 85ab3e0..f4a35c1 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/column.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/column.cpp @@ -1,290 +1,290 @@ -#include "column.hpp" -using namespace std; - -column::column(stream* in, stream* out_B, stream* out_D) -{ - F = in; - B = out_B; - D = out_D; - L=new stream("columnL", F->nb, F->chem); - V=new stream("columnV", F->nb, F->chem); - flasher = new flash(F, L, V); - alpha_1 = new double[F->nb]; - alpha_f = new double[F->nb]; - alpha_N = new double[F->nb]; - alpha_m = new double[F->nb]; - T_d=0; T_b=0; T_f=F->T; -// for(i=0;i<F->nb;i++) -// if(F->chem[i]->Tc<F->T && F->chem[i]->m>EPS) -// { -// logf.open(MESSAGES,ios::app); -// logf<<" --> Warning <-- Presence of gas in column.\n"; -// logf.close(); -// i=F->nb; -// } -} - -column::~column() -{ - delete L; delete V; delete flasher; - delete [] alpha_1; - delete [] alpha_f; - delete [] alpha_N; - delete [] alpha_m; -} - -void column::set(double p, int lk, double xd, int hk, double xb) -{ - P=p; - HK=hk-1; x_B=xb; - LK=lk-1; x_D=xd; - //logf.open(MESSAGES, ios::app); - // F->write(); system("pause"); - // if (F->chem[LK]->m<EPS) logf<<" ==> Error <== Flow of light key in column "<<name<<" is zero.\n"; -// if (F->chem[HK]->m<EPS) logf<<" ==> Error <== Flow of heavy key in column "<<name<<" is zero.\n"; - //logf.close(); -} - -bool column::solve() -{ - - OK=true; - // B->thermo=F->thermo; D->thermo=F->thermo; - //flash once the feed stream - - - - flasher->set(P,F->T); - - flasher->adiabatic(); - - - T_f=flasher->T; - L->set(P, T_f); V->set(P, T_f); - // L->write(); V->write(); TOTO - //check if a column is needed; if not, bypass block - if(F->chem[LK]->n()/F->n()<0.001) OK=false; - if(F->chem[HK]->n()/F->n()<0.001) OK=false; - if(!OK) - return false; -// { -// strcpy(filename, B->name); *B=*L; B->set(filename); B->write(); -// strcpy(filename, D->name); *D=*V; D->set(filename); D->write(); -// } - else - { - - - - - - //apply the FUG method - first_split(); - Nmin = Fenske(); - N=Nmin+1; - while (fabs(N-Nmin)>0.1) - { - N=Nmin; - D->set(P, T_f); T_d=D->bp; - B->set(P, T_f); T_b=B->bp; - set_alpha(); - distribute(); - Nmin = Fenske(); - if (Nmin<1) Nmin=1; - } - D->set(P, T_d); - B->set(P, T_b); - if(fabs(Nmin)<=MIN_PLATES || fabs(Nmin)>MAX_PLATES) OK=false; - else - { - Rmin = Underwood(); - if(Rmin>100) Rmin=100; - if(L->chem[HK]->m+L->chem[LK]->m<EPS) Rmin=10.0; - if (Nmin<5) Ract = 1.5*Rmin; - if (5<Nmin && Nmin<15) Ract = 1.3*Rmin; - if (15<=Nmin) Ract = 1.1*Rmin; - N = Gilliland(); - feed = Kirkbride(); - condense(); - reboil(); - } - // B->write(); TOTO - // D->write(); TOTO - } - return OK; -} - -void column::first_split() -{ - B->purge(); D->purge(); - set_alpha(); - //Check if LK is really lighter than HK - if (alpha_m[LK]<1) - { -// logf.open(MESSAGES,ios::app); -// logf<<" --> Warning <-- Swapping keys in column "<<name<<".\n"; -// logf.close(); - feed=LK; LK=HK; HK=feed; set_alpha(); - } - for(i=0;i<F->nb;i++) - { - if (i!=LK && i!=HK && F->chem[i]->m>EPS) - { - if(alpha_f[i] > alpha_f[LK]) //volatile - { - D->chem[i]->m = (alpha_f[i]-alpha_f[LK])/alpha_f[i]*F->chem[i]->m; - D->m += D->chem[i]->m; - B->chem[i]->m = F->chem[i]->m-D->chem[i]->m; - B->m+=B->chem[i]->m; - } - if(alpha_f[i] < 1) //not volatile - { - B->chem[i]->m = (alpha_f[HK]-alpha_f[i])/alpha_f[i]*F->chem[i]->m; - B->m += B->chem[i]->m; - D->chem[i]->m = F->chem[i]->m-B->chem[i]->m; - D->m+=D->chem[i]->m; - } - if(1 <= alpha_f[i] && alpha_f[i]<=alpha_f[LK]) //ambiguous volatility - { - D->chem[i]->m = (alpha_f[i]-1)/(alpha_f[LK]-1)*F->chem[i]->m; - B->chem[i]->m = F->chem[i]->m-D->chem[i]->m; - D->m+=D->chem[i]->m; - B->m+=B->chem[i]->m; - } - } - } - D->chem[HK]->m = D->n()*x_D/(1-x_D)*D->chem[HK]->M/1000.0; - if(D->chem[HK]->m<EPS) D->chem[HK]->m=0.01*F->chem[HK]->m; - B->chem[LK]->m = B->n()*x_B/(1-x_B)*B->chem[LK]->M/1000.0; - if(B->chem[LK]->m<EPS) B->chem[LK]->m=0.01*F->chem[LK]->m; - B->chem[HK]->m = F->chem[HK]->m - D->chem[HK]->m; - D->chem[LK]->m = F->chem[LK]->m - B->chem[LK]->m; - D->m += (D->chem[LK]->m + D->chem[HK]->m); - B->m += (B->chem[LK]->m + B->chem[HK]->m); -} -void column::distribute() -{ - D->m=0; B->m=0; - for(i=0;i<F->nb;i++) - { - if (i!=LK && i!=HK && F->chem[i]->m>EPS) - { - if(alpha_m[i] > 1) //volatile and ambiguous - { - B->chem[i]->m = F->chem[i]->m/(1+D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin)); - D->chem[i]->m = F->chem[i]->m - B->chem[i]->m; - } - if(alpha_m[i] <= 1) //not volatile - { - D->chem[i]->m = F->chem[i]->m*(D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin))/(1+D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin)); - B->chem[i]->m = F->chem[i]->m - D->chem[i]->m; - } - D->m+=D->chem[i]->m; - B->m+=B->chem[i]->m; - } - } - D->m += (D->chem[LK]->m + D->chem[HK]->m); - B->m += (B->chem[LK]->m + B->chem[HK]->m); -} - -void column::set_alpha() -{ - for(i=0;i<F->nb; i++) - { - if (T_b>EPS && F->chem[i]->m>EPS) alpha_1[i] = F->chem[i]->Psat(T_b)/F->chem[HK]->Psat(T_b); - else alpha_1[i]=0; - if (T_d>EPS&& F->chem[i]->m>EPS) alpha_N[i] = F->chem[i]->Psat(T_d)/F->chem[HK]->Psat(T_d); - else alpha_N[i]=0; - if (T_f>EPS&& F->chem[i]->m>EPS) alpha_f[i] = F->chem[i]->Psat(T_f)/F->chem[HK]->Psat(T_f); - else alpha_f[i]=0; - alpha_m[i] = pow(alpha_1[i]*alpha_f[i]*alpha_N[i], 1.0/3.0); - } - for(i=0;i<F->nb;i++) if(alpha_m[i]<EPS&& F->chem[i]->m>EPS) alpha_m[i] = alpha_f[i]; -} - -void column::reboil() -{ - Q_reboil = 0.0; - for (i=0;i<F->nb;i++) if(F->chem[i]->m>EPS) - { - Q_reboil += B->chem[i]->Cp(false)*(T_b-T_f)*B->chem[i]->n()/1000.0; //energy to go from input to bottoms T - Q_reboil += D->chem[i]->Cp(false)*(T_f-T_d)*D->chem[i]->n()/1000.0; //energy to go from input to tops T - } - Q_reboil += Q_condens; -} - -void column::condense() -{ - Q_condens = 0.0; - for (i=0;i<F->nb;i++) if(F->chem[i]->m>EPS) - { - Q_condens += D->chem[i]->Hvap(T_d)*(1+Ract)*D->chem[i]->n(); - } -} - -void column::write() -{ - cout << setprecision(11); - - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout <<"\t>> "<<name; - cout <<endl<<"\t>> stream in: "<<F->name; - cout <<endl<<"\t>> streams out: "<<B->name<<" (bot.) "<<D->name<<" (top.)"; - cout <<endl<<"\t>> P = "<<P<<" atm, T(0) = "<<T_b<<", T("<<feed<<") = "<<T_f<<", T("<<int(N)<<") = "<<T_d<<" K"; - cout <<endl<<"\t>> Number of stages: "<<int(N)<<" (feeding at stage "<<feed<<")"; - cout <<endl<<setiosflags(ios::fixed|ios::showpoint)<<setprecision(5)<<"\t>> LK purity = "<<D->chem[LK]->n()/D->n()<<" HK purity = "<<B->chem[HK]->n()/B->n(); - cout <<endl<<"\t>> Reboiler duty: "<<Q_reboil<<" kW Condenser duty: "<<(-1)*Q_condens<<" kW"; - cout << "\n\tEND\n\n"; - cost(); water(); power(); -} - -double column::get_cost() -{ - //cost of vessel - vol=(0.45*N)*(pow(300*D->v, 1.5)/2.4/sqrt(B->v))*sqrt(D->m/B->m); - if(vol<0.3) vol=0.3; if(vol>520)vol=520; - money = 3.4974+0.4485*log10(vol)+0.1074*pow(log10(vol),2); - money = pow(10, money); - P= (P-1)*101.325/100; - diam=sqrt(4.0*vol/pi/N/0.45); - vol=(P+1)*diam/(317.46*(850-0.6*(P+1)))+0.0315; - money *=(2.25+ 1.82*vol*2.2); - //cost of trays - vol = (pow(300*D->v, 1.5)/2.4/sqrt(B->v))*sqrt(D->m/B->m); - diam = 2.9949+0.4465*log10(vol)+0.3961*pow(log10(vol),2); - money+=1.5*pow(10, diam); - //cost of reboiler U=5250W/m2.K - vol=fabs(Q_reboil)/0.85/5.25/15.0; - if(vol<10) vol=10; if(vol>100) vol=100; - vol = 4.4646-0.5277*log10(vol)+0.3955*pow(log10(vol),2); - money += (1.63+1.66*2.5)*pow(10, vol); - //cost of condenser U=1850W/m2.K - vol=fabs(Q_condens)/0.85/1.85/(0.5*(T_d-298)); - if(vol<1) vol=1; if(vol>100) vol=100; - vol = 3.9912+0.0668*log10(vol)+0.243*pow(log10(vol),2); - money += (1.74+1.55*2.5)*pow(10, vol); - money = money*MS_YEAR/MS_2001; - return money; -} - - -void column::cost() -{ - cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} -void column::power() -{ - cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; - money =(Q_reboil/0.85-Q_condens); - cout << "\t>>" << money; - cout << "\n\tEND\n\n"; -} -void column::water() -{ - cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; - money = (fabs(Q_condens)/(4.185*0.85*0.25*fabs(T_d-298))); - cout << "\t>>" << money; - cout << "\n\tEND\n\n"; -} +#include "column.hpp" +using namespace std; + +column::column(stream* in, stream* out_B, stream* out_D) +{ + F = in; + B = out_B; + D = out_D; + L=new stream("columnL", F->nb, F->chem); + V=new stream("columnV", F->nb, F->chem); + flasher = new flash(F, L, V); + alpha_1 = new double[F->nb]; + alpha_f = new double[F->nb]; + alpha_N = new double[F->nb]; + alpha_m = new double[F->nb]; + T_d=0; T_b=0; T_f=F->T; +// for(i=0;i<F->nb;i++) +// if(F->chem[i]->Tc<F->T && F->chem[i]->m>EPS) +// { +// logf.open(MESSAGES,ios::app); +// logf<<" --> Warning <-- Presence of gas in column.\n"; +// logf.close(); +// i=F->nb; +// } +} + +column::~column() +{ + delete L; delete V; delete flasher; + delete [] alpha_1; + delete [] alpha_f; + delete [] alpha_N; + delete [] alpha_m; +} + +void column::set(double p, int lk, double xd, int hk, double xb) +{ + P=p; + HK=hk-1; x_B=xb; + LK=lk-1; x_D=xd; + //logf.open(MESSAGES, ios::app); + // F->write(); system("pause"); + // if (F->chem[LK]->m<EPS) logf<<" ==> Error <== Flow of light key in column "<<name<<" is zero.\n"; +// if (F->chem[HK]->m<EPS) logf<<" ==> Error <== Flow of heavy key in column "<<name<<" is zero.\n"; + //logf.close(); +} + +bool column::solve() +{ + + OK=true; + // B->thermo=F->thermo; D->thermo=F->thermo; + //flash once the feed stream + + + + flasher->set(P,F->T); + + flasher->adiabatic(); + + + T_f=flasher->T; + L->set(P, T_f); V->set(P, T_f); + // L->write(); V->write(); TOTO + //check if a column is needed; if not, bypass block + if(F->chem[LK]->n()/F->n()<0.001) OK=false; + if(F->chem[HK]->n()/F->n()<0.001) OK=false; + if(!OK) + return false; +// { +// strcpy(filename, B->name); *B=*L; B->set(filename); B->write(); +// strcpy(filename, D->name); *D=*V; D->set(filename); D->write(); +// } + else + { + + + + + + //apply the FUG method + first_split(); + Nmin = Fenske(); + N=Nmin+1; + while (fabs(N-Nmin)>0.1) + { + N=Nmin; + D->set(P, T_f); T_d=D->bp; + B->set(P, T_f); T_b=B->bp; + set_alpha(); + distribute(); + Nmin = Fenske(); + if (Nmin<1) Nmin=1; + } + D->set(P, T_d); + B->set(P, T_b); + if(fabs(Nmin)<=MIN_PLATES || fabs(Nmin)>MAX_PLATES) OK=false; + else + { + Rmin = Underwood(); + if(Rmin>100) Rmin=100; + if(L->chem[HK]->m+L->chem[LK]->m<EPS) Rmin=10.0; + if (Nmin<5) Ract = 1.5*Rmin; + if (5<Nmin && Nmin<15) Ract = 1.3*Rmin; + if (15<=Nmin) Ract = 1.1*Rmin; + N = Gilliland(); + feed = Kirkbride(); + condense(); + reboil(); + } + // B->write(); TOTO + // D->write(); TOTO + } + return OK; +} + +void column::first_split() +{ + B->purge(); D->purge(); + set_alpha(); + //Check if LK is really lighter than HK + if (alpha_m[LK]<1) + { +// logf.open(MESSAGES,ios::app); +// logf<<" --> Warning <-- Swapping keys in column "<<name<<".\n"; +// logf.close(); + feed=LK; LK=HK; HK=feed; set_alpha(); + } + for(i=0;i<F->nb;i++) + { + if (i!=LK && i!=HK && F->chem[i]->m>EPS) + { + if(alpha_f[i] > alpha_f[LK]) //volatile + { + D->chem[i]->m = (alpha_f[i]-alpha_f[LK])/alpha_f[i]*F->chem[i]->m; + D->m += D->chem[i]->m; + B->chem[i]->m = F->chem[i]->m-D->chem[i]->m; + B->m+=B->chem[i]->m; + } + if(alpha_f[i] < 1) //not volatile + { + B->chem[i]->m = (alpha_f[HK]-alpha_f[i])/alpha_f[i]*F->chem[i]->m; + B->m += B->chem[i]->m; + D->chem[i]->m = F->chem[i]->m-B->chem[i]->m; + D->m+=D->chem[i]->m; + } + if(1 <= alpha_f[i] && alpha_f[i]<=alpha_f[LK]) //ambiguous volatility + { + D->chem[i]->m = (alpha_f[i]-1)/(alpha_f[LK]-1)*F->chem[i]->m; + B->chem[i]->m = F->chem[i]->m-D->chem[i]->m; + D->m+=D->chem[i]->m; + B->m+=B->chem[i]->m; + } + } + } + D->chem[HK]->m = D->n()*x_D/(1-x_D)*D->chem[HK]->M/1000.0; + if(D->chem[HK]->m<EPS) D->chem[HK]->m=0.01*F->chem[HK]->m; + B->chem[LK]->m = B->n()*x_B/(1-x_B)*B->chem[LK]->M/1000.0; + if(B->chem[LK]->m<EPS) B->chem[LK]->m=0.01*F->chem[LK]->m; + B->chem[HK]->m = F->chem[HK]->m - D->chem[HK]->m; + D->chem[LK]->m = F->chem[LK]->m - B->chem[LK]->m; + D->m += (D->chem[LK]->m + D->chem[HK]->m); + B->m += (B->chem[LK]->m + B->chem[HK]->m); +} +void column::distribute() +{ + D->m=0; B->m=0; + for(i=0;i<F->nb;i++) + { + if (i!=LK && i!=HK && F->chem[i]->m>EPS) + { + if(alpha_m[i] > 1) //volatile and ambiguous + { + B->chem[i]->m = F->chem[i]->m/(1+D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin)); + D->chem[i]->m = F->chem[i]->m - B->chem[i]->m; + } + if(alpha_m[i] <= 1) //not volatile + { + D->chem[i]->m = F->chem[i]->m*(D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin))/(1+D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin)); + B->chem[i]->m = F->chem[i]->m - D->chem[i]->m; + } + D->m+=D->chem[i]->m; + B->m+=B->chem[i]->m; + } + } + D->m += (D->chem[LK]->m + D->chem[HK]->m); + B->m += (B->chem[LK]->m + B->chem[HK]->m); +} + +void column::set_alpha() +{ + for(i=0;i<F->nb; i++) + { + if (T_b>EPS && F->chem[i]->m>EPS) alpha_1[i] = F->chem[i]->Psat(T_b)/F->chem[HK]->Psat(T_b); + else alpha_1[i]=0; + if (T_d>EPS&& F->chem[i]->m>EPS) alpha_N[i] = F->chem[i]->Psat(T_d)/F->chem[HK]->Psat(T_d); + else alpha_N[i]=0; + if (T_f>EPS&& F->chem[i]->m>EPS) alpha_f[i] = F->chem[i]->Psat(T_f)/F->chem[HK]->Psat(T_f); + else alpha_f[i]=0; + alpha_m[i] = pow(alpha_1[i]*alpha_f[i]*alpha_N[i], 1.0/3.0); + } + for(i=0;i<F->nb;i++) if(alpha_m[i]<EPS&& F->chem[i]->m>EPS) alpha_m[i] = alpha_f[i]; +} + +void column::reboil() +{ + Q_reboil = 0.0; + for (i=0;i<F->nb;i++) if(F->chem[i]->m>EPS) + { + Q_reboil += B->chem[i]->Cp(false)*(T_b-T_f)*B->chem[i]->n()/1000.0; //energy to go from input to bottoms T + Q_reboil += D->chem[i]->Cp(false)*(T_f-T_d)*D->chem[i]->n()/1000.0; //energy to go from input to tops T + } + Q_reboil += Q_condens; +} + +void column::condense() +{ + Q_condens = 0.0; + for (i=0;i<F->nb;i++) if(F->chem[i]->m>EPS) + { + Q_condens += D->chem[i]->Hvap(T_d)*(1+Ract)*D->chem[i]->n(); + } +} + +void column::write() +{ + cout << setprecision(11); + + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout <<"\t>> "<<name; + cout <<endl<<"\t>> stream in: "<<F->name; + cout <<endl<<"\t>> streams out: "<<B->name<<" (bot.) "<<D->name<<" (top.)"; + cout <<endl<<"\t>> P = "<<P<<" atm, T(0) = "<<T_b<<", T("<<feed<<") = "<<T_f<<", T("<<int(N)<<") = "<<T_d<<" K"; + cout <<endl<<"\t>> Number of stages: "<<int(N)<<" (feeding at stage "<<feed<<")"; + cout <<endl<<setiosflags(ios::fixed|ios::showpoint)<<setprecision(5)<<"\t>> LK purity = "<<D->chem[LK]->n()/D->n()<<" HK purity = "<<B->chem[HK]->n()/B->n(); + cout <<endl<<"\t>> Reboiler duty: "<<Q_reboil<<" kW Condenser duty: "<<(-1)*Q_condens<<" kW"; + cout << "\n\tEND\n\n"; + cost(); water(); power(); +} + +double column::get_cost() +{ + //cost of vessel + vol=(0.45*N)*(pow(300*D->v, 1.5)/2.4/sqrt(B->v))*sqrt(D->m/B->m); + if(vol<0.3) vol=0.3; if(vol>520)vol=520; + money = 3.4974+0.4485*log10(vol)+0.1074*pow(log10(vol),2); + money = pow(10, money); + P= (P-1)*101.325/100; + diam=sqrt(4.0*vol/pi/N/0.45); + vol=(P+1)*diam/(317.46*(850-0.6*(P+1)))+0.0315; + money *=(2.25+ 1.82*vol*2.2); + //cost of trays + vol = (pow(300*D->v, 1.5)/2.4/sqrt(B->v))*sqrt(D->m/B->m); + diam = 2.9949+0.4465*log10(vol)+0.3961*pow(log10(vol),2); + money+=1.5*pow(10, diam); + //cost of reboiler U=5250W/m2.K + vol=fabs(Q_reboil)/0.85/5.25/15.0; + if(vol<10) vol=10; if(vol>100) vol=100; + vol = 4.4646-0.5277*log10(vol)+0.3955*pow(log10(vol),2); + money += (1.63+1.66*2.5)*pow(10, vol); + //cost of condenser U=1850W/m2.K + vol=fabs(Q_condens)/0.85/1.85/(0.5*(T_d-298)); + if(vol<1) vol=1; if(vol>100) vol=100; + vol = 3.9912+0.0668*log10(vol)+0.243*pow(log10(vol),2); + money += (1.74+1.55*2.5)*pow(10, vol); + money = money*MS_YEAR/MS_2001; + return money; +} + + +void column::cost() +{ + cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} +void column::power() +{ + cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; + money =(Q_reboil/0.85-Q_condens); + cout << "\t>>" << money; + cout << "\n\tEND\n\n"; +} +void column::water() +{ + cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; + money = (fabs(Q_condens)/(4.185*0.85*0.25*fabs(T_d-298))); + cout << "\t>>" << money; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/column.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/column.hpp index cfd1daf..8dedb5a 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/column.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/column.hpp @@ -1,61 +1,61 @@ -/* -This unit simulates a distillation column, using -the FUG method. -(ref : Seader & Henley). - -Structure in the .process file: -column {name} {pressure} {index of input stream} {index of bottoms and heads} {indexes of light key and heavy key} {x_LK and x_HK} - -How to use: - 1- Call the constructor : col = new column(in, out_B, out_D); //in is F, out_B is B, out_D is D column(nb, chem_list) - set(in, out_B, out_D) - 2- Set operating conditions : col->set(pressure, LK, x_LK, HK, x_HK); // LK and HK and integer indexes, x_LK is the undesired mole fraction of LK in B, x_HK... - 3- Set the name : col->set(name); - 4- Run the model: col->solve(); -*/ -#ifndef COLUMN_H -#define COLUMN_H - -#include "flash.hpp" -using namespace std; - -class column -{ -private: - // ofstream results, logf; - bool OK; - string name; - stream *F, *B, *D, *L, *V ; - int LK, HK, feed, i; - double x_B, x_D, T_b, T_d, T_f, vol, money, diam; - double Nmin, N, Rmin, Ract, tmp, Q_condens, Q_reboil; - double *alpha_1, *alpha_f, *alpha_N, *alpha_m; - flash *flasher; - void set_alpha(), first_split(), distribute(), condense(), reboil(); - double Fenske() { return log10(D->chem[LK]->n()*B->chem[HK]->n()/D->chem[HK]->n()/B->chem[LK]->n())/log10(alpha_m[LK]);} - double Underwood() {return L->n()*(D->chem[LK]->n()/L->chem[LK]->n()-alpha_m[LK]*D->chem[HK]->n()/L->chem[HK]->n())/(D->n()*(alpha_m[LK]-1));} - double Gilliland(){N=(Ract-Rmin)/(Ract+1); tmp=1-exp((1+54.4*N)*(N-1)/(11+117.2*N)/pow(N, 0.5)); return (tmp+Nmin)/(1-tmp);} - int Kirkbride() {tmp=pow(B->n()*F->chem[HK]->n()*pow(x_B/x_D,2)/F->chem[LK]->n()/D->n(), 0.206); return int(N/(tmp+1));} - -public: - // column(){P=0.0;} - // column(int, chemical*); - // void set(stream*&, stream*&, stream*&); - column(stream*, stream*, stream*); - ~column(); - double P; - void set(double, int, double, int, double); - void set( const string & n ) { name = n; } - bool solve(); - void write(); - void cost(), water(), power(); - - double get_cost ( void ); - double get_power ( void ) const { return Q_reboil/0.85-Q_condens; } - - double get_water ( void ) const { return fabs(Q_condens)/(4.185*0.85*0.25*fabs(T_d-298)); } - - int get_N ( void ) const { return (int) N; } - -}; -#endif +/* +This unit simulates a distillation column, using +the FUG method. +(ref : Seader & Henley). + +Structure in the .process file: +column {name} {pressure} {index of input stream} {index of bottoms and heads} {indexes of light key and heavy key} {x_LK and x_HK} + +How to use: + 1- Call the constructor : col = new column(in, out_B, out_D); //in is F, out_B is B, out_D is D column(nb, chem_list) + set(in, out_B, out_D) + 2- Set operating conditions : col->set(pressure, LK, x_LK, HK, x_HK); // LK and HK and integer indexes, x_LK is the undesired mole fraction of LK in B, x_HK... + 3- Set the name : col->set(name); + 4- Run the model: col->solve(); +*/ +#ifndef COLUMN_H +#define COLUMN_H + +#include "flash.hpp" +using namespace std; + +class column +{ +private: + // ofstream results, logf; + bool OK; + string name; + stream *F, *B, *D, *L, *V ; + int LK, HK, feed, i; + double x_B, x_D, T_b, T_d, T_f, vol, money, diam; + double Nmin, N, Rmin, Ract, tmp, Q_condens, Q_reboil; + double *alpha_1, *alpha_f, *alpha_N, *alpha_m; + flash *flasher; + void set_alpha(), first_split(), distribute(), condense(), reboil(); + double Fenske() { return log10(D->chem[LK]->n()*B->chem[HK]->n()/D->chem[HK]->n()/B->chem[LK]->n())/log10(alpha_m[LK]);} + double Underwood() {return L->n()*(D->chem[LK]->n()/L->chem[LK]->n()-alpha_m[LK]*D->chem[HK]->n()/L->chem[HK]->n())/(D->n()*(alpha_m[LK]-1));} + double Gilliland(){N=(Ract-Rmin)/(Ract+1); tmp=1-exp((1+54.4*N)*(N-1)/(11+117.2*N)/pow(N, 0.5)); return (tmp+Nmin)/(1-tmp);} + int Kirkbride() {tmp=pow(B->n()*F->chem[HK]->n()*pow(x_B/x_D,2)/F->chem[LK]->n()/D->n(), 0.206); return int(N/(tmp+1));} + +public: + // column(){P=0.0;} + // column(int, chemical*); + // void set(stream*&, stream*&, stream*&); + column(stream*, stream*, stream*); + ~column(); + double P; + void set(double, int, double, int, double); + void set( const string & n ) { name = n; } + bool solve(); + void write(); + void cost(), water(), power(); + + double get_cost ( void ); + double get_power ( void ) const { return Q_reboil/0.85-Q_condens; } + + double get_water ( void ) const { return fabs(Q_condens)/(4.185*0.85*0.25*fabs(T_d-298)); } + + int get_N ( void ) const { return (int) N; } + +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/combrx.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/combrx.cpp index 83ad673..0f30f1a 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/combrx.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/combrx.cpp @@ -1,66 +1,66 @@ -#include "combrx.hpp" -using namespace std; - -combrx::combrx ( const string & cas ) { - - // combustion.prop : - // ----------------- - CAS = cas; - - if (CAS=="64-17-5") { - nO2 = 3; - nCO2 = 2; - nH2O = 3; - } - else if (CAS=="74-82-8") { - nO2 = 2; - nCO2 = 1; - nH2O = 2; - } - else if (CAS=="1333-74-0") { - nO2 = 0.5; - nCO2 = 0; - nH2O = 1; - } - else if (CAS=="100-42-5") { - nO2 = 10; - nCO2 = 8; - nH2O = 4; - } - else if (CAS=="74-85-1") { - nO2 = 3; - nCO2 = 2; - nH2O = 2; - } - else if (CAS=="108-88-3") { - nO2 = 9; - nCO2 = 7; - nH2O = 4; - } - else if (CAS=="100-41-4") { - nO2 = 10.5; - nCO2 = 8; - nH2O = 5; - } - else if (CAS=="71-43-2") { - nO2 = 7.5; - nCO2 = 6; - nH2O = 3; - } - else { - cout << "ERROR 21" << endl; - exit(0); - } - - COMB = new chemical(CAS); - O2 = new chemical("7782-44-7"); - N2 = new chemical("7727-37-9"); - CO2 = new chemical("124-38-9"); - H2O = new chemical("7732-18-5"); - Hro = CO2->Ho*nCO2 + nH2O*(H2O->Ho - H2O->dHvap) - COMB->Ho; - LFLo = -3420.0/Hro + 0.569e-3*Hro + 0.0538e-6*pow(Hro,2) + 1.8; - LFLo = LFLo/100.0; - UFLo = 0.0063*Hro + 0.567e-6*pow(Hro, 2) + 23.5; - UFLo = UFLo/100.0; - -} +#include "combrx.hpp" +using namespace std; + +combrx::combrx ( const string & cas ) { + + // combustion.prop : + // ----------------- + CAS = cas; + + if (CAS=="64-17-5") { + nO2 = 3; + nCO2 = 2; + nH2O = 3; + } + else if (CAS=="74-82-8") { + nO2 = 2; + nCO2 = 1; + nH2O = 2; + } + else if (CAS=="1333-74-0") { + nO2 = 0.5; + nCO2 = 0; + nH2O = 1; + } + else if (CAS=="100-42-5") { + nO2 = 10; + nCO2 = 8; + nH2O = 4; + } + else if (CAS=="74-85-1") { + nO2 = 3; + nCO2 = 2; + nH2O = 2; + } + else if (CAS=="108-88-3") { + nO2 = 9; + nCO2 = 7; + nH2O = 4; + } + else if (CAS=="100-41-4") { + nO2 = 10.5; + nCO2 = 8; + nH2O = 5; + } + else if (CAS=="71-43-2") { + nO2 = 7.5; + nCO2 = 6; + nH2O = 3; + } + else { + cout << "ERROR 21" << endl; + exit(0); + } + + COMB = new chemical(CAS); + O2 = new chemical("7782-44-7"); + N2 = new chemical("7727-37-9"); + CO2 = new chemical("124-38-9"); + H2O = new chemical("7732-18-5"); + Hro = CO2->Ho*nCO2 + nH2O*(H2O->Ho - H2O->dHvap) - COMB->Ho; + LFLo = -3420.0/Hro + 0.569e-3*Hro + 0.0538e-6*pow(Hro,2) + 1.8; + LFLo = LFLo/100.0; + UFLo = 0.0063*Hro + 0.567e-6*pow(Hro, 2) + 23.5; + UFLo = UFLo/100.0; + +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/combrx.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/combrx.hpp index b57e643..02e098b 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/combrx.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/combrx.hpp @@ -1,29 +1,29 @@ -#ifndef COMBRX_H -#define COMBRX_H -#include "chemical.hpp" -#include "defines.hpp" -using namespace std; - -class combrx { - -private : - ifstream data; - bool stop; - double nO2, nCO2, nH2O; - char tmp[41]; - string CAS; - chemical *H2O, *N2, *O2, *CO2, *COMB; - double LFLo, UFLo, Hro, sum; - -public: - combrx( const string & cas ); - double O2_flow() { return (O2->M*nO2/1000.0); } //theoritical O2 flow, in kg/mol of COMB - double N2_flow(){return (0.79*O2_flow()/0.21);} //theoritical N2 flow, in kg/mol of COMB - double CO2_flow() {return (nCO2*CO2->M/1000.0);} //theoritical CO2 flow, in kg/mol of COMB - double H2O_flow() {return (nH2O*H2O->M/1000.0);} //theoritical H2O flow, in kg/mol of COMB - double LFL(double P, double T) {sum=LFLo + 0.03139/Hro*(T-298); if(sum<EPS) return EPS; else return sum;} //in %vol - double UFL(double P, double T) {sum=UFLo - 0.03139/Hro*(T-298) + 0.206*(log10(0.101325*P)+1); if(sum>1) return (1-EPS); else return sum;} //in %vol - double Hcomb(double T) {return (nCO2*CO2->dH(298,T,1)+ nH2O*H2O->dH(298,T,1)-nO2*O2->dH(298,T,1)-COMB->dH(298,T,1)+Hro);} //in kJ/mol - ~combrx(){delete H2O; delete N2; delete O2; delete CO2; delete COMB;} -}; -#endif +#ifndef COMBRX_H +#define COMBRX_H +#include "chemical.hpp" +#include "defines.hpp" +using namespace std; + +class combrx { + +private : + ifstream data; + bool stop; + double nO2, nCO2, nH2O; + char tmp[41]; + string CAS; + chemical *H2O, *N2, *O2, *CO2, *COMB; + double LFLo, UFLo, Hro, sum; + +public: + combrx( const string & cas ); + double O2_flow() { return (O2->M*nO2/1000.0); } //theoritical O2 flow, in kg/mol of COMB + double N2_flow(){return (0.79*O2_flow()/0.21);} //theoritical N2 flow, in kg/mol of COMB + double CO2_flow() {return (nCO2*CO2->M/1000.0);} //theoritical CO2 flow, in kg/mol of COMB + double H2O_flow() {return (nH2O*H2O->M/1000.0);} //theoritical H2O flow, in kg/mol of COMB + double LFL(double P, double T) {sum=LFLo + 0.03139/Hro*(T-298); if(sum<EPS) return EPS; else return sum;} //in %vol + double UFL(double P, double T) {sum=UFLo - 0.03139/Hro*(T-298) + 0.206*(log10(0.101325*P)+1); if(sum>1) return (1-EPS); else return sum;} //in %vol + double Hcomb(double T) {return (nCO2*CO2->dH(298,T,1)+ nH2O*H2O->dH(298,T,1)-nO2*O2->dH(298,T,1)-COMB->dH(298,T,1)+Hro);} //in kJ/mol + ~combrx(){delete H2O; delete N2; delete O2; delete CO2; delete COMB;} +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/flash.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/flash.cpp index 930ea8f..027ad0e 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/flash.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/flash.cpp @@ -1,220 +1,220 @@ -#include "flash.hpp" -#include "bissection.cpp" -using namespace std; - -flash::flash ( stream * in , stream * out_L , stream * out_V ) { - F = in; - Fcopy = new stream("Fcopy", F->nb, F->chem); - Tin = F->T; - z = new double[F->nb]; - for ( i = 0 ; i < F->nb ; i++ ) - z[i] = F->chem[i]->n()/F->n(); - - L = out_L; - V = out_V; - success = true; - K = new double[F->nb]; - task=0; - solver = new bissection<flash>(); -} - -void flash::set(double p, double t) -{ - P=p; - T=t; - for (i=0;i<F->nb;i++) - { - if(F->chem[i]->Tc<T) K[i] = F->chem[i]->Psat(T)/P; - else K[i]=1; - } - F->set(P,T); -} - -bool flash::solve() -{ - L->purge(); - V->purge(); - f_x=F->quality(); - - if( 0.0 < f_x && f_x < 1.0) - { - - // TOTO - for ( i = 0 ; i < F->nb ; i++ ) { - if ( F->chem[i]->Tc < T ) { - F->m -= F->chem[i]->m; - F->chem[i]->m = 0; - } - } - - for ( i = 0 ; i < F->nb ; i++ ) - z[i] = F->chem[i]->n()/F->n(); - - solver->set(this, 0.0, 1.0); - - success=solver->run(); - - if (!success) - { -// if(task==0){ -// log.open(MESSAGES, ios::app); -// log<<" --> Warning <-- Solver of FLASH "<<name<<" did not converge.\n"; -// log.close();} - for (i=0;i<F->nb;i++) - { - if (T<F->chem[i]->Tc && T>F->chem[i]->Tboil(P)) {V->chem[i]->m=F->chem[i]->m; V->m+=V->chem[i]->m;} - if (T<F->chem[i]->Tc && T<=F->chem[i]->Tboil(P)) {L->chem[i]->m=F->chem[i]->m; L->m+=L->chem[i]->m;} - } - } - else - { - - V->m = x*F->n(); - L->m = F->n() - V->m; - //Distribute liquid components - for (i=0;i<L->nb;i++) - { - L->chem[i]->m = (L->m*z[i])/(1+x*(K[i]-1))*L->chem[i]->M/1000.0; - L->chem[i]->state=0; - } - - - L->m=0.0; for(i=0;i<L->nb;i++) L->m+=L->chem[i]->m; - //Distribute vapor components - for (i=0;i<V->nb;i++) - { - V->chem[i]->m = V->m*L->chem[i]->n()*K[i]/L->n()*V->chem[i]->M/1000.0; - V->chem[i]->state=1; - } - V->m=0.0; for(i=0;i<V->nb;i++) V->m+=V->chem[i]->m; - } - for(i=0;i<F->nb;i++) - if(F->chem[i]->Tc<T){V->chem[i]->m=Fcopy->chem[i]->m; V->m+=Fcopy->chem[i]->m;} - - } - else - { - /* if(task==0) - { - log.open("runtime\\messages.r", ios::app); - if (T<F->dp) log<<" --> Warning <-- Mixture in "<<name<<" can't be flashed (bp="<<F->bp<<" dp="<<F->dp<<").\n"; - log.close(); - } */ - for (i=0;i<F->nb;i++) - { - if (F->chem[i]->Tc<T || f_x>=1) {V->chem[i]->m=Fcopy->chem[i]->m; V->m+=V->chem[i]->m; } - else {L->chem[i]->m=Fcopy->chem[i]->m; L->m+=L->chem[i]->m;} - - } - success = true; - } - L->set(P,T); - V->set(P,T); - Q = 0.0; - for (i=0;i<F->nb;i++) - { - Q += L->chem[i]->dH(Tin, T, P)*L->chem[i]->n(); - Q += V->chem[i]->dH(Tin, T, P)*V->chem[i]->n(); - } - F->m=0; - for(i=0;i<Fcopy->nb;i++) {F->chem[i]->m = Fcopy->chem[i]->m; F->m+=F->chem[i]->m;} - F->set(F->P,Tin); -// if(fabs(V->m+L->m-F->m)>sqrt(EPS)) -// { -// log.open(MESSAGES, ios::app); -// log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(V->m+L->m-F->m)/F->m<<").\n"; -// log.close(); -// } -// V->write();// TOTO - // L->write(); // TOTO - - return success; -} - -double flash::f(double psy) -{ - x=psy; - f_x=0.0; - for(i=0;i<F->nb;i++) f_x += (z[i]*(1-K[i]))/(1+psy*(K[i]-1)); - return f_x; -} - -bool flash::adiabatic() -{ - task=1; - F->set(P,T); T=F->dp; - step=-5; - Q=1; - - - while (fabs(step)>0.01 && fabs(Q)>0.1) - { - T+=step; - F->set(P,T); - - for (i=0;i<F->nb;i++) - K[i] = F->chem[i]->Psat(T)/P; - - success=solve(); - - - if (Q<0 && step<0) step*=-0.5; - if (Q>0 && step>0) step*=-0.5; - } - if (fabs(Q)<0.1) return true; - else return false; -} - -void flash::write() { - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout << "\t>> "<<name; - cout << endl << "\t>> stream in : "<<F->name; - cout <<endl<<"\t>> streams out : "<<L->name<<" (liq.) "<<V->name<<" (vap.)"; - cout <<endl<<"\t>> P = "<<P<<" atm, T = "<<T<<" K"; - cout <<endl<<"\t>> Heat duty = "<<Q; - if (success==true) cout <<" kW (converge normally)"; - cout << "\n\tEND\n\n"; - cost(); - power(); - water(); -} - - -double flash::get_cost ( void ) { - vol=15.0*(L->v+V->v); - if(vol<0.3) vol=0.3; if(vol>520)vol=520; - step = 3.4974+0.4485*log10(vol)+0.1074*pow(log10(vol),2); - step = pow(10, step); - P= (P-1)*101.325/100; - f_x=pow(2.0*vol/pi, 1.0/3.0); - vol=(P+1)*f_x/(317.46*(850-0.6*(P+1)))+0.0315; - step *=(2.25+ 1.82*vol*2.2); - step = step*MS_YEAR/MS_2001; - return step; -} - -void flash::cost() { - cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} -void flash::power() { - cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; - cout << "\t>>" << Q; - cout << "\n\tEND\n\n"; -} - -double flash::get_water ( void ) { - step = (Q<0.0) ? fabs(Q)/(4.185*0.10*(Tin-298)) : 0.0; - return step; -} - -void flash::water() { - cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; - if(Q<0.0) - step= (fabs(Q)/(4.185*0.10*(Tin-298))); - else - step= 0.0; - cout << "\t>>" << step; - cout << "\n\tEND\n\n"; -} +#include "flash.hpp" +#include "bissection.cpp" +using namespace std; + +flash::flash ( stream * in , stream * out_L , stream * out_V ) { + F = in; + Fcopy = new stream("Fcopy", F->nb, F->chem); + Tin = F->T; + z = new double[F->nb]; + for ( i = 0 ; i < F->nb ; i++ ) + z[i] = F->chem[i]->n()/F->n(); + + L = out_L; + V = out_V; + success = true; + K = new double[F->nb]; + task=0; + solver = new bissection<flash>(); +} + +void flash::set(double p, double t) +{ + P=p; + T=t; + for (i=0;i<F->nb;i++) + { + if(F->chem[i]->Tc<T) K[i] = F->chem[i]->Psat(T)/P; + else K[i]=1; + } + F->set(P,T); +} + +bool flash::solve() +{ + L->purge(); + V->purge(); + f_x=F->quality(); + + if( 0.0 < f_x && f_x < 1.0) + { + + // TOTO + for ( i = 0 ; i < F->nb ; i++ ) { + if ( F->chem[i]->Tc < T ) { + F->m -= F->chem[i]->m; + F->chem[i]->m = 0; + } + } + + for ( i = 0 ; i < F->nb ; i++ ) + z[i] = F->chem[i]->n()/F->n(); + + solver->set(this, 0.0, 1.0); + + success=solver->run(); + + if (!success) + { +// if(task==0){ +// log.open(MESSAGES, ios::app); +// log<<" --> Warning <-- Solver of FLASH "<<name<<" did not converge.\n"; +// log.close();} + for (i=0;i<F->nb;i++) + { + if (T<F->chem[i]->Tc && T>F->chem[i]->Tboil(P)) {V->chem[i]->m=F->chem[i]->m; V->m+=V->chem[i]->m;} + if (T<F->chem[i]->Tc && T<=F->chem[i]->Tboil(P)) {L->chem[i]->m=F->chem[i]->m; L->m+=L->chem[i]->m;} + } + } + else + { + + V->m = x*F->n(); + L->m = F->n() - V->m; + //Distribute liquid components + for (i=0;i<L->nb;i++) + { + L->chem[i]->m = (L->m*z[i])/(1+x*(K[i]-1))*L->chem[i]->M/1000.0; + L->chem[i]->state=0; + } + + + L->m=0.0; for(i=0;i<L->nb;i++) L->m+=L->chem[i]->m; + //Distribute vapor components + for (i=0;i<V->nb;i++) + { + V->chem[i]->m = V->m*L->chem[i]->n()*K[i]/L->n()*V->chem[i]->M/1000.0; + V->chem[i]->state=1; + } + V->m=0.0; for(i=0;i<V->nb;i++) V->m+=V->chem[i]->m; + } + for(i=0;i<F->nb;i++) + if(F->chem[i]->Tc<T){V->chem[i]->m=Fcopy->chem[i]->m; V->m+=Fcopy->chem[i]->m;} + + } + else + { + /* if(task==0) + { + log.open("runtime\\messages.r", ios::app); + if (T<F->dp) log<<" --> Warning <-- Mixture in "<<name<<" can't be flashed (bp="<<F->bp<<" dp="<<F->dp<<").\n"; + log.close(); + } */ + for (i=0;i<F->nb;i++) + { + if (F->chem[i]->Tc<T || f_x>=1) {V->chem[i]->m=Fcopy->chem[i]->m; V->m+=V->chem[i]->m; } + else {L->chem[i]->m=Fcopy->chem[i]->m; L->m+=L->chem[i]->m;} + + } + success = true; + } + L->set(P,T); + V->set(P,T); + Q = 0.0; + for (i=0;i<F->nb;i++) + { + Q += L->chem[i]->dH(Tin, T, P)*L->chem[i]->n(); + Q += V->chem[i]->dH(Tin, T, P)*V->chem[i]->n(); + } + F->m=0; + for(i=0;i<Fcopy->nb;i++) {F->chem[i]->m = Fcopy->chem[i]->m; F->m+=F->chem[i]->m;} + F->set(F->P,Tin); +// if(fabs(V->m+L->m-F->m)>sqrt(EPS)) +// { +// log.open(MESSAGES, ios::app); +// log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(V->m+L->m-F->m)/F->m<<").\n"; +// log.close(); +// } +// V->write();// TOTO + // L->write(); // TOTO + + return success; +} + +double flash::f(double psy) +{ + x=psy; + f_x=0.0; + for(i=0;i<F->nb;i++) f_x += (z[i]*(1-K[i]))/(1+psy*(K[i]-1)); + return f_x; +} + +bool flash::adiabatic() +{ + task=1; + F->set(P,T); T=F->dp; + step=-5; + Q=1; + + + while (fabs(step)>0.01 && fabs(Q)>0.1) + { + T+=step; + F->set(P,T); + + for (i=0;i<F->nb;i++) + K[i] = F->chem[i]->Psat(T)/P; + + success=solve(); + + + if (Q<0 && step<0) step*=-0.5; + if (Q>0 && step>0) step*=-0.5; + } + if (fabs(Q)<0.1) return true; + else return false; +} + +void flash::write() { + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout << "\t>> "<<name; + cout << endl << "\t>> stream in : "<<F->name; + cout <<endl<<"\t>> streams out : "<<L->name<<" (liq.) "<<V->name<<" (vap.)"; + cout <<endl<<"\t>> P = "<<P<<" atm, T = "<<T<<" K"; + cout <<endl<<"\t>> Heat duty = "<<Q; + if (success==true) cout <<" kW (converge normally)"; + cout << "\n\tEND\n\n"; + cost(); + power(); + water(); +} + + +double flash::get_cost ( void ) { + vol=15.0*(L->v+V->v); + if(vol<0.3) vol=0.3; if(vol>520)vol=520; + step = 3.4974+0.4485*log10(vol)+0.1074*pow(log10(vol),2); + step = pow(10, step); + P= (P-1)*101.325/100; + f_x=pow(2.0*vol/pi, 1.0/3.0); + vol=(P+1)*f_x/(317.46*(850-0.6*(P+1)))+0.0315; + step *=(2.25+ 1.82*vol*2.2); + step = step*MS_YEAR/MS_2001; + return step; +} + +void flash::cost() { + cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} +void flash::power() { + cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; + cout << "\t>>" << Q; + cout << "\n\tEND\n\n"; +} + +double flash::get_water ( void ) { + step = (Q<0.0) ? fabs(Q)/(4.185*0.10*(Tin-298)) : 0.0; + return step; +} + +void flash::water() { + cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; + if(Q<0.0) + step= (fabs(Q)/(4.185*0.10*(Tin-298))); + else + step= 0.0; + cout << "\t>>" << step; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/flash.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/flash.hpp index 29bc250..b6cdb41 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/flash.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/flash.hpp @@ -1,55 +1,55 @@ -/* -This unit takes operating P and T, and indexes of streams. It applies -the Rachford-Rice procedure to solve the isothermal flash problem -(ref : Seader & Henley). - -Structure in the .process file: -flash {name} {pressure} {temperature} {index of input stream} {index of output liquid and output vapor} - -How to use: - 1- Call the constructor : flash1 = new flash(in, out_L, out_V); //in is the feed, out_L is the liquid output and out_V is the vapor output - 2- Set P and T: flash1->set(P,T); - 3- Set the name: flash1->set(name); - 4a- Perform an isothermal flash : flash1->solve(); - 4b- Perform an adiabatic flash: flash1->adiabatic(); -*/ -#ifndef FLASH_H -#define FLASH_H - -#include "stream.hpp" -#include "bissection.hpp" -using namespace std; - -class flash { -private: - bool success; - bissection<flash> *solver; - // ofstream log, results; -// char name[31], filename[41]; //name of the unit - - string name; - - int i, task; //task=0: isothermal flash; task=1:adiabatic flash - stream *F, *Fcopy; //pointer to the input stream - stream *L, *V; //pointers to liquid and vapor output streams - double f_x, x, *K, *z; //pressure (given) and temperature (given) - double Q, Tin, step, vol; //required power, in kW - -public: - flash(){P=0.0; T=0.0;} - flash(stream*, stream*, stream*); //defines the connectivities of this unit - ~flash(){delete Fcopy; delete [] K; delete [] z; delete solver;} - double P ,T; - void set(double, double); - void set( const string & n ) { name = n; } - bool solve(); //applies the Rachford-Rice procedure - bool adiabatic(); //adiabatic isobaric flash - double f(double); //returns the function to the solver - void write(); - double get_water ( void ); - double get_cost ( void ); - - double get_power ( void ) const { return Q; } - void cost(), water(), power(); -}; -#endif +/* +This unit takes operating P and T, and indexes of streams. It applies +the Rachford-Rice procedure to solve the isothermal flash problem +(ref : Seader & Henley). + +Structure in the .process file: +flash {name} {pressure} {temperature} {index of input stream} {index of output liquid and output vapor} + +How to use: + 1- Call the constructor : flash1 = new flash(in, out_L, out_V); //in is the feed, out_L is the liquid output and out_V is the vapor output + 2- Set P and T: flash1->set(P,T); + 3- Set the name: flash1->set(name); + 4a- Perform an isothermal flash : flash1->solve(); + 4b- Perform an adiabatic flash: flash1->adiabatic(); +*/ +#ifndef FLASH_H +#define FLASH_H + +#include "stream.hpp" +#include "bissection.hpp" +using namespace std; + +class flash { +private: + bool success; + bissection<flash> *solver; + // ofstream log, results; +// char name[31], filename[41]; //name of the unit + + string name; + + int i, task; //task=0: isothermal flash; task=1:adiabatic flash + stream *F, *Fcopy; //pointer to the input stream + stream *L, *V; //pointers to liquid and vapor output streams + double f_x, x, *K, *z; //pressure (given) and temperature (given) + double Q, Tin, step, vol; //required power, in kW + +public: + flash(){P=0.0; T=0.0;} + flash(stream*, stream*, stream*); //defines the connectivities of this unit + ~flash(){delete Fcopy; delete [] K; delete [] z; delete solver;} + double P ,T; + void set(double, double); + void set( const string & n ) { name = n; } + bool solve(); //applies the Rachford-Rice procedure + bool adiabatic(); //adiabatic isobaric flash + double f(double); //returns the function to the solver + void write(); + double get_water ( void ); + double get_cost ( void ); + + double get_power ( void ) const { return Q; } + void cost(), water(), power(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/heatx.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/heatx.cpp index fd8942e..3c23822 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/heatx.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/heatx.cpp @@ -1,146 +1,146 @@ -#include "heatx.hpp" -#include "bissection.cpp" - -heatx::heatx(bool m, stream* s1, stream* s2) -{ - in = s1; - out = s2; - out->m=0; - for(i=0;i<in->nb;i++) - { - out->chem[i]->m=in->chem[i]->m; - out->m+=out->chem[i]->m; - } - solver = new bissection<heatx>(); - mode = m; - success = true; -} - -void heatx::set(double d1, double d2) -{ - if(mode==0) T=d1; - if(mode==1) Q=d1; - eta = d2; -} - -bool heatx::solve() -{ - if(mode==0) - { - Q = 0.0; - out->set(in->P, T); - // out->write(); // WRITE TOTO - for(i=0;i<in->nb;i++) - Q+=out->chem[i]->dH(in->T, out->T, in->P)*out->chem[i]->n(); - if(eta>EPS) - Qreal = Q/eta; - else { - Qreal=Q; - success=false; - } - } - if(mode==1) - { - Qreal = eta*Q; - min = in->T; - max = 2000; - solver->set(this, min, max); - success = solver->run(); - out->set(in->P, T); - //out->write(); // WRITE TOTO - } - return success; -} - - -double heatx::f(double x) -{ - T=x; - max = Qreal; - for(i=0;i<in->nb;i++) - max -= out->chem[i]->dH(in->T, T, in->P)*out->chem[i]->n(); - return max; -} - -void heatx::write() -{ - - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout << "\t>> " << name; - cout << endl << "\t>> stream in: " << in->name << " T = " << in->T <<" K"; - cout << endl << "\t>> stream out: " << out->name << " T = " << out->T <<" K"; - if (mode==0) - cout<<endl<<"\t>> Heat duty : "<<Qreal<<" kW"; - if (mode==1) - cout<<endl<<"\t>> Heat duty : "<<Q<<" kW"; - if (success) - cout<<endl<<"\t>> Heat losses "<<fabs(Qreal-Q)<<" kW (converged normally)"; - cout << "\n\tEND\n\n"; - - cost(); - power(); - water(); -} - - - -double heatx::get_cost ( void ) { - if(mode==1) min=fabs(Q)/0.225/(eta)/fabs(out->T-in->T); - if(mode==0) min=fabs(Qreal)/0.25/(eta)/fabs(out->T-in->T); - if(min<10) min=10; if(min>1000) min=1000; - max = 4.3247-0.303*log10(min)+0.1634*pow(log10(min),2); - T=in->P; - T = (T-1)*1.01325; - if (fabs(T)<EPS) T=0.1; if(T>100) T=100; - min=0.03881-0.11272*log10(T)+0.08183*pow(log10(T),2); - min=pow(10, min); - max = (1.63+1.66*2.5*min)*pow(10, max); - max = max*MS_YEAR/MS_2001; - return max; -} - - -void heatx::cost() -{ - cout << setprecision(5); - cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} - - - -double heatx::get_water ( void ) -{ - max = (Q<0.0) ? fabs(Q)/(4.185*0.10*(out->T-298)) : 0.0; - return max; -} - - -void heatx::water() -{ - if(Q<0.0) max = fabs(Q)/(4.185*0.10*(out->T-298)); - else max = 0.0; - cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; - cout << "\t>>" << max; - cout << "\n\tEND\n\n"; - -} - -double heatx::get_power ( void ) { - max = (mode) ? Q : Qreal; - if (max>EPS) - return max; - return 0.0; -} - -void heatx::power() -{ - if(mode==0) max = Qreal; - if(mode==1) max = Q; - - cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; - if(max>EPS) cout<< "\t>>" << max; - else cout<< "\t>>" << 0; - cout << "\n\tEND\n\n"; -} +#include "heatx.hpp" +#include "bissection.cpp" + +heatx::heatx(bool m, stream* s1, stream* s2) +{ + in = s1; + out = s2; + out->m=0; + for(i=0;i<in->nb;i++) + { + out->chem[i]->m=in->chem[i]->m; + out->m+=out->chem[i]->m; + } + solver = new bissection<heatx>(); + mode = m; + success = true; +} + +void heatx::set(double d1, double d2) +{ + if(mode==0) T=d1; + if(mode==1) Q=d1; + eta = d2; +} + +bool heatx::solve() +{ + if(mode==0) + { + Q = 0.0; + out->set(in->P, T); + // out->write(); // WRITE TOTO + for(i=0;i<in->nb;i++) + Q+=out->chem[i]->dH(in->T, out->T, in->P)*out->chem[i]->n(); + if(eta>EPS) + Qreal = Q/eta; + else { + Qreal=Q; + success=false; + } + } + if(mode==1) + { + Qreal = eta*Q; + min = in->T; + max = 2000; + solver->set(this, min, max); + success = solver->run(); + out->set(in->P, T); + //out->write(); // WRITE TOTO + } + return success; +} + + +double heatx::f(double x) +{ + T=x; + max = Qreal; + for(i=0;i<in->nb;i++) + max -= out->chem[i]->dH(in->T, T, in->P)*out->chem[i]->n(); + return max; +} + +void heatx::write() +{ + + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout << "\t>> " << name; + cout << endl << "\t>> stream in: " << in->name << " T = " << in->T <<" K"; + cout << endl << "\t>> stream out: " << out->name << " T = " << out->T <<" K"; + if (mode==0) + cout<<endl<<"\t>> Heat duty : "<<Qreal<<" kW"; + if (mode==1) + cout<<endl<<"\t>> Heat duty : "<<Q<<" kW"; + if (success) + cout<<endl<<"\t>> Heat losses "<<fabs(Qreal-Q)<<" kW (converged normally)"; + cout << "\n\tEND\n\n"; + + cost(); + power(); + water(); +} + + + +double heatx::get_cost ( void ) { + if(mode==1) min=fabs(Q)/0.225/(eta)/fabs(out->T-in->T); + if(mode==0) min=fabs(Qreal)/0.25/(eta)/fabs(out->T-in->T); + if(min<10) min=10; if(min>1000) min=1000; + max = 4.3247-0.303*log10(min)+0.1634*pow(log10(min),2); + T=in->P; + T = (T-1)*1.01325; + if (fabs(T)<EPS) T=0.1; if(T>100) T=100; + min=0.03881-0.11272*log10(T)+0.08183*pow(log10(T),2); + min=pow(10, min); + max = (1.63+1.66*2.5*min)*pow(10, max); + max = max*MS_YEAR/MS_2001; + return max; +} + + +void heatx::cost() +{ + cout << setprecision(5); + cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} + + + +double heatx::get_water ( void ) +{ + max = (Q<0.0) ? fabs(Q)/(4.185*0.10*(out->T-298)) : 0.0; + return max; +} + + +void heatx::water() +{ + if(Q<0.0) max = fabs(Q)/(4.185*0.10*(out->T-298)); + else max = 0.0; + cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; + cout << "\t>>" << max; + cout << "\n\tEND\n\n"; + +} + +double heatx::get_power ( void ) { + max = (mode) ? Q : Qreal; + if (max>EPS) + return max; + return 0.0; +} + +void heatx::power() +{ + if(mode==0) max = Qreal; + if(mode==1) max = Q; + + cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; + if(max>EPS) cout<< "\t>>" << max; + else cout<< "\t>>" << 0; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/heatx.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/heatx.hpp index d3b7dff..f9854ad 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/heatx.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/heatx.hpp @@ -1,49 +1,49 @@ -/* -This unit performs the heating of a stream (mode 0) or the heat -exchange to a stream (mode 1). -(ref : McCabe, Smith & Harriott) - -Structure in the .process file: -mode 0 : heatx {name} 0 {index of input stream} {index of output stream} {T out} {efficiency} //efficiency is a fraction between 0 and 1 -mode 1 : heatx {name} 1 {index of input stream} {index of output stream} {Q} {efficiency} //Q is the heat flow in kW -How to use: - 1- Call the constructor: heat = new heatx(mode, in, out); - 2- Set the operating conditions : heat->set(T_out, eta); //mode 0 - or : heat->set(Q, eta); //mode 1 - 3- Set the name of the unit: heat->set(name); - 4- Solve: bool=heat->solve(); -*/ -#ifndef HEATX_H -#define HEATX_H - -#include "stream.hpp" -#include "bissection.hpp" -using namespace std; - -class heatx -{ -private: - int i; - bool success, mode; - bissection<heatx> *solver; - // ofstream logf, results; - double min, max; - string name; - stream *in, *out; //streams of the unit - double eta, Q, Qreal, T; - -public: - heatx(){} - heatx(bool, stream*, stream*); //defines the connectivities of this unit - ~heatx(){delete solver;} - void set(double, double); - void set(const string & n) { name = n; } - double f(double); - bool solve(); - void write(); - void power(), water(), cost(); - double get_cost(); - double get_power(); - double get_water(); -}; -#endif +/* +This unit performs the heating of a stream (mode 0) or the heat +exchange to a stream (mode 1). +(ref : McCabe, Smith & Harriott) + +Structure in the .process file: +mode 0 : heatx {name} 0 {index of input stream} {index of output stream} {T out} {efficiency} //efficiency is a fraction between 0 and 1 +mode 1 : heatx {name} 1 {index of input stream} {index of output stream} {Q} {efficiency} //Q is the heat flow in kW +How to use: + 1- Call the constructor: heat = new heatx(mode, in, out); + 2- Set the operating conditions : heat->set(T_out, eta); //mode 0 + or : heat->set(Q, eta); //mode 1 + 3- Set the name of the unit: heat->set(name); + 4- Solve: bool=heat->solve(); +*/ +#ifndef HEATX_H +#define HEATX_H + +#include "stream.hpp" +#include "bissection.hpp" +using namespace std; + +class heatx +{ +private: + int i; + bool success, mode; + bissection<heatx> *solver; + // ofstream logf, results; + double min, max; + string name; + stream *in, *out; //streams of the unit + double eta, Q, Qreal, T; + +public: + heatx(){} + heatx(bool, stream*, stream*); //defines the connectivities of this unit + ~heatx(){delete solver;} + void set(double, double); + void set(const string & n) { name = n; } + double f(double); + bool solve(); + void write(); + void power(), water(), cost(); + double get_cost(); + double get_power(); + double get_water(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/mix.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/mix.cpp index dc02dc7..00202a2 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/mix.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/mix.cpp @@ -1,80 +1,80 @@ -#include "mix.hpp" -#include "bissection.cpp" -using namespace std; - -mix::mix ( int n , stream ** s1 , stream * s2 ) { - nb_in=n; - in = s1; - out= s2; - success = true; - solver = new bissection<mix>(); -} - -bool mix::solve() -{ - //Mass balance - out->m=0; - out->purge(); - for (j=0; j<out->nb;j++) - for (i=0;i<nb_in;i++) if(in[i]->chem[j]->m>EPS) - { - out->chem[j]->m+=in[i]->chem[j]->m; - out->m+=in[i]->chem[j]->m; - } - //Find the temperature - double max=0.0; double min=1e6; - for(i=0;i<nb_in;i++) - for(j=0;j<out->nb;j++) - { - if(in[i]->chem[j]->T>max && in[i]->chem[j]->m>EPS) max=in[i]->chem[j]->T; - if(in[i]->chem[j]->T<min && in[i]->chem[j]->m>EPS) min=in[i]->chem[j]->T; - } - if(fabs(max-min)<EPS) T=max; - else - { - solver->set(this, min, max); - success = solver->run(); - } - out->set(P,T); - // if (success==false) - // { - // log.open(MESSAGES, ios::app); - // log<<" --> Warning <-- Solver of "<<name<<" did not converge.\n"; - // log.close(); - // } - // min = 0; - // for(i=0;i<nb_in;i++) - // min+=in[i]->m; - // if(fabs(min-out->m)>sqrt(EPS)) - // { - // log.open(MESSAGES, ios::app); - // log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(min-out->m)/min<<").\n"; - // log.close(); - // } - - // out->write(); // WRITE TOTO - return success; -} - -double mix::f(double x) -{ - T=x; - double energy=0.0; //in kW - for (j=0; j<out->nb;j++) - for (i=0;i<nb_in;i++) - energy += in[i]->chem[j]->dH(in[i]->T, T, P)*in[i]->chem[j]->n()/1000; - return energy; -} - -void mix::write() { - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout << "\t>> " << name - << endl << "\t>> streams in: "; - for ( int i = 0 ; i < nb_in ; i++ ) - cout << in[i]->name << " "; - cout << endl << "\t>> stream out: " << out->name; - cout <<endl << "\t>> P = " << P << " atm, T = " << T; - if (success) - cout << " K (converged normally)"; - cout << "\n\tEND\n\n"; -} +#include "mix.hpp" +#include "bissection.cpp" +using namespace std; + +mix::mix ( int n , stream ** s1 , stream * s2 ) { + nb_in=n; + in = s1; + out= s2; + success = true; + solver = new bissection<mix>(); +} + +bool mix::solve() +{ + //Mass balance + out->m=0; + out->purge(); + for (j=0; j<out->nb;j++) + for (i=0;i<nb_in;i++) if(in[i]->chem[j]->m>EPS) + { + out->chem[j]->m+=in[i]->chem[j]->m; + out->m+=in[i]->chem[j]->m; + } + //Find the temperature + double max=0.0; double min=1e6; + for(i=0;i<nb_in;i++) + for(j=0;j<out->nb;j++) + { + if(in[i]->chem[j]->T>max && in[i]->chem[j]->m>EPS) max=in[i]->chem[j]->T; + if(in[i]->chem[j]->T<min && in[i]->chem[j]->m>EPS) min=in[i]->chem[j]->T; + } + if(fabs(max-min)<EPS) T=max; + else + { + solver->set(this, min, max); + success = solver->run(); + } + out->set(P,T); + // if (success==false) + // { + // log.open(MESSAGES, ios::app); + // log<<" --> Warning <-- Solver of "<<name<<" did not converge.\n"; + // log.close(); + // } + // min = 0; + // for(i=0;i<nb_in;i++) + // min+=in[i]->m; + // if(fabs(min-out->m)>sqrt(EPS)) + // { + // log.open(MESSAGES, ios::app); + // log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(min-out->m)/min<<").\n"; + // log.close(); + // } + + // out->write(); // WRITE TOTO + return success; +} + +double mix::f(double x) +{ + T=x; + double energy=0.0; //in kW + for (j=0; j<out->nb;j++) + for (i=0;i<nb_in;i++) + energy += in[i]->chem[j]->dH(in[i]->T, T, P)*in[i]->chem[j]->n()/1000; + return energy; +} + +void mix::write() { + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout << "\t>> " << name + << endl << "\t>> streams in: "; + for ( int i = 0 ; i < nb_in ; i++ ) + cout << in[i]->name << " "; + cout << endl << "\t>> stream out: " << out->name; + cout <<endl << "\t>> P = " << P << " atm, T = " << T; + if (success) + cout << " K (converged normally)"; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/mix.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/mix.hpp index 6d4ee0f..85b8d77 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/mix.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/mix.hpp @@ -1,44 +1,44 @@ -/* -This unit takes more than two input streams and merge them in one -output stream. The pressure must be specified by the user, and the -temperature of the output stream is computed. - -Structure in the .process file: -mix {name} {pressure} {nb_in} {indexes of input streams} {index of output stream} - -How to use: - 1- Call the constructor: mix1 = new mix(nb_in, list1_in, out); - 2- Set the operating pressure : mix1->set(P); - 3- Set the name of the unit: mix1->set(name); - 4- Solve: bool=mix1->solve(); -*/ -#ifndef MIX_H -#define MIX_H - -#include "stream.hpp" -#include "bissection.hpp" -using namespace std; - -class mix { - private: - int i, j; - bool success; - bissection<mix> *solver; - string name; - int nb_in; //number of input streams - stream **in; //list pointers to input streams - stream *out; //pointer to output stream - // double min, max; - - public: - double P, T; //pressure (given) and temperature (unknown) - mix(){P=0.0;} - mix(int, stream**, stream*); //defines the connectivities of this unit - ~mix(){delete solver;} - void set(double p) {P=p;} - void set ( const string & n ) { name = n; } - double f(double); //returns the function to the solver - bool solve(); //finds the temperature and computes mass balance - void write(); -}; -#endif +/* +This unit takes more than two input streams and merge them in one +output stream. The pressure must be specified by the user, and the +temperature of the output stream is computed. + +Structure in the .process file: +mix {name} {pressure} {nb_in} {indexes of input streams} {index of output stream} + +How to use: + 1- Call the constructor: mix1 = new mix(nb_in, list1_in, out); + 2- Set the operating pressure : mix1->set(P); + 3- Set the name of the unit: mix1->set(name); + 4- Solve: bool=mix1->solve(); +*/ +#ifndef MIX_H +#define MIX_H + +#include "stream.hpp" +#include "bissection.hpp" +using namespace std; + +class mix { + private: + int i, j; + bool success; + bissection<mix> *solver; + string name; + int nb_in; //number of input streams + stream **in; //list pointers to input streams + stream *out; //pointer to output stream + // double min, max; + + public: + double P, T; //pressure (given) and temperature (unknown) + mix(){P=0.0;} + mix(int, stream**, stream*); //defines the connectivities of this unit + ~mix(){delete solver;} + void set(double p) {P=p;} + void set ( const string & n ) { name = n; } + double f(double); //returns the function to the solver + bool solve(); //finds the temperature and computes mass balance + void write(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pfr.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pfr.cpp index bcb7ccf..5469451 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pfr.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pfr.cpp @@ -1,174 +1,174 @@ -#include "pfr.hpp" -#include "RungeKutta.cpp" -using namespace std; - -pfr::pfr ( stream * s1 , stream * s2 , double ** t , int nb_r , reaction ** rr , double u , double ta ) { - - F = s2; - F->m=0; - P=s1->P; - for ( i = 0 ; i < s1->nb ; i++ ) { - F->chem[i]->m = s1->chem[i]->m; - F->m+=F->chem[i]->m; - } - F->set(s1->P, s1->T); - m_in=F->m; - a = t; - rx = rr; - n=nb_r; - m= F->nb; - U=u; - Ta=ta; - T = F->T; - C = new double[m]; - y = new double[m+1]; - r=new double[n]; - OK=true; - explode=true; - solver = new RungeKutta<pfr>(m+1); -} - -pfr::~pfr() { - delete [] r; - delete [] C; - delete [] y; - delete solver; -} - -bool pfr::run() { - - for ( i = 0 ; i < m ; i++ ) - y[i]=F->chem[i]->n(); - - y[m]=T; - - solver->set ( this , y , 0.0 , L ); - - dL=solver->dx(); - - OK=solver->run(); - - sum = F->m; - F->m = 0; - - for ( i = 0 ; i < m ; i++ ) - F->m+=F->chem[i]->m; - for ( i = 0 ; i < m ; i++ ) - F->chem[i]->m *= sum/F->m; - // if (OK) - //mass balance! - if ( fabs(m_in-F->m) > EPS || !explode ) - OK=false; - - return OK; -} - -double pfr::f ( int eq , double l , double * y ) { - - - sum=F->m; - F->m=0; - for(i=0; i<m;i++) - { - if(y[i]<0) y[i]=0; - F->chem[i]->m = y[i]*F->chem[i]->M/1000.0; - F->m+=F->chem[i]->m; - } - - - for(i=0; i<m;i++) - F->chem[i]->m *= sum/F->m; - - - F->m=sum; - T=y[m]; - if(T>MAX_TEMP) - { - cout << "ERROR 11\n\n"; - exit(0); - } - - - for(i=0; i<m;i++) - C[i]=F->chem[i]->n()/F->v; - - for(j=0;j<n;j++) - r[j] = rx[j]->rate(T,C); - - if(0<=eq && eq<m) //return dFi/dL - { - tmp=0.0; - for(j=0;j<n;j++) tmp+=a[eq][j]*r[j]; - tmp *= (pi*D*D/4.0); - } - - - - if(eq==m) //return dT/dL - { - - - F->set(F->P,T); - - tmp=0.0; - for(j=0;j<n;j++) - tmp -= r[j]*rx[j]->dHr(T); - - - tmp *= (pi*D*D/4.0); - - - tmp += (pi*D)*U*(Ta-T); - - - tmp1=0.0; - for(i=0;i<m;i++) - tmp1+= y[i]*F->chem[i]->Cp()*0.001; - tmp /= tmp1; - - - if(fabs(tmp*dL)>500.0) - { - cout << "ERROR 13\n\n"; - exit(0); - } - } - - - - - return tmp; -} - - - -double pfr::get_cost ( void ) { - dL=L*pi*pow(D,2)/4.0; - if(dL<0.3) dL=0.3; if(dL>520) dL=520; - sum = 3.4974+0.4485*log10(dL)+0.1074*pow(log10(dL),2); - sum = pow(10, sum); - P= (P-1)*101.325/100; - dL=(P+1)*D/(317.46*(850-0.6*(P+1)))+0.0315; - sum *=(2.25+ 1.82*dL*4.2); - sum = sum*MS_YEAR/MS_2001; - return sum; -} - -double pfr::get_water() { - sum = (U>EPS && T>Ta) ? U*L*pi*pow(D,2)/4*(T-Ta)/4.185/25.0 : 0.0; - return sum; -} - -void pfr::cost() { - cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} - -void pfr::water() { - cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; - if (U>EPS && T>Ta) sum = (U*L*pi*pow(D,2)/4*(T-Ta)/4.185/25.0); - else sum = 0.0; - cout << "\t>>" << sum; - cout << "\n\tEND\n\n"; -} +#include "pfr.hpp" +#include "RungeKutta.cpp" +using namespace std; + +pfr::pfr ( stream * s1 , stream * s2 , double ** t , int nb_r , reaction ** rr , double u , double ta ) { + + F = s2; + F->m=0; + P=s1->P; + for ( i = 0 ; i < s1->nb ; i++ ) { + F->chem[i]->m = s1->chem[i]->m; + F->m+=F->chem[i]->m; + } + F->set(s1->P, s1->T); + m_in=F->m; + a = t; + rx = rr; + n=nb_r; + m= F->nb; + U=u; + Ta=ta; + T = F->T; + C = new double[m]; + y = new double[m+1]; + r=new double[n]; + OK=true; + explode=true; + solver = new RungeKutta<pfr>(m+1); +} + +pfr::~pfr() { + delete [] r; + delete [] C; + delete [] y; + delete solver; +} + +bool pfr::run() { + + for ( i = 0 ; i < m ; i++ ) + y[i]=F->chem[i]->n(); + + y[m]=T; + + solver->set ( this , y , 0.0 , L ); + + dL=solver->dx(); + + OK=solver->run(); + + sum = F->m; + F->m = 0; + + for ( i = 0 ; i < m ; i++ ) + F->m+=F->chem[i]->m; + for ( i = 0 ; i < m ; i++ ) + F->chem[i]->m *= sum/F->m; + // if (OK) + //mass balance! + if ( fabs(m_in-F->m) > EPS || !explode ) + OK=false; + + return OK; +} + +double pfr::f ( int eq , double l , double * y ) { + + + sum=F->m; + F->m=0; + for(i=0; i<m;i++) + { + if(y[i]<0) y[i]=0; + F->chem[i]->m = y[i]*F->chem[i]->M/1000.0; + F->m+=F->chem[i]->m; + } + + + for(i=0; i<m;i++) + F->chem[i]->m *= sum/F->m; + + + F->m=sum; + T=y[m]; + if(T>MAX_TEMP) + { + cout << "ERROR 11\n\n"; + exit(0); + } + + + for(i=0; i<m;i++) + C[i]=F->chem[i]->n()/F->v; + + for(j=0;j<n;j++) + r[j] = rx[j]->rate(T,C); + + if(0<=eq && eq<m) //return dFi/dL + { + tmp=0.0; + for(j=0;j<n;j++) tmp+=a[eq][j]*r[j]; + tmp *= (pi*D*D/4.0); + } + + + + if(eq==m) //return dT/dL + { + + + F->set(F->P,T); + + tmp=0.0; + for(j=0;j<n;j++) + tmp -= r[j]*rx[j]->dHr(T); + + + tmp *= (pi*D*D/4.0); + + + tmp += (pi*D)*U*(Ta-T); + + + tmp1=0.0; + for(i=0;i<m;i++) + tmp1+= y[i]*F->chem[i]->Cp()*0.001; + tmp /= tmp1; + + + if(fabs(tmp*dL)>500.0) + { + cout << "ERROR 13\n\n"; + exit(0); + } + } + + + + + return tmp; +} + + + +double pfr::get_cost ( void ) { + dL=L*pi*pow(D,2)/4.0; + if(dL<0.3) dL=0.3; if(dL>520) dL=520; + sum = 3.4974+0.4485*log10(dL)+0.1074*pow(log10(dL),2); + sum = pow(10, sum); + P= (P-1)*101.325/100; + dL=(P+1)*D/(317.46*(850-0.6*(P+1)))+0.0315; + sum *=(2.25+ 1.82*dL*4.2); + sum = sum*MS_YEAR/MS_2001; + return sum; +} + +double pfr::get_water() { + sum = (U>EPS && T>Ta) ? U*L*pi*pow(D,2)/4*(T-Ta)/4.185/25.0 : 0.0; + return sum; +} + +void pfr::cost() { + cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} + +void pfr::water() { + cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; + if (U>EPS && T>Ta) sum = (U*L*pi*pow(D,2)/4*(T-Ta)/4.185/25.0); + else sum = 0.0; + cout << "\t>>" << sum; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pfr.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pfr.hpp index 9746a50..a8f49a7 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pfr.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pfr.hpp @@ -1,36 +1,36 @@ -#ifndef PFR_H -#define PFR_H - -#include "reaction.hpp" -#include "RungeKutta.hpp" -#include "stream.hpp" -using namespace std; - -class pfr { -private: - // terminator *term; - // ofstream results; - string name; - bool OK, explode; - int i ,j, n, m; - double L,D,dL, U, Ta, m_in, sum, P; - stream *F; - double **a, *C, T, *y, *r, tmp, tmp1; - reaction **rx; - RungeKutta<pfr> *solver; - -public: - // pfr(){}; - pfr ( stream * , stream * , double ** , int , reaction ** , double , double ); - void set ( const string & n ) { name = n; } - void set(double l, double d) {L=l; D=d;} - bool run(); - void water(); - void cost(); - double get_cost ( void ); - double get_water ( void ); - - double f(int, double, double*); - ~pfr(); -}; -#endif +#ifndef PFR_H +#define PFR_H + +#include "reaction.hpp" +#include "RungeKutta.hpp" +#include "stream.hpp" +using namespace std; + +class pfr { +private: + // terminator *term; + // ofstream results; + string name; + bool OK, explode; + int i ,j, n, m; + double L,D,dL, U, Ta, m_in, sum, P; + stream *F; + double **a, *C, T, *y, *r, tmp, tmp1; + reaction **rx; + RungeKutta<pfr> *solver; + +public: + // pfr(){}; + pfr ( stream * , stream * , double ** , int , reaction ** , double , double ); + void set ( const string & n ) { name = n; } + void set(double l, double d) {L=l; D=d;} + bool run(); + void water(); + void cost(); + double get_cost ( void ); + double get_water ( void ); + + double f(int, double, double*); + ~pfr(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/profitability.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/profitability.cpp index 902f30d..3617b30 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/profitability.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/profitability.cpp @@ -1,138 +1,138 @@ -#include "profitability.hpp" -#include "secant.cpp" -using namespace std; - -bool profitability::run ( double * y ) -{ - OK=true; - - // cout<<setiosflags(ios::fixed); - // cout<<endl<<endl<<" PROFITABILITY ANALYSIS"<<endl; - // cout<<endl<<setprecision(1)<<" Return on investment (%)= "<<ROI()*100.0; - // cout<<endl<<" Rate of return (%)= "<<RR()*100.0; // y[10] - - y[10] = RR()*100.0; // y[10] - - ROI(); - RR(); - - // cout<<endl<<" Discounted flow rate (%)= "<<DFR()*100.0; - - DFR(); - - // cout<<endl<<endl<<" Payout time (y)= "<<PT(); // y[ 9] - y[9] = PT(); - - // cout<<endl<<setprecision(0)<<" Annual equivalent cost ($)= "<<AEC(); // y[12] - y[12] = AEC(); - - // cout<<endl<<" Net present value ($)= "<<NPV()<<endl; // y[13] - y[13] = NPV(); - - return OK; -} - -double profitability::ROI() -{ - // if(!MUTE)cout<<endl<<" return on investment..."; - num=den=0.0; - for(i=0;i<C->N;i++) - { - if(C->Inv[i]>EPS) den+=C->Inv[i]; - num+=(C->Rev[i]-C->Coper[i]-C->Amort[i]); - } - if (num>EPS && den>EPS && C->N>0) { - // if(!MUTE)cout<<" OK"; - return num/C->N/den; - } - else return 0.0; -} - -double profitability::RR() -{ - // if(!MUTE)cout<<endl<<" rate of return..."; - num=den=0.0; - for(i=0;i<C->N;i++) - { - num+=(C->Rev[i]-C->Coper[i])/pow(1.0+C->i_rate, i); - den+=C->Inv[i]/pow(1.0+C->i_rate, i); - } - if(num>EPS && den>EPS) { - // if(!MUTE)cout<<" OK"; - return num/den; - } - else return 0.0; -} - -double profitability::DFR() -{ - //if(!MUTE)cout<<endl<<" discounted cash flow rate..."; - solver = new secant<profitability>(); - solver->set(this, 0.0, 0.01); - OK = solver->run(); - - if ( OK && num>EPS && num < 1e20 ) { - // if(!MUTE)cout<<" OK"; - return num; - } - else return 0.0; -} - -double profitability::f(double x) -{ - num=x; - sum=0.0; - for(i=0;i<C->N;i++) - sum += C->Flow[i]/pow(1.0+x, i); - return sum; -} - -double profitability::PT() -{ - // if(!MUTE)cout<<endl<<" payout time..."; - sum=0.0; - for(i=0;i<C->N;i++) - { - if((sum+C->Flow[i])>0.0) - { - den=0.0; - while(sum+den*C->Flow[i]<=0.0) den+=0.001; - den+=double(i-1); - i=C->N; - } - else sum+=C->Flow[i]; - } - - if(den>EPS) { - // if(!MUTE)cout<<" OK"; - return den; - } - else return 0.0; -} - -double profitability::AEC() -{ - //if(!MUTE)cout<<endl<<" annual equivalent cost..."; - sum=0.0; - for(i=0;i<C->N;i++) sum+=(C->Coper[i]+C->Inv[i])/pow(1.0+C->i_rate, i); - if (sum>EPS) { -// if(!MUTE) -// cout<<" OK"; - return sum*(C->i_rate*pow(1.0+C->i_rate,C->N))/(pow(1.0+C->i_rate,C->N)-1.0); - } - else return 0.0; -} - -double profitability::NPV() -{ - // if(!MUTE)cout<<endl<<" net present value..."; - sum=0.0; - for ( i = 0 ; i < C->N ; i++ ) - sum += C->Flowact[i]; - if ( sum > EPS ) { -// if(!MUTE) -// cout<<" OK"; - return sum; - } - return 0.0; -} +#include "profitability.hpp" +#include "secant.cpp" +using namespace std; + +bool profitability::run ( double * y ) +{ + OK=true; + + // cout<<setiosflags(ios::fixed); + // cout<<endl<<endl<<" PROFITABILITY ANALYSIS"<<endl; + // cout<<endl<<setprecision(1)<<" Return on investment (%)= "<<ROI()*100.0; + // cout<<endl<<" Rate of return (%)= "<<RR()*100.0; // y[10] + + y[10] = RR()*100.0; // y[10] + + ROI(); + RR(); + + // cout<<endl<<" Discounted flow rate (%)= "<<DFR()*100.0; + + DFR(); + + // cout<<endl<<endl<<" Payout time (y)= "<<PT(); // y[ 9] + y[9] = PT(); + + // cout<<endl<<setprecision(0)<<" Annual equivalent cost ($)= "<<AEC(); // y[12] + y[12] = AEC(); + + // cout<<endl<<" Net present value ($)= "<<NPV()<<endl; // y[13] + y[13] = NPV(); + + return OK; +} + +double profitability::ROI() +{ + // if(!MUTE)cout<<endl<<" return on investment..."; + num=den=0.0; + for(i=0;i<C->N;i++) + { + if(C->Inv[i]>EPS) den+=C->Inv[i]; + num+=(C->Rev[i]-C->Coper[i]-C->Amort[i]); + } + if (num>EPS && den>EPS && C->N>0) { + // if(!MUTE)cout<<" OK"; + return num/C->N/den; + } + else return 0.0; +} + +double profitability::RR() +{ + // if(!MUTE)cout<<endl<<" rate of return..."; + num=den=0.0; + for(i=0;i<C->N;i++) + { + num+=(C->Rev[i]-C->Coper[i])/pow(1.0+C->i_rate, i); + den+=C->Inv[i]/pow(1.0+C->i_rate, i); + } + if(num>EPS && den>EPS) { + // if(!MUTE)cout<<" OK"; + return num/den; + } + else return 0.0; +} + +double profitability::DFR() +{ + //if(!MUTE)cout<<endl<<" discounted cash flow rate..."; + solver = new secant<profitability>(); + solver->set(this, 0.0, 0.01); + OK = solver->run(); + + if ( OK && num>EPS && num < 1e20 ) { + // if(!MUTE)cout<<" OK"; + return num; + } + else return 0.0; +} + +double profitability::f(double x) +{ + num=x; + sum=0.0; + for(i=0;i<C->N;i++) + sum += C->Flow[i]/pow(1.0+x, i); + return sum; +} + +double profitability::PT() +{ + // if(!MUTE)cout<<endl<<" payout time..."; + sum=0.0; + for(i=0;i<C->N;i++) + { + if((sum+C->Flow[i])>0.0) + { + den=0.0; + while(sum+den*C->Flow[i]<=0.0) den+=0.001; + den+=double(i-1); + i=C->N; + } + else sum+=C->Flow[i]; + } + + if(den>EPS) { + // if(!MUTE)cout<<" OK"; + return den; + } + else return 0.0; +} + +double profitability::AEC() +{ + //if(!MUTE)cout<<endl<<" annual equivalent cost..."; + sum=0.0; + for(i=0;i<C->N;i++) sum+=(C->Coper[i]+C->Inv[i])/pow(1.0+C->i_rate, i); + if (sum>EPS) { +// if(!MUTE) +// cout<<" OK"; + return sum*(C->i_rate*pow(1.0+C->i_rate,C->N))/(pow(1.0+C->i_rate,C->N)-1.0); + } + else return 0.0; +} + +double profitability::NPV() +{ + // if(!MUTE)cout<<endl<<" net present value..."; + sum=0.0; + for ( i = 0 ; i < C->N ; i++ ) + sum += C->Flowact[i]; + if ( sum > EPS ) { +// if(!MUTE) +// cout<<" OK"; + return sum; + } + return 0.0; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/profitability.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/profitability.hpp index 03f85c5..194102c 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/profitability.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/profitability.hpp @@ -1,30 +1,30 @@ -#ifndef PROFITABILITY_H -#define PROFITABILITY_H -#include "cashflow.hpp" -#include "secant.hpp" - -#include <iomanip> - -using namespace std; - -class profitability -{ -private: - cashflow *C; -// ofstream out; -// char name[41]; - bool OK; - double ROI(), RR(), DFR(); - double PT(), AEC(), NPV(); - int i; - double den, num, sum; - secant<profitability> *solver; - -public: - profitability(cashflow* c){C=c;} - ~profitability(){delete solver;}; - // void set(char n[31]) {strcpy(name, n); strcat(name, ".econo");} - bool run ( double * y ); - double f(double); -}; -#endif +#ifndef PROFITABILITY_H +#define PROFITABILITY_H +#include "cashflow.hpp" +#include "secant.hpp" + +#include <iomanip> + +using namespace std; + +class profitability +{ +private: + cashflow *C; +// ofstream out; +// char name[41]; + bool OK; + double ROI(), RR(), DFR(); + double PT(), AEC(), NPV(); + int i; + double den, num, sum; + secant<profitability> *solver; + +public: + profitability(cashflow* c){C=c;} + ~profitability(){delete solver;}; + // void set(char n[31]) {strcpy(name, n); strcat(name, ".econo");} + bool run ( double * y ); + double f(double); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pump.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pump.cpp index 166123f..685a0be 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pump.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pump.cpp @@ -1,94 +1,94 @@ -#include "pump.hpp" -using namespace std; - -bool pump::solve() { - - // out->chem = in->chem; - out->set ( in->nb , in->chem ); - out->m = in->m; - - - in->set(in->P,in->T); - for ( i = 0 ; i < in->nb ; i++ ) - if(in->chem[i]->m>EPS) { - in->chem[i]->find_v(); - if(in->chem[i]->state==1) { - W+=in->chem[i]->gamma()*in->T*0.0083144*in->chem[i]->n()/ - (in->chem[i]->gamma()-1.0)*(pow(P/in->P, 1.0-1.0/in->chem[i]->gamma())-1.0); - tmp += in->chem[i]->gamma(); - n++; - } - if(in->chem[i]->state==0) - W+=in->chem[i]->v*(P-in->P)*101.325; - } - if (fabs(state-1)<EPS) //compressing gases - out->T = in->T*pow(P/in->P, 1.0-1.0/(tmp/n)); - else //compressing liquids - out->T=in->T; - out->set(P, out->T); - if(eta>EPS) - W /= eta; - else - success=false; - // out->write(); // WRITE TOTO - return success; -} - -void pump::write() { - - cout << setprecision(6); - - string file_name = RUNTIME + name + ".unit"; - cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; - cout <<"\t>> " << name; - cout << endl << "\t>> stream in: "<<in->name<<" out: "<<out->name; - cout << endl << "\t>> P(in) = "<<in->P<<" P(out) = "<<out->P<<" atm"; - cout << endl << "\t>> T(in) = "<<in->T<<" T(out) = "<<out->T<<" K"; - cout << endl << "\t>> Shaft work = "<<W; - if (success) - cout <<" kW (converge normally)"; - cout << "\n\tEND\n\n"; - - power(); - cost(); -} - - -double pump::get_cost ( void ) { - - if ( fabs(state-1) < EPS ) { - if(W<450) W=450; if(W>3000)W=3000; - tmp=2.2891+1.3604*log10(W)-0.1027*pow(log10(W),2); - tmp=3.2*pow(10.0, tmp); - tmp1=2.4604+1.4191*log10(W)-0.1798*pow(log10(W),2); - tmp1=1.5*pow(10.0, tmp1); - tmp+=tmp1; - } - else { - if(W<1) W=1; if(W>300)W=300; - tmp=3.3892+0.0536*log10(W)+0.1538*pow(log10(W),2); - tmp=pow(10.0, tmp); - P=(P-1.0)*101.325/100.0; - if (P<EPS) P=1; if(P>100) P=100; - W = -0.3925+0.3957*log10(P)-0.00226*pow(log10(P),2); - W=pow(10.0, W); if(W<1) W=1; - tmp*=(1.89+1.35*W*1.8); - } - tmp = tmp*MS_YEAR/MS_2001; - return tmp; -} - - -void pump::cost() { - string file_name = RUNTIME + name + ".cost"; - cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} - -void pump::power() { - string file_name = RUNTIME + name + ".power"; - cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; - cout << "\t>>" << W; - cout << "\n\tEND\n\n"; -} +#include "pump.hpp" +using namespace std; + +bool pump::solve() { + + // out->chem = in->chem; + out->set ( in->nb , in->chem ); + out->m = in->m; + + + in->set(in->P,in->T); + for ( i = 0 ; i < in->nb ; i++ ) + if(in->chem[i]->m>EPS) { + in->chem[i]->find_v(); + if(in->chem[i]->state==1) { + W+=in->chem[i]->gamma()*in->T*0.0083144*in->chem[i]->n()/ + (in->chem[i]->gamma()-1.0)*(pow(P/in->P, 1.0-1.0/in->chem[i]->gamma())-1.0); + tmp += in->chem[i]->gamma(); + n++; + } + if(in->chem[i]->state==0) + W+=in->chem[i]->v*(P-in->P)*101.325; + } + if (fabs(state-1)<EPS) //compressing gases + out->T = in->T*pow(P/in->P, 1.0-1.0/(tmp/n)); + else //compressing liquids + out->T=in->T; + out->set(P, out->T); + if(eta>EPS) + W /= eta; + else + success=false; + // out->write(); // WRITE TOTO + return success; +} + +void pump::write() { + + cout << setprecision(6); + + string file_name = RUNTIME + name + ".unit"; + cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; + cout <<"\t>> " << name; + cout << endl << "\t>> stream in: "<<in->name<<" out: "<<out->name; + cout << endl << "\t>> P(in) = "<<in->P<<" P(out) = "<<out->P<<" atm"; + cout << endl << "\t>> T(in) = "<<in->T<<" T(out) = "<<out->T<<" K"; + cout << endl << "\t>> Shaft work = "<<W; + if (success) + cout <<" kW (converge normally)"; + cout << "\n\tEND\n\n"; + + power(); + cost(); +} + + +double pump::get_cost ( void ) { + + if ( fabs(state-1) < EPS ) { + if(W<450) W=450; if(W>3000)W=3000; + tmp=2.2891+1.3604*log10(W)-0.1027*pow(log10(W),2); + tmp=3.2*pow(10.0, tmp); + tmp1=2.4604+1.4191*log10(W)-0.1798*pow(log10(W),2); + tmp1=1.5*pow(10.0, tmp1); + tmp+=tmp1; + } + else { + if(W<1) W=1; if(W>300)W=300; + tmp=3.3892+0.0536*log10(W)+0.1538*pow(log10(W),2); + tmp=pow(10.0, tmp); + P=(P-1.0)*101.325/100.0; + if (P<EPS) P=1; if(P>100) P=100; + W = -0.3925+0.3957*log10(P)-0.00226*pow(log10(P),2); + W=pow(10.0, W); if(W<1) W=1; + tmp*=(1.89+1.35*W*1.8); + } + tmp = tmp*MS_YEAR/MS_2001; + return tmp; +} + + +void pump::cost() { + string file_name = RUNTIME + name + ".cost"; + cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} + +void pump::power() { + string file_name = RUNTIME + name + ".power"; + cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; + cout << "\t>>" << W; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pump.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pump.hpp index dbcacfd..aac9e6b 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pump.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/pump.hpp @@ -1,46 +1,46 @@ -/* -This unit takes one input stream and divides in two or more -output streams. The pressure and temparature of output streams -are the same as the input's. -(ref : McCabe, Smith & Harriott) - -Structure in the .process file: -pump {name} {index of input stream} {index of output stream} {output pressure in atm} {efficiency, between 0 and 1} - -How to use: - 1- Call the constructor: pump1 = new pump(in, out); - 2- Set conditions: pump1->set(P_output, efficiency); - 3- Set the name: pump1->set(name); - 4- Solve: pump1->solve(); -*/ -#ifndef PUMP_H -#define PUMP_H - -#include "stream.hpp" -using namespace std; - -class pump -{ -private: - int i, j, n; - double state, tmp, tmp1; - bool success; - string name; - stream *in; //pointer to input stream - stream *out; //pointer to output stream - -public: - double P, W, eta; //output presure in atm, work in kW and efficiency - pump(stream* s1, stream* s2) {in=s1; out=s2; success=true; W=0.0; n=0; tmp=0.0;} - ~pump(){} - void set(double p, double e){P = p; eta = e; state=in->quality();} - void set(const string & n) { name = n; } - bool solve(); //finds the temperature and computes mass balance - void write(); - void cost(); - double get_cost(); // calcule W aussi - double get_power() const { return W; } - - void power(); -}; -#endif +/* +This unit takes one input stream and divides in two or more +output streams. The pressure and temparature of output streams +are the same as the input's. +(ref : McCabe, Smith & Harriott) + +Structure in the .process file: +pump {name} {index of input stream} {index of output stream} {output pressure in atm} {efficiency, between 0 and 1} + +How to use: + 1- Call the constructor: pump1 = new pump(in, out); + 2- Set conditions: pump1->set(P_output, efficiency); + 3- Set the name: pump1->set(name); + 4- Solve: pump1->solve(); +*/ +#ifndef PUMP_H +#define PUMP_H + +#include "stream.hpp" +using namespace std; + +class pump +{ +private: + int i, j, n; + double state, tmp, tmp1; + bool success; + string name; + stream *in; //pointer to input stream + stream *out; //pointer to output stream + +public: + double P, W, eta; //output presure in atm, work in kW and efficiency + pump(stream* s1, stream* s2) {in=s1; out=s2; success=true; W=0.0; n=0; tmp=0.0;} + ~pump(){} + void set(double p, double e){P = p; eta = e; state=in->quality();} + void set(const string & n) { name = n; } + bool solve(); //finds the temperature and computes mass balance + void write(); + void cost(); + double get_cost(); // calcule W aussi + double get_power() const { return W; } + + void power(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reaction.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reaction.cpp index ee658e5..9eaafc1 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reaction.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reaction.cpp @@ -1,204 +1,204 @@ -#include "reaction.hpp" -using namespace std; - - -int reaction::find_chemical ( const string & chem_name ) const { - for ( int i = 0 ; i < m ; i++ ) - if ( list[i]->CAS == chem_name ) - return i; - return -1; -} - -// donnees hardcodees -reaction::reaction ( const string & in1 , int dim , chemical ** in2 ) { - - m = dim; // nbre de chemicals - list = in2; // liste des chemicals - - n = new double[m]; - safe_n = new double[m]; - safe_a = new double[m]; - a = new double[m]; - - int i , j; - for ( i = 0 ; i < m ; i++ ) { - a[i]=0.0; - n[i]=0.0; - } - - // 1/5 : - if ( in1 == "eb2sty" ) { - k0 = 3.525e5; - E = 90.85; - if ( (j = find_chemical ("100-41-4")) < 0 ) { - cout << "ERROR 10a\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("1333-74-0")) < 0 ) { - cout << "ERROR 10b\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - if ( (j = find_chemical ("100-42-5")) < 0 ) { - cout << "ERROR 10c\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - } - - // 2/5 : - else if ( in1 == "sty2eb" ) { - k0 = 2.754e-4; - E = -18.653; - if ( (j = find_chemical ("100-41-4")) < 0 ) { - cout << "ERROR 10d\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - if ( (j = find_chemical ("1333-74-0")) < 0 ) { - cout << "ERROR 10e\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("100-42-5")) < 0 ) { - cout << "ERROR 10f\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - } - - // 3/5 : - else if ( in1 == "eb2bz" ) { - k0 = 9.577e4; - E = 111.375; - if ( (j = find_chemical ("100-41-4")) < 0 ) { - cout << "ERROR 10g\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("71-43-2")) < 0 ) { - cout << "ERROR 10h\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - if ( (j = find_chemical ("74-85-1")) < 0 ) { - cout << "ERROR 10i\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - } - - // 4/5 : - else if ( in1 == "eb2tol" ) { - k0 = 6.077e8; - E = 207.850; - if ( (j = find_chemical ("100-41-4")) < 0 ) { - cout << "ERROR 10j\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("1333-74-0")) < 0 ) { - cout << "ERROR 10k\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("108-88-3")) < 0 ) { - cout << "ERROR 10l\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - if ( (j = find_chemical ("74-82-8")) < 0 ) { - cout << "ERROR 10m\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - } - - // 5/5 : - else if ( in1 == "tol2bz" ) { - k0 = 1; - E = 19.038; - if ( (j = find_chemical ("1333-74-0")) < 0 ) { - cout << "ERROR 10n\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 0.5; - if ( (j = find_chemical ("108-88-3")) < 0 ) { - cout << "ERROR 10o\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("71-43-2")) < 0 ) { - cout << "ERROR 10p\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - if ( (j = find_chemical ("74-82-8")) < 0 ) { - cout << "ERROR 10q\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - } - else { - cout << "ERROR 12\n\n"; - exit(0); - } - - for ( i = 0 ; i < m ; i++ ) { - safe_n[i]=n[i]; - safe_a[i]=a[i]; - } -} - -reaction::~reaction() { - delete [] a; - delete [] n; - delete [] safe_n; - delete [] safe_a; -} - -double reaction::dHr(double T) -{ - int i , j; - for (i=0;i<m;i++) - if(safe_a[i]!=a[i]) - { - if(a[i]>safe_a[i]) a[i]=safe_a[i]; - else safe_a[i]=a[i]; - } - double tmp=0.0; - for (i=0;i<m;i++) tmp += a[i]*list[i]->Ho; - if(fabs(T-298)>EPS) - for (i=0;i<m;i++) - for (j=1;j<=4;j++) tmp += a[i]*list[i]->Cp_param[j-1]*(pow(T,j)-pow(298.0,j))/j/1000.0; - return tmp; -} - -double reaction::rate(double T, double* C) -{ - double tmp = k0*exp(-1000*E/8.3144/T); - for ( int i=0;i<m;i++) - { - if(safe_n[i]!=n[i]) n[i]=safe_n[i]; - if(C[i]>EPS && fabs(n[i])>EPS) tmp *= pow(C[i], n[i]); - } - return tmp; -} +#include "reaction.hpp" +using namespace std; + + +int reaction::find_chemical ( const string & chem_name ) const { + for ( int i = 0 ; i < m ; i++ ) + if ( list[i]->CAS == chem_name ) + return i; + return -1; +} + +// donnees hardcodees +reaction::reaction ( const string & in1 , int dim , chemical ** in2 ) { + + m = dim; // nbre de chemicals + list = in2; // liste des chemicals + + n = new double[m]; + safe_n = new double[m]; + safe_a = new double[m]; + a = new double[m]; + + int i , j; + for ( i = 0 ; i < m ; i++ ) { + a[i]=0.0; + n[i]=0.0; + } + + // 1/5 : + if ( in1 == "eb2sty" ) { + k0 = 3.525e5; + E = 90.85; + if ( (j = find_chemical ("100-41-4")) < 0 ) { + cout << "ERROR 10a\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("1333-74-0")) < 0 ) { + cout << "ERROR 10b\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + if ( (j = find_chemical ("100-42-5")) < 0 ) { + cout << "ERROR 10c\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + } + + // 2/5 : + else if ( in1 == "sty2eb" ) { + k0 = 2.754e-4; + E = -18.653; + if ( (j = find_chemical ("100-41-4")) < 0 ) { + cout << "ERROR 10d\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + if ( (j = find_chemical ("1333-74-0")) < 0 ) { + cout << "ERROR 10e\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("100-42-5")) < 0 ) { + cout << "ERROR 10f\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + } + + // 3/5 : + else if ( in1 == "eb2bz" ) { + k0 = 9.577e4; + E = 111.375; + if ( (j = find_chemical ("100-41-4")) < 0 ) { + cout << "ERROR 10g\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("71-43-2")) < 0 ) { + cout << "ERROR 10h\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + if ( (j = find_chemical ("74-85-1")) < 0 ) { + cout << "ERROR 10i\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + } + + // 4/5 : + else if ( in1 == "eb2tol" ) { + k0 = 6.077e8; + E = 207.850; + if ( (j = find_chemical ("100-41-4")) < 0 ) { + cout << "ERROR 10j\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("1333-74-0")) < 0 ) { + cout << "ERROR 10k\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("108-88-3")) < 0 ) { + cout << "ERROR 10l\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + if ( (j = find_chemical ("74-82-8")) < 0 ) { + cout << "ERROR 10m\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + } + + // 5/5 : + else if ( in1 == "tol2bz" ) { + k0 = 1; + E = 19.038; + if ( (j = find_chemical ("1333-74-0")) < 0 ) { + cout << "ERROR 10n\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 0.5; + if ( (j = find_chemical ("108-88-3")) < 0 ) { + cout << "ERROR 10o\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("71-43-2")) < 0 ) { + cout << "ERROR 10p\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + if ( (j = find_chemical ("74-82-8")) < 0 ) { + cout << "ERROR 10q\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + } + else { + cout << "ERROR 12\n\n"; + exit(0); + } + + for ( i = 0 ; i < m ; i++ ) { + safe_n[i]=n[i]; + safe_a[i]=a[i]; + } +} + +reaction::~reaction() { + delete [] a; + delete [] n; + delete [] safe_n; + delete [] safe_a; +} + +double reaction::dHr(double T) +{ + int i , j; + for (i=0;i<m;i++) + if(safe_a[i]!=a[i]) + { + if(a[i]>safe_a[i]) a[i]=safe_a[i]; + else safe_a[i]=a[i]; + } + double tmp=0.0; + for (i=0;i<m;i++) tmp += a[i]*list[i]->Ho; + if(fabs(T-298)>EPS) + for (i=0;i<m;i++) + for (j=1;j<=4;j++) tmp += a[i]*list[i]->Cp_param[j-1]*(pow(T,j)-pow(298.0,j))/j/1000.0; + return tmp; +} + +double reaction::rate(double T, double* C) +{ + double tmp = k0*exp(-1000*E/8.3144/T); + for ( int i=0;i<m;i++) + { + if(safe_n[i]!=n[i]) n[i]=safe_n[i]; + if(C[i]>EPS && fabs(n[i])>EPS) tmp *= pow(C[i], n[i]); + } + return tmp; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reaction.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reaction.hpp index f05b27e..1456e0d 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reaction.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reaction.hpp @@ -1,32 +1,32 @@ -#ifndef REACTION_H -#define REACTION_H - -#include "chemical.hpp" -using namespace std; - -class reaction { -private: - - int m; - double *n, k0, E, Hr, *safe_n, *safe_a; - // double tmp; -// char file[41], line[31]; - chemical ** list; -// ifstream in; - // ofstream logf; - // terminator *end; - - int find_chemical ( const string & chem_name ) const; - -public: - // reaction(){}; - reaction ( const string & , int , chemical ** ); - ~reaction(); - double *a; //contains the molar coefficients - double dHr(double); //returns heat of rection at T, in kJ/mol - double rate(double, double*); //returns rate of reaction aT and C[], in mol/s.m3 - -// void show_name(){cout<<name;} -}; - -#endif +#ifndef REACTION_H +#define REACTION_H + +#include "chemical.hpp" +using namespace std; + +class reaction { +private: + + int m; + double *n, k0, E, Hr, *safe_n, *safe_a; + // double tmp; +// char file[41], line[31]; + chemical ** list; +// ifstream in; + // ofstream logf; + // terminator *end; + + int find_chemical ( const string & chem_name ) const; + +public: + // reaction(){}; + reaction ( const string & , int , chemical ** ); + ~reaction(); + double *a; //contains the molar coefficients + double dHr(double); //returns heat of rection at T, in kJ/mol + double rate(double, double*); //returns rate of reaction aT and C[], in mol/s.m3 + +// void show_name(){cout<<name;} +}; + +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reactor.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reactor.cpp index 0f0ddae..7f6e3a9 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reactor.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reactor.cpp @@ -1,100 +1,100 @@ -#include "reactor.hpp" -using namespace std; - -template<class TYPE> -reactor<TYPE>::reactor(stream* s1, stream* s2) -{ - in = s1; - out = s2; - - model = NULL; -} - -template<class TYPE> -reactor<TYPE>::~reactor() { - for ( i = 0 ; i < n ; i++ ) - delete rx[i]; - delete [] rx; - for ( i = 0 ; i < m ; i++ ) - delete table[i]; - delete [] table; - - if (model) - delete model; -} - -template<class TYPE> -void reactor<TYPE>::set ( double l , double d , int nb , const string * list_rx ) { - m = in->nb; - n = nb; - L = l; - D = d; - V = pi*pow(D/2.0, 2)*L; - - double * yields = new double [n]; - - rx = new reaction * [n]; - for ( j = 0 ; j < n ; j++ ) - rx[j] = new reaction ( list_rx[j] , m , in->chem ); - - table = new double * [m]; - for ( i = 0 ; i < m ; i++ ) - table[i] = new double[n]; - for ( j = 0 ; j < n ; j++ ) - for ( i = 0 ; i < m ; i++ ) - table[i][j] = rx[j]->a[i]; - for ( j = 0 ; j < n ; j++ ) { - yields[j]=0.0; - for ( i = 0 ; i < m ; i++ ) - if ( table[i][j] < 0 ) { - yields[j]=in->chem[i]->n(); - i=m; - } - } - - delete [] yields; - -} - -template<class TYPE> -bool reactor<TYPE>::solve() { - - if (model) - delete model; - model = new TYPE(in, out, table, n, rx, U, Ta); - model->set(name); - model->set(L,D); - - success = model->run(); - - // if(fabs(in->m-out->m)>sqrt(EPS)) - // { - // log.open(MESSAGES, ios::app); - // log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(in->m-out->m)/in->m<<").\n"; - // log.close(); - // } - - - // out->write(); // WRITE TOTO - - return success; -} - -template<class TYPE> -void reactor<TYPE>::write ( void ) { - - cout << setprecision(6); - - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout << "\t>> " << name; - cout << endl << "\t>> stream in : " << in->name; - cout << endl << "\t>> stream out : " << out->name; - cout << endl << "\t>> P = " << in->P - << " atm, T(in) = " << in->T << ", T(out) = " << out->T << " K"; - cout << endl << "\t>> L = " << L << ", D = " << D << " m"; - if (success) - cout << " (converge normally)"; - cout << "\n\tEND\n\n"; - model->cost(); - model->water(); -} +#include "reactor.hpp" +using namespace std; + +template<class TYPE> +reactor<TYPE>::reactor(stream* s1, stream* s2) +{ + in = s1; + out = s2; + + model = NULL; +} + +template<class TYPE> +reactor<TYPE>::~reactor() { + for ( i = 0 ; i < n ; i++ ) + delete rx[i]; + delete [] rx; + for ( i = 0 ; i < m ; i++ ) + delete table[i]; + delete [] table; + + if (model) + delete model; +} + +template<class TYPE> +void reactor<TYPE>::set ( double l , double d , int nb , const string * list_rx ) { + m = in->nb; + n = nb; + L = l; + D = d; + V = pi*pow(D/2.0, 2)*L; + + double * yields = new double [n]; + + rx = new reaction * [n]; + for ( j = 0 ; j < n ; j++ ) + rx[j] = new reaction ( list_rx[j] , m , in->chem ); + + table = new double * [m]; + for ( i = 0 ; i < m ; i++ ) + table[i] = new double[n]; + for ( j = 0 ; j < n ; j++ ) + for ( i = 0 ; i < m ; i++ ) + table[i][j] = rx[j]->a[i]; + for ( j = 0 ; j < n ; j++ ) { + yields[j]=0.0; + for ( i = 0 ; i < m ; i++ ) + if ( table[i][j] < 0 ) { + yields[j]=in->chem[i]->n(); + i=m; + } + } + + delete [] yields; + +} + +template<class TYPE> +bool reactor<TYPE>::solve() { + + if (model) + delete model; + model = new TYPE(in, out, table, n, rx, U, Ta); + model->set(name); + model->set(L,D); + + success = model->run(); + + // if(fabs(in->m-out->m)>sqrt(EPS)) + // { + // log.open(MESSAGES, ios::app); + // log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(in->m-out->m)/in->m<<").\n"; + // log.close(); + // } + + + // out->write(); // WRITE TOTO + + return success; +} + +template<class TYPE> +void reactor<TYPE>::write ( void ) { + + cout << setprecision(6); + + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout << "\t>> " << name; + cout << endl << "\t>> stream in : " << in->name; + cout << endl << "\t>> stream out : " << out->name; + cout << endl << "\t>> P = " << in->P + << " atm, T(in) = " << in->T << ", T(out) = " << out->T << " K"; + cout << endl << "\t>> L = " << L << ", D = " << D << " m"; + if (success) + cout << " (converge normally)"; + cout << "\n\tEND\n\n"; + model->cost(); + model->water(); +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reactor.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reactor.hpp index 78f936f..af0d281 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reactor.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/reactor.hpp @@ -1,48 +1,48 @@ -/* -This unit simulates a chemical reactor. Actually, only the pfr can be used. -(ref : Fogler). - -Structure in the .process file: -reactor {name} {pfr or cstr} {index of input stream} {index of output stream} {length in m} {diameter in m} {nb_react, list of reactions occuring} {U in kW/m2.K}{Ta in K} - -How to use: - 1- Call the constructor : react = new reactor<pfr or cstr>(in, out); - 2- Set dimensions and reactions : react->set(length, diameter, nb_react, list_react); //list_react is the list of reactions names - 3- Set cooling parameters : react->set(U, Ta); - 4- Set the name : react->set(name); - 5- Run the model: react->solve(); -*/ -#ifndef REACTOR_H -#define REACTOR_H - -#include "pfr.hpp" -using namespace std; - -template<class TYPE> -class reactor { -private: - // ofstream log; - bool success; - string name; - int i ,j, m, n; - double V, L, D, U, Ta; - stream *in, *out; - TYPE *model; - reaction ** rx; - double ** table; - -public: - // reactor(){}; - reactor(stream*, stream*); - void set( const string & n) { name = n; } - void set(double, double, int, const string * ); - void set(double u, double ta) {U=u;Ta=ta;} - bool solve(); - void write(); - - double get_cost ( void ) const { return model->get_cost() ; } - double get_water ( void ) const { return model->get_water(); } - - ~reactor(); -}; -#endif +/* +This unit simulates a chemical reactor. Actually, only the pfr can be used. +(ref : Fogler). + +Structure in the .process file: +reactor {name} {pfr or cstr} {index of input stream} {index of output stream} {length in m} {diameter in m} {nb_react, list of reactions occuring} {U in kW/m2.K}{Ta in K} + +How to use: + 1- Call the constructor : react = new reactor<pfr or cstr>(in, out); + 2- Set dimensions and reactions : react->set(length, diameter, nb_react, list_react); //list_react is the list of reactions names + 3- Set cooling parameters : react->set(U, Ta); + 4- Set the name : react->set(name); + 5- Run the model: react->solve(); +*/ +#ifndef REACTOR_H +#define REACTOR_H + +#include "pfr.hpp" +using namespace std; + +template<class TYPE> +class reactor { +private: + // ofstream log; + bool success; + string name; + int i ,j, m, n; + double V, L, D, U, Ta; + stream *in, *out; + TYPE *model; + reaction ** rx; + double ** table; + +public: + // reactor(){}; + reactor(stream*, stream*); + void set( const string & n) { name = n; } + void set(double, double, int, const string * ); + void set(double u, double ta) {U=u;Ta=ta;} + bool solve(); + void write(); + + double get_cost ( void ) const { return model->get_cost() ; } + double get_water ( void ) const { return model->get_water(); } + + ~reactor(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/secant.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/secant.cpp index 79e5d04..e8582e0 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/secant.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/secant.cpp @@ -1,47 +1,47 @@ -#include "secant.hpp" -using namespace std; - -template <class E> -secant<E>::secant() -{ - x_last=0; - x_now=0; - x_next=0; - f_last=0; - f_now=0; - OK=false; -} - -template <class E> -void secant<E>::set(E* tmp, double x1, double x2) -{ - unit=tmp; - x_last=x1; - x_now=x2; - OK=false; -} - -template <class E> -bool secant<E>::run() -{ - // if(DEBUG) cout<<endl<<"begin solve secant"; - f_last = unit->f(x_last); - for (i=1; i<MAX_ITER_SECANT; i++) - { - f_now = unit->f(x_now); - // if(DEBUG) cout<<endl<<" x = "<<x_now<<" f(x) = "<<f_now; - x_next = x_now - (f_now*(x_now-x_last)/(f_now-f_last)); - if (fabs((x_next-x_now)/x_now)<=TOL_SECANT) - { - i=MAX_ITER_SECANT; - OK=true; - } - else - { - x_last=x_now; - f_last=f_now; - x_now=x_next; - } - } - return OK; -} +#include "secant.hpp" +using namespace std; + +template <class E> +secant<E>::secant() +{ + x_last=0; + x_now=0; + x_next=0; + f_last=0; + f_now=0; + OK=false; +} + +template <class E> +void secant<E>::set(E* tmp, double x1, double x2) +{ + unit=tmp; + x_last=x1; + x_now=x2; + OK=false; +} + +template <class E> +bool secant<E>::run() +{ + // if(DEBUG) cout<<endl<<"begin solve secant"; + f_last = unit->f(x_last); + for (i=1; i<MAX_ITER_SECANT; i++) + { + f_now = unit->f(x_now); + // if(DEBUG) cout<<endl<<" x = "<<x_now<<" f(x) = "<<f_now; + x_next = x_now - (f_now*(x_now-x_last)/(f_now-f_last)); + if (fabs((x_next-x_now)/x_now)<=TOL_SECANT) + { + i=MAX_ITER_SECANT; + OK=true; + } + else + { + x_last=x_now; + f_last=f_now; + x_now=x_next; + } + } + return OK; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/secant.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/secant.hpp index d1bb096..a04cbc5 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/secant.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/secant.hpp @@ -1,31 +1,31 @@ -/* -To use the secant solver to find the root of a scalar function: - (the parametric object E must have public function such as E->f(x), - where x is the point at which evaluate f.) - 1- construct the solver : solver = new secant<E>(); - 2- set the solver : solver->set(unit, x0, x1); //unit is usually the pointer *this, and x0 and x1 are two required initial points - 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed -*/ -#ifndef SECANT_H -#define SECANT_H - -#include "defines.hpp" -using namespace std; - - -template <class E> -class secant { -private: - double x_last, x_now, x_next; - double f_last, f_now, error; - int i; - bool OK; - E *unit; - -public: - secant(); - void set(E*, double, double); - bool run(); - ~secant(){} -}; -#endif +/* +To use the secant solver to find the root of a scalar function: + (the parametric object E must have public function such as E->f(x), + where x is the point at which evaluate f.) + 1- construct the solver : solver = new secant<E>(); + 2- set the solver : solver->set(unit, x0, x1); //unit is usually the pointer *this, and x0 and x1 are two required initial points + 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed +*/ +#ifndef SECANT_H +#define SECANT_H + +#include "defines.hpp" +using namespace std; + + +template <class E> +class secant { +private: + double x_last, x_now, x_next; + double f_last, f_now, error; + int i; + bool OK; + E *unit; + +public: + secant(); + void set(E*, double, double); + bool run(); + ~secant(){} +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/servor.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/servor.cpp index 0b2df20..75216ae 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/servor.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/servor.cpp @@ -1,538 +1,538 @@ -#include "servor.hpp" -#include "reactor.cpp" -using namespace std; - -/*---------------------------------------------------------------------*/ -servor::servor ( int nb_u , int n2 , stream ** streams ) { - nb = nb_u; - nb_s = n2; - type = new string[nb]; - name = new string[nb]; - s = streams; - - -// for (int i=0; i<nb; i++) -// { -// type[i]=new char[31]; -// name[i]=new char[31]; -// } -// cursor=0; -// s = s_list; -// // end = new terminator("\0"); -// mix1=NULL; -// split1=NULL; -// flash1=NULL; -// pump1=NULL; -// col=NULL; -// react_pfr=NULL; -// react_cstr=NULL; -// heat=NULL; - - burn = new burner ( s[0]->nb , s[0]->chem ); -} - -/*---------------------------------------------------------------------*/ -servor::~servor() { - delete [] type; - delete [] name; - delete burn; -} - -/*---------------------------------------------------------------------*/ -bool servor::solve_process ( const double * x , double * y ) { - - - for ( i = 0 ; i < 8 ; i++ ) - costs[i] = 0.0; - - k = 0; - norm = 1.0 / TOL_WEGSTEIN; - - for ( cursor = 0 ; cursor < nb ; cursor++ ) { - - if (type[cursor] == "mix" ) { - do_mix_process(x); - } - else if ( type[cursor] == "split" ) { - do_split_process(x); - } - else if ( type[cursor] == "flash" ) { - do_flash_process(x); - } - else if ( type[cursor] == "pump" ) { - do_pump_process(x); - } - else if ( type[cursor] == "heatx") { - do_heatx_process(x); - } - else if ( type[cursor] == "burner" ) { - do_burner_process(x,y); - } - else if ( type[cursor] == "column" ) { - do_column_process(x,y); - } - else if ( type[cursor] == "reactor" ) { - do_reactor_process(x); - } - else if ( type[cursor] == "loop" ) { - - recycle = 10; - end_recycle = 0; - do_loop_process(x); - } - else { - cout << "ERROR 18\n\n"; - exit(0); - } - - } - - return true; -} - - -/*---------------------------------------------------------------------*/ -void servor::do_loop_process ( const double * x ) { - - // structure in the input file : - // loop - // name : "looping" - // index of recycle stream : 11 - // index of stream's beginning block : 7 - // index of stream's end block : 1 - - // TOTO -// if (k==0) -// cout << endl << " -> Wegstein iterations "; -// else if ( k <= 2 ) -// cout << endl << " -> loop " << setw(3) << k; -// else -// cout << endl << " -> loop " << setw(3) << k << " > error " << norm; - - // Get the two fisrst points - if ( k==0 ) { - for ( i = 0 ; i < s[0]->nb ; i++ ) - x_last[i] = s[recycle]->chem[i]->m; - end_loop = false; - } - - if ( k==1 ) { - for ( i = 0 ; i < s[0]->nb ; i++ ) { - x_now [i] = s[recycle]->chem[i]->m; - g_last[i] = s[recycle]->chem[i]->m; - } - - end_loop = false; - } - - if ( k == 2 ) { - for ( i = 0 ; i < s[0]->nb ; i++ ) - g_now[i] = s[recycle]->chem[i]->m; - end_loop=false; - } - k++; - - - // run the Wegstein algorithm - if ( k > 2 ) { - for ( i = 0 ; i < s[0]->nb ; i++ ) { - g_now[i] = s[recycle]->chem[i]->m; - - if ( fabs (x_now[i]-x_last[i]) > EPS ) - slope[i] = ( g_now[i] - g_last[i] ) / ( x_now[i] - x_last[i] ); - else - slope[i] = 0; - - theta[i] = 1.0 / (1.0-slope[i]); - if ( theta[i] < MIN_THETA ) - theta[i] = MIN_THETA; - if ( theta[i] > MAX_THETA ) - theta[i] = MAX_THETA; - x_next[i] = (1.0-theta[i])*x_now[i] + theta[i]*g_now[i]; - } - norm = 0.0; - for ( i = 0 ; i < s[0]->nb ; i++ ) - if ( fabs(x_now[i]) > EPS ) - norm += fabs (x_next[i]-x_now[i]) / fabs(x_now[i]); - - if ( norm > TOL_WEGSTEIN && k < MAX_ITER_WEGSTEIN ) { - s[recycle]->m = 0.0; - for ( i = 0 ; i < s[0]->nb ; i++ ) { - s[recycle]->chem[i]->m = x_next[i]; - s[recycle]->m += x_next[i]; - x_last[i] = x_now[i]; - g_last[i] = g_now[i]; - x_now[i] = x_next[i]; - } - end_loop=false; - } - if ( norm <= TOL_WEGSTEIN && k < MAX_ITER_WEGSTEIN ) - end_loop = true; - - } - - - if ( end_loop ) { - if ( k < MAX_ITER_WEGSTEIN && k > 3 ) { - // cout<<" OK"; // TOTO - // s[recycle]->write(); // WRITE TOTO - -// // WRITE TOTO : -// cout << "WRITE FILE " << RUNTIME << name[cursor] << ".unit" << " :\n\tBEGIN\n"; -// cout << "\t>> " << name[cursor]; -// cout << endl << "\t>> from block " << cursor+1 << " to block " << end_recycle+1; -// cout << endl << "\t>> Wegstein converged in " -// << k << " iterations (rel. err. " << norm << ")."; -// cout << "\n\tEND\n\n"; - - k = 0; - norm = 1.0/TOL_WEGSTEIN; - } -// else { -// log.open(MESSAGES, ios::app); -// log<<" ==> Error <== Wegstein algorithm did not converge.\n"; -// log.close(); -// } - } - - - if ( !end_loop && k < MAX_ITER_WEGSTEIN ) - cursor = end_recycle-1; - if ( !end_loop && k==MAX_ITER_WEGSTEIN ) { -// log.open(MESSAGES, ios::app); -// log<<" ==> Error <== Wegstein algorithm did not converge.\n"; -// log.close(); - k=0; - norm = 1.0/TOL_WEGSTEIN; - cursor=nb; - } - -} - -/*---------------------------------------------------------------------*/ -void servor::do_burner_process ( const double * x , double * y ) { - - // cout << endl << " -- " << name[cursor] << "... "; // TOTO - - // read parameters : - int i1 = 8; - int i2 = 13; - double f = x[6]; - - burn->set ( s[i1-1] , s[i2-1] ); - burn->set(f); - burn->set(name[cursor]); - - if ( burn->solve(y) ) { - // cout << "OK"; // TOTO - // burn->write(); // WRITE TOTO - costs[7] = burn->get_cost(); - } - else { - cout << "ERROR 20\n\n"; - exit(0); - } -} - -/*---------------------------------------------------------------------*/ -void servor::do_split_process ( const double * x ) -{ - // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO - - //Read parameters - int i1 = 9; - int i2 = 2; - int i_tab[2] = { 10 , 11 }; - double f_tab[2]; - f_tab[0] = x[5]; - f_tab[1] = 1-x[5]; - - stream * list1[2]; - list1[0] = s[i_tab[0]-1]; - list1[1] = s[i_tab[1]-1]; - - split * split1 = new split ( i2 , s[i1-1] , list1 ); - - split1->set(f_tab); - split1->set(name[cursor]); - if ( split1->solve() ) { - // cout<<"OK"; // TOTO - // split1->write(); // WRITE TOTO - } - else { - cout << "ERROR 19\n\n"; - exit(0); - } - delete split1; -} - -/*---------------------------------------------------------------------*/ -void servor::do_column_process ( const double * x , double * y ) { - // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO - - //Read parameters - double f1 , f2; - int i , i1 , i2; - int i_tab[2]; - double f = 1.0; - - if (name[cursor]=="sep-sty") { - i = 7; - i1 = 15; - i2 = 9; - i_tab[0] = 1; - i_tab[1] = 7; - f1 = f2 = x[2]; - } - else if (name[cursor]=="sep-bz") { - i = 10; - i1 = 12; - i2 = 14; - i_tab[0] = 5; - i_tab[1] = 1; - f1 = f2 = x[3]; - } - else { - cout << "ERROR 17\n\n"; - exit(0); - } - - column * col = new column ( s[i-1] , s[i1-1] , s[i2-1] ); - col->set ( f , i_tab[0] , f1 , i_tab[1] , f2 ); - col->set(name[cursor]); - if ( col->solve() ) { - //cout<<"OK"; // TOTO - //col->write(); // WRITE TOTO - - if (name[cursor]=="sep-sty") { - y[4] = col->get_N(); - costs[5] = col->get_cost(); - power[5] = col->get_power(); - water[5] = col->get_water(); - } - else { - y[5] = col->get_N(); - costs[6] = col->get_cost(); - power[4] = col->get_power(); - water[4] = col->get_water(); - } - } - else { - cout << "ERROR 15\n\n"; - exit(0); - } - delete col; -} - -/*---------------------------------------------------------------------*/ -void servor::do_flash_process ( const double * x ) { - // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO - - //Read parameters - double f1 = 1.0; - double f2 = x[7]; - // int i_tab [3] = { 6 , 7 , 8 }; - // flash * flash1 = new flash ( s[i_tab[0]-1] , s[i_tab[1]-1] , s[i_tab[2]-1] ); - flash * flash1 = new flash ( s[5] , s[6] , s[7] ); - - flash1->set(f1, f2); - flash1->set(name[cursor]); - if ( flash1->solve() ) { - // cout<<"OK"; // TOTO - // flash1->write(); // WRITE TOTO - costs[4] = flash1->get_cost(); - power[2] = flash1->get_power(); - water[1] = flash1->get_water(); - } - else { - cout << "ERROR 14\n\n"; - exit(0); - } - delete flash1; -} - - -/*---------------------------------------------------------------------*/ -void servor::do_mix_process ( const double * x ) { - - // cout << endl << " -- " << name[cursor] << "... "; // TOTO - - // Read parameters (hardcode avec eb2sty.process) : - double f1 = 1.0; - int i1 = 3; - int i_tab[3] = { 1 , 12 , 11 }; - int i2 = 2; - - // We can solve the unit - stream * list2 = s[i2-1] , ** list1 = new stream * [i1]; - for ( int i = 0 ; i < i1 ; i++ ) - list1[i] = s[i_tab[i]-1]; - mix * mix1 = new mix ( i1 , list1 , list2 ); - mix1->set(f1); - mix1->set(name[cursor]); - if (mix1->solve()) { - // cout<<"OK"; // TOTO - // mix1->write(); // WRITE TOTO - } - else { - cout << "ERROR 6\n\n"; - exit(0); - } - delete mix1; - delete [] list1; -} - - -/*---------------------------------------------------------------------*/ -void servor::do_pump_process ( const double * x ) { - - // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO - - //Read parameters (hardcode avec eb2sty.process) : - int i1 = 2; - int i2 = 3; - double f1 = x[4]; - double f2 = 0.75; - - pump * pump1 = new pump ( s[i1-1] , s[i2-1] ); - pump1->set(f1,f2); - pump1->set(name[cursor]); - - - - // solve : - if ( pump1->solve() ) { - // cout<<"OK"; // TOTO - // pump1->write(); // WRITE TOTO - - power[0] = pump1->get_power(); - costs[0] = pump1->get_cost(); - } - else { - cout << "ERROR 7\n\n"; - exit(0); - } - - delete pump1; -} - -/*---------------------------------------------------------------------*/ -void servor::do_heatx_process ( const double * x ) { - - // cout << endl << " -- " << name[cursor] << "... "; // TOTO - - //Read parameters (idem) : - - bool b = false; - - // heater : - int i1; - int i2; - double f1; - - // heater : - if (name[cursor]=="heater") { - i1 = 3; - i2 = 4; - f1 = x[0]; - } - - // cooler : - else if (name[cursor]=="cooler") { - i1 = 5; - i2 = 6; - f1 = x[7]; - } - else { - cout << "ERROR 16\n\n"; - exit(0); - } - - double f2 = 0.85; - - // solve : - heatx * heat = new heatx ( b , s[i1-1] , s[i2-1] ); - heat->set(f1,f2); - heat->set(name[cursor]); - if (heat->solve()) { - // cout<<"OK"; // TOTO - // heat->write(); // WRITE TOTO - if (name[cursor]=="heater") { - costs[1] = heat->get_cost(); - power[3] = heat->get_power(); - water[2] = heat->get_water(); - } - else { - costs[3] = heat->get_cost(); - power[1] = heat->get_power(); - water[0] = heat->get_water(); - } - } - else { - cout << "ERROR 8\n\n"; - exit(0); - } - delete heat; -} - -/*---------------------------------------------------------------------*/ -void servor::do_reactor_process ( const double * x ) { - - // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO - - // Read parameters (idem) : - int i1 = 4; - int i2 = 5; - - reactor<pfr> * react_pfr = new reactor<pfr> ( s[i1-1] , s[i2-1] ); - - react_pfr->set(name[cursor]); - - double f1 = x[1]; - double f2 = 0.5; - - string list[5] = { "eb2sty" , "sty2eb" , "eb2bz" , "eb2tol" , "tol2bz" }; - - i1 = 5; - - react_pfr->set(f1,f2,i1,list); - - f1 = 0.0; - f2 = 300.0; - - react_pfr->set(f1,f2); - - if ( react_pfr->solve() ) { - // cout<<"OK"; // TOTO - // react_pfr->write(); // WRITE TOTO - costs[2] = react_pfr->get_cost(); - water[3] = react_pfr->get_water(); - } - else { - cout << "ERROR 9\n\n"; - exit(0); - } - delete react_pfr; -} - - -double servor::get_costs_sum ( void ) const { - double sum = 0.0; - for ( int i = 0 ; i < 8 ; i++ ) - sum += ( (ARRONDI) ? arrondi(costs[i],6) : costs[i] ); - return sum; -} - -double servor::get_power_sum ( void ) const { - double sum = 0.0; - for ( int i = 0 ; i < 6 ; i++ ) - sum += ( (ARRONDI) ? arrondi(power[i],6) : power[i] ); - return sum; -} - -double servor::get_water_sum ( void ) const { - double sum = 0.0; - for ( int i = 0 ; i < 6 ; i++ ) - sum += ( (ARRONDI) ? arrondi(water[i],6) : water[i] ); - return sum; -} +#include "servor.hpp" +#include "reactor.cpp" +using namespace std; + +/*---------------------------------------------------------------------*/ +servor::servor ( int nb_u , int n2 , stream ** streams ) { + nb = nb_u; + nb_s = n2; + type = new string[nb]; + name = new string[nb]; + s = streams; + + +// for (int i=0; i<nb; i++) +// { +// type[i]=new char[31]; +// name[i]=new char[31]; +// } +// cursor=0; +// s = s_list; +// // end = new terminator("\0"); +// mix1=NULL; +// split1=NULL; +// flash1=NULL; +// pump1=NULL; +// col=NULL; +// react_pfr=NULL; +// react_cstr=NULL; +// heat=NULL; + + burn = new burner ( s[0]->nb , s[0]->chem ); +} + +/*---------------------------------------------------------------------*/ +servor::~servor() { + delete [] type; + delete [] name; + delete burn; +} + +/*---------------------------------------------------------------------*/ +bool servor::solve_process ( const double * x , double * y ) { + + + for ( i = 0 ; i < 8 ; i++ ) + costs[i] = 0.0; + + k = 0; + norm = 1.0 / TOL_WEGSTEIN; + + for ( cursor = 0 ; cursor < nb ; cursor++ ) { + + if (type[cursor] == "mix" ) { + do_mix_process(x); + } + else if ( type[cursor] == "split" ) { + do_split_process(x); + } + else if ( type[cursor] == "flash" ) { + do_flash_process(x); + } + else if ( type[cursor] == "pump" ) { + do_pump_process(x); + } + else if ( type[cursor] == "heatx") { + do_heatx_process(x); + } + else if ( type[cursor] == "burner" ) { + do_burner_process(x,y); + } + else if ( type[cursor] == "column" ) { + do_column_process(x,y); + } + else if ( type[cursor] == "reactor" ) { + do_reactor_process(x); + } + else if ( type[cursor] == "loop" ) { + + recycle = 10; + end_recycle = 0; + do_loop_process(x); + } + else { + cout << "ERROR 18\n\n"; + exit(0); + } + + } + + return true; +} + + +/*---------------------------------------------------------------------*/ +void servor::do_loop_process ( const double * x ) { + + // structure in the input file : + // loop + // name : "looping" + // index of recycle stream : 11 + // index of stream's beginning block : 7 + // index of stream's end block : 1 + + // TOTO +// if (k==0) +// cout << endl << " -> Wegstein iterations "; +// else if ( k <= 2 ) +// cout << endl << " -> loop " << setw(3) << k; +// else +// cout << endl << " -> loop " << setw(3) << k << " > error " << norm; + + // Get the two fisrst points + if ( k==0 ) { + for ( i = 0 ; i < s[0]->nb ; i++ ) + x_last[i] = s[recycle]->chem[i]->m; + end_loop = false; + } + + if ( k==1 ) { + for ( i = 0 ; i < s[0]->nb ; i++ ) { + x_now [i] = s[recycle]->chem[i]->m; + g_last[i] = s[recycle]->chem[i]->m; + } + + end_loop = false; + } + + if ( k == 2 ) { + for ( i = 0 ; i < s[0]->nb ; i++ ) + g_now[i] = s[recycle]->chem[i]->m; + end_loop=false; + } + k++; + + + // run the Wegstein algorithm + if ( k > 2 ) { + for ( i = 0 ; i < s[0]->nb ; i++ ) { + g_now[i] = s[recycle]->chem[i]->m; + + if ( fabs (x_now[i]-x_last[i]) > EPS ) + slope[i] = ( g_now[i] - g_last[i] ) / ( x_now[i] - x_last[i] ); + else + slope[i] = 0; + + theta[i] = 1.0 / (1.0-slope[i]); + if ( theta[i] < MIN_THETA ) + theta[i] = MIN_THETA; + if ( theta[i] > MAX_THETA ) + theta[i] = MAX_THETA; + x_next[i] = (1.0-theta[i])*x_now[i] + theta[i]*g_now[i]; + } + norm = 0.0; + for ( i = 0 ; i < s[0]->nb ; i++ ) + if ( fabs(x_now[i]) > EPS ) + norm += fabs (x_next[i]-x_now[i]) / fabs(x_now[i]); + + if ( norm > TOL_WEGSTEIN && k < MAX_ITER_WEGSTEIN ) { + s[recycle]->m = 0.0; + for ( i = 0 ; i < s[0]->nb ; i++ ) { + s[recycle]->chem[i]->m = x_next[i]; + s[recycle]->m += x_next[i]; + x_last[i] = x_now[i]; + g_last[i] = g_now[i]; + x_now[i] = x_next[i]; + } + end_loop=false; + } + if ( norm <= TOL_WEGSTEIN && k < MAX_ITER_WEGSTEIN ) + end_loop = true; + + } + + + if ( end_loop ) { + if ( k < MAX_ITER_WEGSTEIN && k > 3 ) { + // cout<<" OK"; // TOTO + // s[recycle]->write(); // WRITE TOTO + +// // WRITE TOTO : +// cout << "WRITE FILE " << RUNTIME << name[cursor] << ".unit" << " :\n\tBEGIN\n"; +// cout << "\t>> " << name[cursor]; +// cout << endl << "\t>> from block " << cursor+1 << " to block " << end_recycle+1; +// cout << endl << "\t>> Wegstein converged in " +// << k << " iterations (rel. err. " << norm << ")."; +// cout << "\n\tEND\n\n"; + + k = 0; + norm = 1.0/TOL_WEGSTEIN; + } +// else { +// log.open(MESSAGES, ios::app); +// log<<" ==> Error <== Wegstein algorithm did not converge.\n"; +// log.close(); +// } + } + + + if ( !end_loop && k < MAX_ITER_WEGSTEIN ) + cursor = end_recycle-1; + if ( !end_loop && k==MAX_ITER_WEGSTEIN ) { +// log.open(MESSAGES, ios::app); +// log<<" ==> Error <== Wegstein algorithm did not converge.\n"; +// log.close(); + k=0; + norm = 1.0/TOL_WEGSTEIN; + cursor=nb; + } + +} + +/*---------------------------------------------------------------------*/ +void servor::do_burner_process ( const double * x , double * y ) { + + // cout << endl << " -- " << name[cursor] << "... "; // TOTO + + // read parameters : + int i1 = 8; + int i2 = 13; + double f = x[6]; + + burn->set ( s[i1-1] , s[i2-1] ); + burn->set(f); + burn->set(name[cursor]); + + if ( burn->solve(y) ) { + // cout << "OK"; // TOTO + // burn->write(); // WRITE TOTO + costs[7] = burn->get_cost(); + } + else { + cout << "ERROR 20\n\n"; + exit(0); + } +} + +/*---------------------------------------------------------------------*/ +void servor::do_split_process ( const double * x ) +{ + // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO + + //Read parameters + int i1 = 9; + int i2 = 2; + int i_tab[2] = { 10 , 11 }; + double f_tab[2]; + f_tab[0] = x[5]; + f_tab[1] = 1-x[5]; + + stream * list1[2]; + list1[0] = s[i_tab[0]-1]; + list1[1] = s[i_tab[1]-1]; + + split * split1 = new split ( i2 , s[i1-1] , list1 ); + + split1->set(f_tab); + split1->set(name[cursor]); + if ( split1->solve() ) { + // cout<<"OK"; // TOTO + // split1->write(); // WRITE TOTO + } + else { + cout << "ERROR 19\n\n"; + exit(0); + } + delete split1; +} + +/*---------------------------------------------------------------------*/ +void servor::do_column_process ( const double * x , double * y ) { + // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO + + //Read parameters + double f1 , f2; + int i , i1 , i2; + int i_tab[2]; + double f = 1.0; + + if (name[cursor]=="sep-sty") { + i = 7; + i1 = 15; + i2 = 9; + i_tab[0] = 1; + i_tab[1] = 7; + f1 = f2 = x[2]; + } + else if (name[cursor]=="sep-bz") { + i = 10; + i1 = 12; + i2 = 14; + i_tab[0] = 5; + i_tab[1] = 1; + f1 = f2 = x[3]; + } + else { + cout << "ERROR 17\n\n"; + exit(0); + } + + column * col = new column ( s[i-1] , s[i1-1] , s[i2-1] ); + col->set ( f , i_tab[0] , f1 , i_tab[1] , f2 ); + col->set(name[cursor]); + if ( col->solve() ) { + //cout<<"OK"; // TOTO + //col->write(); // WRITE TOTO + + if (name[cursor]=="sep-sty") { + y[4] = col->get_N(); + costs[5] = col->get_cost(); + power[5] = col->get_power(); + water[5] = col->get_water(); + } + else { + y[5] = col->get_N(); + costs[6] = col->get_cost(); + power[4] = col->get_power(); + water[4] = col->get_water(); + } + } + else { + cout << "ERROR 15\n\n"; + exit(0); + } + delete col; +} + +/*---------------------------------------------------------------------*/ +void servor::do_flash_process ( const double * x ) { + // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO + + //Read parameters + double f1 = 1.0; + double f2 = x[7]; + // int i_tab [3] = { 6 , 7 , 8 }; + // flash * flash1 = new flash ( s[i_tab[0]-1] , s[i_tab[1]-1] , s[i_tab[2]-1] ); + flash * flash1 = new flash ( s[5] , s[6] , s[7] ); + + flash1->set(f1, f2); + flash1->set(name[cursor]); + if ( flash1->solve() ) { + // cout<<"OK"; // TOTO + // flash1->write(); // WRITE TOTO + costs[4] = flash1->get_cost(); + power[2] = flash1->get_power(); + water[1] = flash1->get_water(); + } + else { + cout << "ERROR 14\n\n"; + exit(0); + } + delete flash1; +} + + +/*---------------------------------------------------------------------*/ +void servor::do_mix_process ( const double * x ) { + + // cout << endl << " -- " << name[cursor] << "... "; // TOTO + + // Read parameters (hardcode avec eb2sty.process) : + double f1 = 1.0; + int i1 = 3; + int i_tab[3] = { 1 , 12 , 11 }; + int i2 = 2; + + // We can solve the unit + stream * list2 = s[i2-1] , ** list1 = new stream * [i1]; + for ( int i = 0 ; i < i1 ; i++ ) + list1[i] = s[i_tab[i]-1]; + mix * mix1 = new mix ( i1 , list1 , list2 ); + mix1->set(f1); + mix1->set(name[cursor]); + if (mix1->solve()) { + // cout<<"OK"; // TOTO + // mix1->write(); // WRITE TOTO + } + else { + cout << "ERROR 6\n\n"; + exit(0); + } + delete mix1; + delete [] list1; +} + + +/*---------------------------------------------------------------------*/ +void servor::do_pump_process ( const double * x ) { + + // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO + + //Read parameters (hardcode avec eb2sty.process) : + int i1 = 2; + int i2 = 3; + double f1 = x[4]; + double f2 = 0.75; + + pump * pump1 = new pump ( s[i1-1] , s[i2-1] ); + pump1->set(f1,f2); + pump1->set(name[cursor]); + + + + // solve : + if ( pump1->solve() ) { + // cout<<"OK"; // TOTO + // pump1->write(); // WRITE TOTO + + power[0] = pump1->get_power(); + costs[0] = pump1->get_cost(); + } + else { + cout << "ERROR 7\n\n"; + exit(0); + } + + delete pump1; +} + +/*---------------------------------------------------------------------*/ +void servor::do_heatx_process ( const double * x ) { + + // cout << endl << " -- " << name[cursor] << "... "; // TOTO + + //Read parameters (idem) : + + bool b = false; + + // heater : + int i1; + int i2; + double f1; + + // heater : + if (name[cursor]=="heater") { + i1 = 3; + i2 = 4; + f1 = x[0]; + } + + // cooler : + else if (name[cursor]=="cooler") { + i1 = 5; + i2 = 6; + f1 = x[7]; + } + else { + cout << "ERROR 16\n\n"; + exit(0); + } + + double f2 = 0.85; + + // solve : + heatx * heat = new heatx ( b , s[i1-1] , s[i2-1] ); + heat->set(f1,f2); + heat->set(name[cursor]); + if (heat->solve()) { + // cout<<"OK"; // TOTO + // heat->write(); // WRITE TOTO + if (name[cursor]=="heater") { + costs[1] = heat->get_cost(); + power[3] = heat->get_power(); + water[2] = heat->get_water(); + } + else { + costs[3] = heat->get_cost(); + power[1] = heat->get_power(); + water[0] = heat->get_water(); + } + } + else { + cout << "ERROR 8\n\n"; + exit(0); + } + delete heat; +} + +/*---------------------------------------------------------------------*/ +void servor::do_reactor_process ( const double * x ) { + + // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO + + // Read parameters (idem) : + int i1 = 4; + int i2 = 5; + + reactor<pfr> * react_pfr = new reactor<pfr> ( s[i1-1] , s[i2-1] ); + + react_pfr->set(name[cursor]); + + double f1 = x[1]; + double f2 = 0.5; + + string list[5] = { "eb2sty" , "sty2eb" , "eb2bz" , "eb2tol" , "tol2bz" }; + + i1 = 5; + + react_pfr->set(f1,f2,i1,list); + + f1 = 0.0; + f2 = 300.0; + + react_pfr->set(f1,f2); + + if ( react_pfr->solve() ) { + // cout<<"OK"; // TOTO + // react_pfr->write(); // WRITE TOTO + costs[2] = react_pfr->get_cost(); + water[3] = react_pfr->get_water(); + } + else { + cout << "ERROR 9\n\n"; + exit(0); + } + delete react_pfr; +} + + +double servor::get_costs_sum ( void ) const { + double sum = 0.0; + for ( int i = 0 ; i < 8 ; i++ ) + sum += ( (ARRONDI) ? arrondi(costs[i],6) : costs[i] ); + return sum; +} + +double servor::get_power_sum ( void ) const { + double sum = 0.0; + for ( int i = 0 ; i < 6 ; i++ ) + sum += ( (ARRONDI) ? arrondi(power[i],6) : power[i] ); + return sum; +} + +double servor::get_water_sum ( void ) const { + double sum = 0.0; + for ( int i = 0 ; i < 6 ; i++ ) + sum += ( (ARRONDI) ? arrondi(water[i],6) : water[i] ); + return sum; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/servor.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/servor.hpp index e048542..73b1cd2 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/servor.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/servor.hpp @@ -1,101 +1,101 @@ -#ifndef SERVOR_H -#define SERVOR_H - -//Possible units -#include "mix.hpp" -#include "split.hpp" -#include "pump.hpp" -#include "column.hpp" -#include "reactor.hpp" -#include "heatx.hpp" -#include "burner.hpp" - -using namespace std; - -class servor { - -public: - - double norm; - int k; - int nb; - int nb_s; - string * type; - string * name; - int cursor; - stream ** s; - - int recycle; - int end_recycle; - int i; - bool end_loop; - - double x_last[MAX_DIM]; - double x_now [MAX_DIM]; - double x_next[MAX_DIM]; - double g_last[MAX_DIM]; - double g_now [MAX_DIM]; - double slope [MAX_DIM]; - double theta [MAX_DIM]; - - double costs[8]; - double power[6]; - double water[6]; - - - // clock_t beg_time, end_time; - // bool OK, b, solve_OK; - // char filename[31], kind[10], **list, process_name[31]; - // double f, f1, f2, f_tab[10], t; - // int i, i1, i2, i_tab[10], time; - // stream *list2; - -// double theta[MAX_DIM], slope[MAX_DIM], norm; -// bool end_loop; -// int k, recycle, end_recycle; -// char loop_name[31]; - -// mix *mix1; void do_mix(); -// split *split1; -// flash *flash1; void do_flash(); -// pump *pump1; void do_pump(); -// column *col; void do_column(); -// reactor<pfr> *react_pfr; void do_reactor(); -// reactor<cstr> *react_cstr; -// heatx *heat; void do_heatx(); - burner * burn; - -// stream *s; //list of streams -// friend void out_of_memory(void){exit(0);} - - - // constructeur : - servor ( int , int , stream ** ); - - // destructeur : - ~servor(); - - -// void set(int t) {time=t;} -// void set(char n[31]) {strcpy(process_name, n);} - void do_split_process ( const double * x ); - void do_column_process ( const double * x , double * y ); - void do_flash_process ( const double * x ); - void do_mix_process ( const double * x ); - void do_pump_process ( const double * x ); - void do_heatx_process ( const double * x ); - void do_reactor_process ( const double * x ); - void do_burner_process ( const double * x , double * y ); - void do_loop_process ( const double * x ); - - bool solve_process ( const double * x , double * y ); //main solver of the software. - - double get_costs_sum ( void ) const; - - double get_power_sum ( void ) const; - - double get_water_sum ( void ) const; - - -}; -#endif +#ifndef SERVOR_H +#define SERVOR_H + +//Possible units +#include "mix.hpp" +#include "split.hpp" +#include "pump.hpp" +#include "column.hpp" +#include "reactor.hpp" +#include "heatx.hpp" +#include "burner.hpp" + +using namespace std; + +class servor { + +public: + + double norm; + int k; + int nb; + int nb_s; + string * type; + string * name; + int cursor; + stream ** s; + + int recycle; + int end_recycle; + int i; + bool end_loop; + + double x_last[MAX_DIM]; + double x_now [MAX_DIM]; + double x_next[MAX_DIM]; + double g_last[MAX_DIM]; + double g_now [MAX_DIM]; + double slope [MAX_DIM]; + double theta [MAX_DIM]; + + double costs[8]; + double power[6]; + double water[6]; + + + // clock_t beg_time, end_time; + // bool OK, b, solve_OK; + // char filename[31], kind[10], **list, process_name[31]; + // double f, f1, f2, f_tab[10], t; + // int i, i1, i2, i_tab[10], time; + // stream *list2; + +// double theta[MAX_DIM], slope[MAX_DIM], norm; +// bool end_loop; +// int k, recycle, end_recycle; +// char loop_name[31]; + +// mix *mix1; void do_mix(); +// split *split1; +// flash *flash1; void do_flash(); +// pump *pump1; void do_pump(); +// column *col; void do_column(); +// reactor<pfr> *react_pfr; void do_reactor(); +// reactor<cstr> *react_cstr; +// heatx *heat; void do_heatx(); + burner * burn; + +// stream *s; //list of streams +// friend void out_of_memory(void){exit(0);} + + + // constructeur : + servor ( int , int , stream ** ); + + // destructeur : + ~servor(); + + +// void set(int t) {time=t;} +// void set(char n[31]) {strcpy(process_name, n);} + void do_split_process ( const double * x ); + void do_column_process ( const double * x , double * y ); + void do_flash_process ( const double * x ); + void do_mix_process ( const double * x ); + void do_pump_process ( const double * x ); + void do_heatx_process ( const double * x ); + void do_reactor_process ( const double * x ); + void do_burner_process ( const double * x , double * y ); + void do_loop_process ( const double * x ); + + bool solve_process ( const double * x , double * y ); //main solver of the software. + + double get_costs_sum ( void ) const; + + double get_power_sum ( void ) const; + + double get_water_sum ( void ) const; + + +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/split.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/split.cpp index d3f48c9..d14c519 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/split.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/split.cpp @@ -1,53 +1,53 @@ -#include "split.hpp" -using namespace std; - -split::split(int n, stream* s1, stream** s2) -{ - nb_out=n; - in = s1; - out= s2; - success = true; -} - -bool split::solve() -{ - tmp=0; - for (i=0;i<nb_out; i++) tmp+=frac[i]; - if(fabs(1-tmp)<=EPS) - { - success = true; - for (i=0; i<nb_out;i++) - { - out[i]->m=0; - for (j=0;j<in->nb;j++) - { - - out[i]->chem[j]->m = frac[i]*in->chem[j]->m; - out[i]->m += out[i]->chem[j]->m; - } - out[i]->set(in->P, in->T); - // out[i]->write(); // TOTO - } - } - tmp=0; for(i=0;i<nb_out;i++) tmp+=out[i]->m; - if(fabs(tmp-in->m)>EPS) - { -// logf.open(MESSAGES, ios::app); -// logf<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(tmp-in->m)/tmp<<").\n"; -// logf.close(); - success = false; - } - else success = true; - return success; -} - -void split::write() -{ - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout <<"\t>> "<<name; - cout << endl<<"\t>> stream in: "<<in->name;; - cout<<endl<<"\t>> streams out: "<<setprecision(3); - for ( i = 0 ; i < nb_out ; i++ ) - cout << out[i]->name<<" ("<<frac[i]<<") "; - cout << "\n\tEND\n\n"; -} +#include "split.hpp" +using namespace std; + +split::split(int n, stream* s1, stream** s2) +{ + nb_out=n; + in = s1; + out= s2; + success = true; +} + +bool split::solve() +{ + tmp=0; + for (i=0;i<nb_out; i++) tmp+=frac[i]; + if(fabs(1-tmp)<=EPS) + { + success = true; + for (i=0; i<nb_out;i++) + { + out[i]->m=0; + for (j=0;j<in->nb;j++) + { + + out[i]->chem[j]->m = frac[i]*in->chem[j]->m; + out[i]->m += out[i]->chem[j]->m; + } + out[i]->set(in->P, in->T); + // out[i]->write(); // TOTO + } + } + tmp=0; for(i=0;i<nb_out;i++) tmp+=out[i]->m; + if(fabs(tmp-in->m)>EPS) + { +// logf.open(MESSAGES, ios::app); +// logf<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(tmp-in->m)/tmp<<").\n"; +// logf.close(); + success = false; + } + else success = true; + return success; +} + +void split::write() +{ + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout <<"\t>> "<<name; + cout << endl<<"\t>> stream in: "<<in->name;; + cout<<endl<<"\t>> streams out: "<<setprecision(3); + for ( i = 0 ; i < nb_out ; i++ ) + cout << out[i]->name<<" ("<<frac[i]<<") "; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/split.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/split.hpp index 2c75638..7634f47 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/split.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/split.hpp @@ -1,43 +1,43 @@ -/* -This unit takes one input stream and divides in two or more -output streams. The pressure and temparature of output streams -are the same as the input's. - -Structure in the .process file: -split {name} {index of input stream} {nb_out} {indexes of output streams and fractions of input} - -How to use: - 1- Call the constructor: split1 = new split(nb_out, in, list_out); - 2- Set split fractions: split1->set(fractions); - 3- Set the name: split1->set(name); - 4- Solve: split1->solve(); -*/ -#ifndef SPLIT_H -#define SPLIT_H - -#include "stream.hpp" -using namespace std; - -class split -{ -private: - - int i, j; - bool success; - double tmp; - string name; - int nb_out; //number of input streams - stream *in; //pointer to input stream - stream **out; //list of pointers to output streams - double *frac; //list of split fractions - -public: - split(int, stream*, stream**); //defines the connectivities of this unit - ~split(){} - void set(double* f) {frac=f;} - void set(const string & n) { name = n;} - bool solve(); //finds the temperature and computes mass balance - void write(); -}; - -#endif +/* +This unit takes one input stream and divides in two or more +output streams. The pressure and temparature of output streams +are the same as the input's. + +Structure in the .process file: +split {name} {index of input stream} {nb_out} {indexes of output streams and fractions of input} + +How to use: + 1- Call the constructor: split1 = new split(nb_out, in, list_out); + 2- Set split fractions: split1->set(fractions); + 3- Set the name: split1->set(name); + 4- Solve: split1->solve(); +*/ +#ifndef SPLIT_H +#define SPLIT_H + +#include "stream.hpp" +using namespace std; + +class split +{ +private: + + int i, j; + bool success; + double tmp; + string name; + int nb_out; //number of input streams + stream *in; //pointer to input stream + stream **out; //list of pointers to output streams + double *frac; //list of split fractions + +public: + split(int, stream*, stream**); //defines the connectivities of this unit + ~split(){} + void set(double* f) {frac=f;} + void set(const string & n) { name = n;} + bool solve(); //finds the temperature and computes mass balance + void write(); +}; + +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/stream.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/stream.cpp index 8854441..408c1cb 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/stream.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/stream.cpp @@ -1,265 +1,265 @@ -#include "stream.hpp" -using namespace std; - -// destructor : -stream::~stream ( void ) { - delete thermo; - delete [] tab1; - delete [] tab2; - delete [] tab3; - delete [] tab4; - for ( i = 0 ; i < nb ; i++ ) - delete chem[i]; - delete [] chem; -} - -void stream::check_error() -{ - - if (error>MAX_ERROR) { - cout << "ERROR 4\n\n"; - exit(0); - } - if (warning>MAX_WARNING) { - cout << "ERROR 5\n\n"; - exit(0); - } -} - -void stream::set ( int _nb , chemical ** _chem) { - int i; - for ( i = 0 ; i < nb ; i++ ) - delete chem[i]; - delete [] chem; - nb = _nb; - chem = new chemical * [nb]; - for ( i = 0 ; i < nb ; i++ ) - chem[i] = new chemical(*_chem[i]); -} - -void stream::set(double pres, double temp) //set P, T, find state and resulting v -{ - if(thermo->get_dim()!=nb) - { - delete thermo; - thermo = new thermolib(nb); - } - P=pres; - T=temp; - for (i=0;i<nb;i++) {chem[i]->P=pres; chem[i]->T=temp;} - if(n()>EPS) - { - v=quality(); - tmp1=0; - for (i=0;i<nb;i++) - { - if (T>chem[i]->Tc || v==1) chem[i]->state=1; - else chem[i]->state=0; - } - v=0; - for (i=0;i<nb;i++) - { - if (chem[i]->state==0) {if (chem[i]->m>EPS) v+= chem[i]->m/chem[i]->rho(); tab4[i]=0;} - if (chem[i]->state==1) {tab4[i] = chem[i]->n(); tmp1+=tab4[i];} - } - if (tmp1>EPS) - { - for (i=0;i<nb;i++) - { - tab1[i] = chem[i]->Pc; //cout<<endl<<tab1[i]; - tab2[i] = chem[i]->Tc; // cout<<" "<<tab2[i]; - tab3[i] = chem[i]->omega(); //cout<<" "<<tab3[i]; - tab4[i]/=tmp1; // cout<<" "<<tab4[i]; - } - thermo->send(tab1,tab2,tab3, tab4); - thermo->set(P,T,0.0,tmp1); - v+=thermo->v(); - } - } - else v= 0.0; -} - -void stream::set(double *list) -{ - m=0; - for (i=0; i<nb; i++) - { - chem[i]->m=list[i]; - m+=list[i]; - } -} - -void stream::bubble() -{ - bp=1.1e6; - for(i=0;i<nb;i++) if(T<chem[i]->Tc && chem[i]->Tboil(P)<bp && chem[i]->m>EPS) bp=chem[i]->Tboil(P); - if (bp==1.1e6) bp=0.0; - else - { - step=2; - while (fabs(step)>TOL_BP && fabs(tmp1-1)>TOL_BP) - { - //if(DEBUG) cout<<endl<<bp; - bp+=step; - tmp1=tmp2=0; - for (i=0;i<nb;i++) if(T<chem[i]->Tc) {tmp2+=chem[i]->n(); tmp1+=chem[i]->n()*chem[i]->Psat(bp)/P;} - tmp1/=tmp2; - step=10*(1.0-tmp1); - } - } -} - -void stream::dew() -{ - dp=0.0; - tmp1=10; - for(i=0;i<nb;i++) if(T<chem[i]->Tc && chem[i]->Tboil(P)>dp && chem[i]->m>EPS) dp=chem[i]->Tboil(P); - if (dp>EPS) - { - dp=bp; - step=1; - while (fabs(step)>TOL_DP && fabs(tmp1/tmp2-1)>TOL_DP) - { - dp+=step; - if(dp<bp) dp=bp; - //if(DEBUG) cout<<endl<<dp; - tmp1=tmp2=0; - for (i=0;i<nb;i++) if(T<chem[i]->Tc) {tmp2+=chem[i]->n(); tmp1+=chem[i]->n()/chem[i]->Psat(dp)*P; } - if (step/fabs(step)*tmp2/tmp1 >1 || step/fabs(step)*tmp1/tmp2 <-1) step*= -0.1; - } - } -} - -double stream::quality() -{ - if(T>EPS) - { - bubble(); - dew(); - //if(DEBUG) cout<<endl<<name<<" bp="<<bp<<" dp="<<dp<<" T="<<T; system("pause"); - if (bp < dp) - { - if (bp < T && T< dp) tmp= (T-bp)/(dp-bp); - if (T<= bp) tmp= 0.0; - if (T >= dp) tmp= 1.0; - } - } - else tmp= 0.0; - return tmp; -} - -double stream::K(int i) -{ - for (j=0;j<nb;j++) - tab4[j] = chem[j]->n()/n(); - thermo->send(tab1,tab2,tab3, tab4); - if (T>EPS && P>EPS) - { - thermo->set(P,T,v,n()); - return thermo->K(i); - } - else - { - ofstream logf; - logf.open(MESSAGES, ios::app); - logf<<" --> Warning <-- Cannot compute K of "<<chem[i]->name<<" in stream "<<name<<".\n"; - logf.close(); - warning++; - check_error(); - return 1.0; - } -} - -double stream::n() -{ - tmp=0.0; - for ( k = 0 ; k < nb ; k++ ) - tmp+=chem[k]->n(); - return tmp; -} - - -// affectation : -stream & stream::operator = ( const stream & s ) { - - (*thermo) = *(s.thermo); - - delete [] tab1; - delete [] tab2; - delete [] tab3; - delete [] tab4; - for ( i = 0 ; i < nb ; i++ ) - delete chem[i]; - delete [] chem; - - P = s.P; - T = s.T; - m = s.m; - v = s.v; - i = s.i; - j = s.j; - k = s.k; - error = s.error; - warning = s.warning; - name = s.name; - nb = s.nb; - chem = new chemical *[nb]; - - tab1 = new double[nb]; - tab2 = new double[nb]; - tab3 = new double[nb]; - tab4 = new double[nb]; - - step = s.step; - - for ( i = 0 ; i < nb ; i++ ) { - chem[i] = new chemical(*s.chem[i]); - tab1[i] = s.tab1[i]; - tab2[i] = s.tab2[i]; - tab3[i] = s.tab3[i]; - tab4[i] = s.tab4[i]; - } - - tmp = s.tmp; - tmp1 = s.tmp1; - tmp2 = s.tmp2; - - return *this; -} - - -void stream::write() { - - string file_name = RUNTIME + name + ".stream"; - - cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; - - cout.unsetf(ios::scientific); - cout << setiosflags(ios::showpoint | ios::fixed)<<setprecision(1); - - cout << "\t>>" << setw(8) << P << " " << setw(9) << T <<" "; - - cout << resetiosflags(ios::fixed) << setiosflags(ios::scientific) << setprecision(3); - - if (m>EPS) - cout << setw(11) << m << setw(11) << v; - else - cout << " x x "; - for ( i = 0 ; i < nb ; i++ ) { - if ( chem[i]->m <= EPS ) - cout << " x "; - else - cout << setw(11) << chem[i]->m; - } - cout << "\n\tEND\n\n"; - - cout.setf(ios::scientific); - -} - -void stream::purge() -{ - P=T=m=v=0.0; - for(i=0;i<nb;i++) - chem[i]->purge(); -} +#include "stream.hpp" +using namespace std; + +// destructor : +stream::~stream ( void ) { + delete thermo; + delete [] tab1; + delete [] tab2; + delete [] tab3; + delete [] tab4; + for ( i = 0 ; i < nb ; i++ ) + delete chem[i]; + delete [] chem; +} + +void stream::check_error() +{ + + if (error>MAX_ERROR) { + cout << "ERROR 4\n\n"; + exit(0); + } + if (warning>MAX_WARNING) { + cout << "ERROR 5\n\n"; + exit(0); + } +} + +void stream::set ( int _nb , chemical ** _chem) { + int i; + for ( i = 0 ; i < nb ; i++ ) + delete chem[i]; + delete [] chem; + nb = _nb; + chem = new chemical * [nb]; + for ( i = 0 ; i < nb ; i++ ) + chem[i] = new chemical(*_chem[i]); +} + +void stream::set(double pres, double temp) //set P, T, find state and resulting v +{ + if(thermo->get_dim()!=nb) + { + delete thermo; + thermo = new thermolib(nb); + } + P=pres; + T=temp; + for (i=0;i<nb;i++) {chem[i]->P=pres; chem[i]->T=temp;} + if(n()>EPS) + { + v=quality(); + tmp1=0; + for (i=0;i<nb;i++) + { + if (T>chem[i]->Tc || v==1) chem[i]->state=1; + else chem[i]->state=0; + } + v=0; + for (i=0;i<nb;i++) + { + if (chem[i]->state==0) {if (chem[i]->m>EPS) v+= chem[i]->m/chem[i]->rho(); tab4[i]=0;} + if (chem[i]->state==1) {tab4[i] = chem[i]->n(); tmp1+=tab4[i];} + } + if (tmp1>EPS) + { + for (i=0;i<nb;i++) + { + tab1[i] = chem[i]->Pc; //cout<<endl<<tab1[i]; + tab2[i] = chem[i]->Tc; // cout<<" "<<tab2[i]; + tab3[i] = chem[i]->omega(); //cout<<" "<<tab3[i]; + tab4[i]/=tmp1; // cout<<" "<<tab4[i]; + } + thermo->send(tab1,tab2,tab3, tab4); + thermo->set(P,T,0.0,tmp1); + v+=thermo->v(); + } + } + else v= 0.0; +} + +void stream::set(double *list) +{ + m=0; + for (i=0; i<nb; i++) + { + chem[i]->m=list[i]; + m+=list[i]; + } +} + +void stream::bubble() +{ + bp=1.1e6; + for(i=0;i<nb;i++) if(T<chem[i]->Tc && chem[i]->Tboil(P)<bp && chem[i]->m>EPS) bp=chem[i]->Tboil(P); + if (bp==1.1e6) bp=0.0; + else + { + step=2; + while (fabs(step)>TOL_BP && fabs(tmp1-1)>TOL_BP) + { + //if(DEBUG) cout<<endl<<bp; + bp+=step; + tmp1=tmp2=0; + for (i=0;i<nb;i++) if(T<chem[i]->Tc) {tmp2+=chem[i]->n(); tmp1+=chem[i]->n()*chem[i]->Psat(bp)/P;} + tmp1/=tmp2; + step=10*(1.0-tmp1); + } + } +} + +void stream::dew() +{ + dp=0.0; + tmp1=10; + for(i=0;i<nb;i++) if(T<chem[i]->Tc && chem[i]->Tboil(P)>dp && chem[i]->m>EPS) dp=chem[i]->Tboil(P); + if (dp>EPS) + { + dp=bp; + step=1; + while (fabs(step)>TOL_DP && fabs(tmp1/tmp2-1)>TOL_DP) + { + dp+=step; + if(dp<bp) dp=bp; + //if(DEBUG) cout<<endl<<dp; + tmp1=tmp2=0; + for (i=0;i<nb;i++) if(T<chem[i]->Tc) {tmp2+=chem[i]->n(); tmp1+=chem[i]->n()/chem[i]->Psat(dp)*P; } + if (step/fabs(step)*tmp2/tmp1 >1 || step/fabs(step)*tmp1/tmp2 <-1) step*= -0.1; + } + } +} + +double stream::quality() +{ + if(T>EPS) + { + bubble(); + dew(); + //if(DEBUG) cout<<endl<<name<<" bp="<<bp<<" dp="<<dp<<" T="<<T; system("pause"); + if (bp < dp) + { + if (bp < T && T< dp) tmp= (T-bp)/(dp-bp); + if (T<= bp) tmp= 0.0; + if (T >= dp) tmp= 1.0; + } + } + else tmp= 0.0; + return tmp; +} + +double stream::K(int i) +{ + for (j=0;j<nb;j++) + tab4[j] = chem[j]->n()/n(); + thermo->send(tab1,tab2,tab3, tab4); + if (T>EPS && P>EPS) + { + thermo->set(P,T,v,n()); + return thermo->K(i); + } + else + { + ofstream logf; + logf.open(MESSAGES, ios::app); + logf<<" --> Warning <-- Cannot compute K of "<<chem[i]->name<<" in stream "<<name<<".\n"; + logf.close(); + warning++; + check_error(); + return 1.0; + } +} + +double stream::n() +{ + tmp=0.0; + for ( k = 0 ; k < nb ; k++ ) + tmp+=chem[k]->n(); + return tmp; +} + + +// affectation : +stream & stream::operator = ( const stream & s ) { + + (*thermo) = *(s.thermo); + + delete [] tab1; + delete [] tab2; + delete [] tab3; + delete [] tab4; + for ( i = 0 ; i < nb ; i++ ) + delete chem[i]; + delete [] chem; + + P = s.P; + T = s.T; + m = s.m; + v = s.v; + i = s.i; + j = s.j; + k = s.k; + error = s.error; + warning = s.warning; + name = s.name; + nb = s.nb; + chem = new chemical *[nb]; + + tab1 = new double[nb]; + tab2 = new double[nb]; + tab3 = new double[nb]; + tab4 = new double[nb]; + + step = s.step; + + for ( i = 0 ; i < nb ; i++ ) { + chem[i] = new chemical(*s.chem[i]); + tab1[i] = s.tab1[i]; + tab2[i] = s.tab2[i]; + tab3[i] = s.tab3[i]; + tab4[i] = s.tab4[i]; + } + + tmp = s.tmp; + tmp1 = s.tmp1; + tmp2 = s.tmp2; + + return *this; +} + + +void stream::write() { + + string file_name = RUNTIME + name + ".stream"; + + cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; + + cout.unsetf(ios::scientific); + cout << setiosflags(ios::showpoint | ios::fixed)<<setprecision(1); + + cout << "\t>>" << setw(8) << P << " " << setw(9) << T <<" "; + + cout << resetiosflags(ios::fixed) << setiosflags(ios::scientific) << setprecision(3); + + if (m>EPS) + cout << setw(11) << m << setw(11) << v; + else + cout << " x x "; + for ( i = 0 ; i < nb ; i++ ) { + if ( chem[i]->m <= EPS ) + cout << " x "; + else + cout << setw(11) << chem[i]->m; + } + cout << "\n\tEND\n\n"; + + cout.setf(ios::scientific); + +} + +void stream::purge() +{ + P=T=m=v=0.0; + for(i=0;i<nb;i++) + chem[i]->purge(); +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/stream.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/stream.hpp index 94b2102..895ef3d 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/stream.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/stream.hpp @@ -1,86 +1,86 @@ -#ifndef STREAM_H -#define STREAM_H -#include "chemical.hpp" -#include <iomanip> -using namespace std; - -class stream { - -private: - - stream ( void ) {} - stream ( const stream & s ) {} - -public: - void check_error(); - - double P, T, m, v; // Pressure in atm, temperature in K, - // total mass flow in kg/s, total volume flow in m3/s - - int i, j, k, error, warning; - - string name; - - int nb; // number of chemicals to store; - - chemical ** chem; // list of stored chemicals - - thermolib *thermo; - - double tmp, tmp1,tmp2, *tab1, *tab2, *tab3, *tab4; - double step; - void bubble(), dew(); - -public: - - - - - - double dp, bp; - double rho() {if(v!=0) return m/v; else exit(0);} // Apparent density in kg/m3 - double n(); // total mole flow (mol/s) - double quality(); // returns the vapor fraction of stream (1=all vapor, 0 = all liquid) - double K(int); // returns the vapor-liquid equilibrium constant of compound i - - // constructor : - stream ( const string _name , int n , chemical ** list ) : P (0 ) , - T (0 ) , - m (0 ) , - v (0 ) , - error (0 ) , - warning(0 ) , - name (_name ) , - nb (n ) , - chem (new chemical *[nb]) , - thermo (new thermolib (nb)) , - tab1 (new double [nb]) , - tab2 (new double [nb]) , - tab3 (new double [nb]) , - tab4 (new double [nb]) { - for ( i = 0 ; i < nb ; i++ ) - chem[i] = new chemical(*list[i]); - } - - - // affectation : - stream & operator = ( const stream & s ); - - void set_thermo ( thermolib * t ) { (*thermo) = *t; } - - - void set(double, double); // Sets P and T - void set(double*); // Sets mass flows - void set( const string & n ) { name = n;} - void set ( int _nb , chemical ** _chem); - - - // destructor : - ~stream ( void ); - - void write(); - void purge(); -}; - - -#endif +#ifndef STREAM_H +#define STREAM_H +#include "chemical.hpp" +#include <iomanip> +using namespace std; + +class stream { + +private: + + stream ( void ) {} + stream ( const stream & s ) {} + +public: + void check_error(); + + double P, T, m, v; // Pressure in atm, temperature in K, + // total mass flow in kg/s, total volume flow in m3/s + + int i, j, k, error, warning; + + string name; + + int nb; // number of chemicals to store; + + chemical ** chem; // list of stored chemicals + + thermolib *thermo; + + double tmp, tmp1,tmp2, *tab1, *tab2, *tab3, *tab4; + double step; + void bubble(), dew(); + +public: + + + + + + double dp, bp; + double rho() {if(v!=0) return m/v; else exit(0);} // Apparent density in kg/m3 + double n(); // total mole flow (mol/s) + double quality(); // returns the vapor fraction of stream (1=all vapor, 0 = all liquid) + double K(int); // returns the vapor-liquid equilibrium constant of compound i + + // constructor : + stream ( const string _name , int n , chemical ** list ) : P (0 ) , + T (0 ) , + m (0 ) , + v (0 ) , + error (0 ) , + warning(0 ) , + name (_name ) , + nb (n ) , + chem (new chemical *[nb]) , + thermo (new thermolib (nb)) , + tab1 (new double [nb]) , + tab2 (new double [nb]) , + tab3 (new double [nb]) , + tab4 (new double [nb]) { + for ( i = 0 ; i < nb ; i++ ) + chem[i] = new chemical(*list[i]); + } + + + // affectation : + stream & operator = ( const stream & s ); + + void set_thermo ( thermolib * t ) { (*thermo) = *t; } + + + void set(double, double); // Sets P and T + void set(double*); // Sets mass flows + void set( const string & n ) { name = n;} + void set ( int _nb , chemical ** _chem); + + + // destructor : + ~stream ( void ); + + void write(); + void purge(); +}; + + +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/thermolib.cpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/thermolib.cpp index 51e3fbb..5113bca 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/thermolib.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/thermolib.cpp @@ -1,175 +1,175 @@ -#include "thermolib.hpp" -#include "defines.hpp" -#include "secant.cpp" -using namespace std; - - - - -// affectation : -thermolib & thermolib::operator = ( const thermolib & t ) { - - if (dim!=t.dim) - reset(t.dim); - - for ( i = 0 ; i < dim ; i++ ) { - Pc[i] = t.Pc[i]; - Tc[i] = t.Tc[i]; - omega[i] = t.omega[i]; - molefrac[i] = t.molefrac[i]; - } - - return *this; -} - -thermolib::~thermolib() { - delete solver; - delete [] Pc; - delete [] Tc; - delete [] omega; - delete [] molefrac; -} - -void thermolib::construct ( void ) { - molefrac = new double[dim]; - Pc = new double[dim]; - Tc = new double[dim]; - omega = new double[dim]; - - // C. Tribes add this for more robustness (variables may be initialized uncorrectly dependent on the execution) - for ( i = 0 ; i < dim ; i++ ) - { - Pc[i] = 0.0; - Tc[i] = 0.0; - omega[i] = 0.0; - molefrac[i] = 0.0; - } - - - solver = new secant<thermolib>(); -} - -void thermolib::reset(int b) -{ - delete [] molefrac; - delete [] Pc; - delete [] Tc; - delete [] omega; - delete solver; - dim = b; - construct(); -} - -double thermolib::a_mix() -{ - if (dim>1) - { - tmp=0; - for (i=0;i<dim;i++) - for (j=0;j<dim;j++) - tmp += molefrac[i]*molefrac[j]*sqrt(a(i)*a(j)); - return tmp; - } - else return a(0); -} - -double thermolib::b_mix() -{ - if (dim>1) - { - tmp=0; - for (i=0;i<dim;i++) - tmp += molefrac[i]*b(i); - return tmp; - } - else return b(0); -} - -void thermolib::send(double* pc, double* tc, double* w, double* y) -{ - for (i=0;i<dim;i++) - { - Pc[i] = pc[i]*101.325; - Tc[i] = tc[i]; - omega[i] = w[i]; - molefrac[i] = y[i]; - } -} - -double thermolib::P() -{ - task=0; - pressure = 8.3144*temperature/molevolume; - solver->set(this, pressure, 1.001*pressure); - success=solver->run(); - return pressure/101.325; -} - -double thermolib::T() -{ - task=1; - temperature = pressure*molevolume/8.144; - solver->set(this, temperature, 1.001*temperature); - success=solver->run(); - return temperature; -} - -double thermolib::v() -{ - if (mole>EPS) - { - task=2; - molevolume = 8.3144*temperature/pressure; - solver->set(this, molevolume, 1.001*molevolume); - success=solver->run(); - return 0.001*mole*molevolume; - } - else return 0.0; -} - -double thermolib::Zv() -{ - task=4; - solver->set(this, 1.0, 0.99); - success=solver->run(); - return Z; -} - -double thermolib::phiV(int i) -{ - return exp((Z-1)*B(i)/B() - log(Z-B()) - A()/B()*(2*sqrt(A(i)/A())-B(i)/B())*log(1+B()/Z)); -} - -double thermolib::phiL(int i) -{ - Pr = pressure/Pc[i]; - Tr = temperature/Tc[i]; - tmp = 2.05135 - 2.10899/Tr - 0.19396*pow(Tr,2) + 0.02282*pow(Tr,3) + (0.08852 - 0.00872*pow(Tr,2))*Pr + (-0.00353 - 0.00203*Tr)*pow(Pr,2) - log10(Pr); - tmp += omega[i]*(-4.23893 + 8.65808*Tr - 1.2206/Tr - 3.15224*pow(Tr,3) - 0.025*(Pr-0.6)); - return pow(10, tmp); -} - -double thermolib::f(double x) -{ - if (task==0) - { - pressure=x; - x= 8.3144*temperature/(molevolume-b_mix()) - a_mix()/(pow(molevolume,2)+b_mix()*molevolume) - x; - } - if (task==1) - { - temperature=x; - x= 8.3144*x/(molevolume-b_mix()) - a_mix()/(pow(molevolume,2)+b_mix()*molevolume) - pressure; - } - if (task==2) - { - molevolume=x; - x= 8.3144*temperature/(x-b_mix()) - a_mix()/(pow(x,2)+b_mix()*x) - pressure; - } - if(task==4) - { - Z=x; - x= (pow(x,3)-pow(x,2)+(A()-B()-pow(B(),2))*x-A()*B()); - } - return x; -} +#include "thermolib.hpp" +#include "defines.hpp" +#include "secant.cpp" +using namespace std; + + + + +// affectation : +thermolib & thermolib::operator = ( const thermolib & t ) { + + if (dim!=t.dim) + reset(t.dim); + + for ( i = 0 ; i < dim ; i++ ) { + Pc[i] = t.Pc[i]; + Tc[i] = t.Tc[i]; + omega[i] = t.omega[i]; + molefrac[i] = t.molefrac[i]; + } + + return *this; +} + +thermolib::~thermolib() { + delete solver; + delete [] Pc; + delete [] Tc; + delete [] omega; + delete [] molefrac; +} + +void thermolib::construct ( void ) { + molefrac = new double[dim]; + Pc = new double[dim]; + Tc = new double[dim]; + omega = new double[dim]; + + // C. Tribes add this for more robustness (variables may be initialized uncorrectly dependent on the execution) + for ( i = 0 ; i < dim ; i++ ) + { + Pc[i] = 0.0; + Tc[i] = 0.0; + omega[i] = 0.0; + molefrac[i] = 0.0; + } + + + solver = new secant<thermolib>(); +} + +void thermolib::reset(int b) +{ + delete [] molefrac; + delete [] Pc; + delete [] Tc; + delete [] omega; + delete solver; + dim = b; + construct(); +} + +double thermolib::a_mix() +{ + if (dim>1) + { + tmp=0; + for (i=0;i<dim;i++) + for (j=0;j<dim;j++) + tmp += molefrac[i]*molefrac[j]*sqrt(a(i)*a(j)); + return tmp; + } + else return a(0); +} + +double thermolib::b_mix() +{ + if (dim>1) + { + tmp=0; + for (i=0;i<dim;i++) + tmp += molefrac[i]*b(i); + return tmp; + } + else return b(0); +} + +void thermolib::send(double* pc, double* tc, double* w, double* y) +{ + for (i=0;i<dim;i++) + { + Pc[i] = pc[i]*101.325; + Tc[i] = tc[i]; + omega[i] = w[i]; + molefrac[i] = y[i]; + } +} + +double thermolib::P() +{ + task=0; + pressure = 8.3144*temperature/molevolume; + solver->set(this, pressure, 1.001*pressure); + success=solver->run(); + return pressure/101.325; +} + +double thermolib::T() +{ + task=1; + temperature = pressure*molevolume/8.144; + solver->set(this, temperature, 1.001*temperature); + success=solver->run(); + return temperature; +} + +double thermolib::v() +{ + if (mole>EPS) + { + task=2; + molevolume = 8.3144*temperature/pressure; + solver->set(this, molevolume, 1.001*molevolume); + success=solver->run(); + return 0.001*mole*molevolume; + } + else return 0.0; +} + +double thermolib::Zv() +{ + task=4; + solver->set(this, 1.0, 0.99); + success=solver->run(); + return Z; +} + +double thermolib::phiV(int i) +{ + return exp((Z-1)*B(i)/B() - log(Z-B()) - A()/B()*(2*sqrt(A(i)/A())-B(i)/B())*log(1+B()/Z)); +} + +double thermolib::phiL(int i) +{ + Pr = pressure/Pc[i]; + Tr = temperature/Tc[i]; + tmp = 2.05135 - 2.10899/Tr - 0.19396*pow(Tr,2) + 0.02282*pow(Tr,3) + (0.08852 - 0.00872*pow(Tr,2))*Pr + (-0.00353 - 0.00203*Tr)*pow(Pr,2) - log10(Pr); + tmp += omega[i]*(-4.23893 + 8.65808*Tr - 1.2206/Tr - 3.15224*pow(Tr,3) - 0.025*(Pr-0.6)); + return pow(10, tmp); +} + +double thermolib::f(double x) +{ + if (task==0) + { + pressure=x; + x= 8.3144*temperature/(molevolume-b_mix()) - a_mix()/(pow(molevolume,2)+b_mix()*molevolume) - x; + } + if (task==1) + { + temperature=x; + x= 8.3144*x/(molevolume-b_mix()) - a_mix()/(pow(molevolume,2)+b_mix()*molevolume) - pressure; + } + if (task==2) + { + molevolume=x; + x= 8.3144*temperature/(x-b_mix()) - a_mix()/(pow(x,2)+b_mix()*x) - pressure; + } + if(task==4) + { + Z=x; + x= (pow(x,3)-pow(x,2)+(A()-B()-pow(B(),2))*x-A()*B()); + } + return x; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/thermolib.hpp b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/thermolib.hpp index 3440270..3d39c8c 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/surrogate/thermolib.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/surrogate/thermolib.hpp @@ -1,50 +1,50 @@ -#ifndef THERMOLIB_H -#define THERMOLIB_H -#include "secant.hpp" -using namespace std; - -class thermolib -{ - private: - bool success; - int dim, i, j; - double pressure, temperature, molevolume, mole,*molefrac; - double *Pc, *Tc, *omega, Z, tmp, Tr, Pr; - void construct(); - double a(int i) {return (0.42748*pow(8.8144,2)*pow(Tc[i],2)*pow(1.0+f_omega(i)*(1.0-sqrt(temperature/Tc[i])), 2)/Pc[i]);} - double a_mix(); - double b(int i) {return (0.08664*8.3144*Tc[i]/Pc[i]);} - double b_mix(); - double A(int i) {return (a(i)*pressure/pow(8.3144, 2)/pow(temperature, 2));} - double A() {return (a_mix()*pressure/pow(8.3144, 2)/pow(temperature, 2));} - double B(int i) {return (b(i)*pressure/8.3144/temperature);} - double B(){return (b_mix()*pressure/8.3144/temperature);} - double Zv(), phiV(int), phiL(int); - double f_omega(int i) {return (0.48 + 1.574*omega[i] - 0.176*pow(omega[i], 2));} - int task; //0=find P 1=find T 2=find v 3= find K 4=find Zv - secant<thermolib> *solver; - - public: - double P(); //retruns pressure at T and v, in atm - double T(); //returns temperature at P and v, in K - double v(); //returns volume flow at P, T, n(), in m3/s - double K() {Z = Zv(); return phiL(0)/phiV(0);} //returns the vapor-liquid equilibirum constant - double K(int i) {return phiL(i)/phiV(i);} - double compres_coeff(){return 1.0;}; - - -// affectation : - thermolib & operator = ( const thermolib & t ); - - thermolib ( int d = 1 ) { dim=d; construct();} - - void send(double pc, double tc, double w) { Pc[0] = pc*101.325; Tc[0] = tc; omega[0]=w;} - void send(double*, double*, double*, double*); - void set(double p, double t, double v, double n) {pressure=p*101.325; temperature=t; molevolume=0.001*n/v; mole=n;} - double f(double); - int get_dim() {return dim;} - ~thermolib(); - void reset(int); -}; -#endif - +#ifndef THERMOLIB_H +#define THERMOLIB_H +#include "secant.hpp" +using namespace std; + +class thermolib +{ + private: + bool success; + int dim, i, j; + double pressure, temperature, molevolume, mole,*molefrac; + double *Pc, *Tc, *omega, Z, tmp, Tr, Pr; + void construct(); + double a(int i) {return (0.42748*pow(8.8144,2)*pow(Tc[i],2)*pow(1.0+f_omega(i)*(1.0-sqrt(temperature/Tc[i])), 2)/Pc[i]);} + double a_mix(); + double b(int i) {return (0.08664*8.3144*Tc[i]/Pc[i]);} + double b_mix(); + double A(int i) {return (a(i)*pressure/pow(8.3144, 2)/pow(temperature, 2));} + double A() {return (a_mix()*pressure/pow(8.3144, 2)/pow(temperature, 2));} + double B(int i) {return (b(i)*pressure/8.3144/temperature);} + double B(){return (b_mix()*pressure/8.3144/temperature);} + double Zv(), phiV(int), phiL(int); + double f_omega(int i) {return (0.48 + 1.574*omega[i] - 0.176*pow(omega[i], 2));} + int task; //0=find P 1=find T 2=find v 3= find K 4=find Zv + secant<thermolib> *solver; + + public: + double P(); //retruns pressure at T and v, in atm + double T(); //returns temperature at P and v, in K + double v(); //returns volume flow at P, T, n(), in m3/s + double K() {Z = Zv(); return phiL(0)/phiV(0);} //returns the vapor-liquid equilibirum constant + double K(int i) {return phiL(i)/phiV(i);} + double compres_coeff(){return 1.0;}; + + +// affectation : + thermolib & operator = ( const thermolib & t ); + + thermolib ( int d = 1 ) { dim=d; construct();} + + void send(double pc, double tc, double w) { Pc[0] = pc*101.325; Tc[0] = tc; omega[0]=w;} + void send(double*, double*, double*, double*); + void set(double p, double t, double v, double n) {pressure=p*101.325; temperature=t; molevolume=0.001*n/v; mole=n;} + double f(double); + int get_dim() {return dim;} + ~thermolib(); + void reset(int); +}; +#endif + diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/RungeKutta.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/RungeKutta.cpp index 175e64b..dbc37f4 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/RungeKutta.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/RungeKutta.cpp @@ -1,80 +1,80 @@ -#include "RungeKutta.hpp" - -#include <iomanip> - -using namespace std; - -template <class E> -RungeKutta<E>::RungeKutta(int dim) -{ - m = dim; - k1 = new double[m]; - k2 = new double[m]; - k3 = new double[m]; - k4 = new double[m]; - y = new double[m]; - y_tmp = new double[m]; -} - -template <class E> -RungeKutta<E>::~RungeKutta() -{ - delete [] k1; - delete [] k2; - delete [] k3; - delete [] k4; - delete [] y; - delete [] y_tmp; -} - -template <class E> -void RungeKutta<E>::set ( E * tmp , double * y0 , double beg , double end ) -{ - unit=tmp; - x0=beg; xn=end; - x=x0; - h=double(xn-x0)/double(N_INTER); - for (i=0;i<m;i++) {y[i]=y0[i];} - success=true; -} - -template <class E> -bool RungeKutta<E>::run() { - for(j=0;j<MAX_ITER_RK;j++) { - //Avoid going out of x interval - if (x+h >xn) { - h = xn-x; - j = MAX_ITER_RK; - } - - //Compute k1, k2, k3, k4 - for(i=0;i<m;i++) - k1[i] = h*unit->f(i, x, y); - for(i=0;i<m;i++) - y_tmp[i] = y[i]+k1[i]/2.0; - for(i=0;i<m;i++) - k2[i] = h*unit->f(i, x+h/2.0, y_tmp); - for(i=0;i<m;i++) - y_tmp[i] = y[i]+k2[i]/2.0; - for(i=0;i<m;i++) - k3[i] = h*unit->f(i, x+h/2.0, y_tmp); - for(i=0;i<m;i++) - y_tmp[i] = y[i]+k3[i]; - for ( i = 0 ; i < m ; i++ ) - k4[i] = h*unit->f ( i , x+h , y_tmp ); - //Compute the new y - for(i=0;i<m;i++) - y[i]+=(k1[i]+2*k2[i]+2*k3[i]+k4[i])/6.0; - x += h; - } - - if ( x < xn-EPS ) {// MODIF SEB (le EPS) - success=false; - - // cout.setf(ios::fixed); - // cout << setprecision(12); - // cout << "x=" << x << " < xn=" << xn << " diff=" << xn-x << endl; - } - - return success; -} +#include "RungeKutta.hpp" + +#include <iomanip> + +using namespace std; + +template <class E> +RungeKutta<E>::RungeKutta(int dim) +{ + m = dim; + k1 = new double[m]; + k2 = new double[m]; + k3 = new double[m]; + k4 = new double[m]; + y = new double[m]; + y_tmp = new double[m]; +} + +template <class E> +RungeKutta<E>::~RungeKutta() +{ + delete [] k1; + delete [] k2; + delete [] k3; + delete [] k4; + delete [] y; + delete [] y_tmp; +} + +template <class E> +void RungeKutta<E>::set ( E * tmp , double * y0 , double beg , double end ) +{ + unit=tmp; + x0=beg; xn=end; + x=x0; + h=double(xn-x0)/double(N_INTER); + for (i=0;i<m;i++) {y[i]=y0[i];} + success=true; +} + +template <class E> +bool RungeKutta<E>::run() { + for(j=0;j<MAX_ITER_RK;j++) { + //Avoid going out of x interval + if (x+h >xn) { + h = xn-x; + j = MAX_ITER_RK; + } + + //Compute k1, k2, k3, k4 + for(i=0;i<m;i++) + k1[i] = h*unit->f(i, x, y); + for(i=0;i<m;i++) + y_tmp[i] = y[i]+k1[i]/2.0; + for(i=0;i<m;i++) + k2[i] = h*unit->f(i, x+h/2.0, y_tmp); + for(i=0;i<m;i++) + y_tmp[i] = y[i]+k2[i]/2.0; + for(i=0;i<m;i++) + k3[i] = h*unit->f(i, x+h/2.0, y_tmp); + for(i=0;i<m;i++) + y_tmp[i] = y[i]+k3[i]; + for ( i = 0 ; i < m ; i++ ) + k4[i] = h*unit->f ( i , x+h , y_tmp ); + //Compute the new y + for(i=0;i<m;i++) + y[i]+=(k1[i]+2*k2[i]+2*k3[i]+k4[i])/6.0; + x += h; + } + + if ( x < xn-EPS ) {// MODIF SEB (le EPS) + success=false; + + // cout.setf(ios::fixed); + // cout << setprecision(12); + // cout << "x=" << x << " < xn=" << xn << " diff=" << xn-x << endl; + } + + return success; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/RungeKutta.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/RungeKutta.hpp index db2b3c2..2400753 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/RungeKutta.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/RungeKutta.hpp @@ -1,37 +1,37 @@ -/* -To use the Runge-Kutta solver for systems of first order differential equations, - (the parametric object E must have public function such as E->f(i,x,y), - where i is the index of the function to evaluate, x is the time and - y is a point such as y(x), returns values of differential equation i) - - 1- construct the solver : solver = new RungeKutta<objet>(int); //the integer is the dimension of x - 2- set the solver : solver->set(unit, y0, x0, xn); //unit is usually the pointer *this, y0 are the initial conditions, and x0 and xn is the time interval - 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed???????????????????????????? - 4- delete the solver : delete solver; -(ref :Fortin) -*/ -#ifndef RUNGEKUTTA_H -#define RUNGEKUTTA_H - -#include "defines.hpp" -using namespace std; - -template <class E> -class RungeKutta -{ -private: - double *k1, *k2, *k3, *k4, *y_tmp, *y; - // double k1[MAX_DIM], k2[MAX_DIM], k3[MAX_DIM], k4[MAX_DIM], y_tmp[MAX_DIM], y[MAX_DIM]; - double h, x0, xn, x; - int i, j, m; - bool success; - E *unit; - -public: - RungeKutta(int); - ~RungeKutta(); - void set(E*, double*, double, double); - double dx(){return h;} - bool run(); -}; -#endif +/* +To use the Runge-Kutta solver for systems of first order differential equations, + (the parametric object E must have public function such as E->f(i,x,y), + where i is the index of the function to evaluate, x is the time and + y is a point such as y(x), returns values of differential equation i) + + 1- construct the solver : solver = new RungeKutta<objet>(int); //the integer is the dimension of x + 2- set the solver : solver->set(unit, y0, x0, xn); //unit is usually the pointer *this, y0 are the initial conditions, and x0 and xn is the time interval + 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed???????????????????????????? + 4- delete the solver : delete solver; +(ref :Fortin) +*/ +#ifndef RUNGEKUTTA_H +#define RUNGEKUTTA_H + +#include "defines.hpp" +using namespace std; + +template <class E> +class RungeKutta +{ +private: + double *k1, *k2, *k3, *k4, *y_tmp, *y; + // double k1[MAX_DIM], k2[MAX_DIM], k3[MAX_DIM], k4[MAX_DIM], y_tmp[MAX_DIM], y[MAX_DIM]; + double h, x0, xn, x; + int i, j, m; + bool success; + E *unit; + +public: + RungeKutta(int); + ~RungeKutta(); + void set(E*, double*, double, double); + double dx(){return h;} + bool run(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/bb.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/bb.cpp index 151727d..4e348d7 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/bb.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/bb.cpp @@ -1,361 +1,361 @@ -#include "servor.hpp" -#include "profitability.hpp" -using namespace std; - -/*------------------------------------------------------------------------*/ -/* fonction principale */ -/*------------------------------------------------------------------------*/ -int main ( int argc , char ** argv ) { - - double g0 = 1e+20; - double g1 = 1e+20; - double g2 = 1e+20; - double g3 = 1e+20; - double g4 = 1e+20; - double g5 = 1e+20; - double g6 = 1e+20; - double g7 = 1e+20; - double g8 = 1e+20; - double g9 = 1e+20; - double g10 = 1e+20; - double f = 1e+20; - - bool OK; - ifstream in; - double d; - int i; - int i_stream , i_chem; - double x [8]; - long double tmp[8]; - double raw_cost; - double util_cost; - double Itot; - double Coper; - double Rtot; - double max; - double mtot; - double m; - double purity; - int nb_chem = 7; - int nb_s = 15; - int nb_u = 11; - int n = 8; - double l [8] = { 600 , 2 , 0.0001 , 0.0001 , 2 , 0.01 , 0.1 , 300 }; - double u [8] = { 1100 , 20 , 0.1 , 0.1 , 20 , 0.5 , 5 , 500 }; - double list [7] = { 0.5 , 0 , 0 , 0 , 0 , 0 , 0 }; - double price[7] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 }; - profitability * P = NULL; - cashflow * F = NULL; - chemical ** chem = NULL; - stream ** s = NULL; - servor * units = NULL; - string * safe = NULL; - - // verif. du nombre d'arguments : - if (argc!=2) { - // cout << "\nargc != 2\n\n"; - goto TERMINATE; - } - - // lecture et scaling de x : - // ------------------------- - in.open (argv[1]); - - for ( i = 0 ; i < n ; i++ ) - in >> tmp[i]; - - in.close(); - - if (in.fail()) { - // cout << "\nin.fail (1)\n\n"; - goto TERMINATE; - } - - //for ( i = 0 ; i < n ; i++ ) - // cout << "tmp[" << i << "] = " << tmp[i] << endl; - // cout << endl; - - for ( i = 0 ; i < n ; i++ ) - x[i] = (u[i]-l[i])*((double)tmp[i]/100.0) + l[i]; - - //for ( i = 0 ; i < n ; i++ ) - // cout << "x[" << i << "] = " << x[i] << endl; - - // verifs de x (j'ai pris ca dans checkup et c'est tout ce dont - // ca a besoin de checker ici) : - if ( x[6] < EPS || x[2] < 0 || x[2] > 1 || x[3] < 0 || x[3] > 1 ) - goto TERMINATE; - - // chemicals : - // ----------- - chem = new chemical * [nb_chem]; - chem[0] = new chemical ("100-41-4" ); - chem[1] = new chemical ("1333-74-0"); - chem[2] = new chemical ("108-88-3" ); - chem[3] = new chemical ("74-82-8" ); - chem[4] = new chemical ("71-43-2" ); - chem[5] = new chemical ("74-85-1" ); - chem[6] = new chemical ("100-42-5" ); - - price[6] = 1.39; - price[2] = 0.64; - price[0] = 0.11; - price[4] = 1.19; - - // streams : - // --------- - s = new stream * [nb_s]; - s[ 0] = new stream ( "feed" , nb_chem , chem ); - s[ 1] = new stream ( "2" , nb_chem , chem ); - s[ 2] = new stream ( "3" , nb_chem , chem ); - s[ 3] = new stream ( "4" , nb_chem , chem ); - s[ 4] = new stream ( "5" , nb_chem , chem ); - s[ 5] = new stream ( "6" , nb_chem , chem ); - s[ 6] = new stream ( "7" , nb_chem , chem ); - s[ 7] = new stream ( "8" , nb_chem , chem ); - s[ 8] = new stream ( "9" , nb_chem , chem ); - s[ 9] = new stream ( "10" , nb_chem , chem ); - s[10] = new stream ( "back" , nb_chem , chem ); - s[11] = new stream ( "12" , nb_chem , chem ); - s[12] = new stream ( "stack" , nb_chem , chem ); - s[13] = new stream ( "out-bz" , nb_chem , chem ); - s[14] = new stream ( "out-sty" , nb_chem , chem ); - - // initial conditions on streams : - // ------------------------------- - s[0]->P = 1.0; - s[0]->T = 298; - s[0]->set(list); - - // units settings and calculation sequence : - // ----------------------------------------- - units = new servor ( nb_u , nb_s , s ); - safe = new string[nb_u]; - - units->type[ 0] = "mix"; - units->name[ 0] = safe[ 0] = "mixfeed"; - units->type[ 1] = "pump"; - units->name[ 1] = safe[ 1] = "pump"; - units->type[ 2] = "heatx"; - units->name[ 2] = safe[ 2] = "heater"; - units->type[ 3] = "reactor"; - units->name[ 3] = safe[ 3] = "pfr"; - units->type[ 4] = "heatx"; - units->name[ 4] = safe[ 4] = "cooler"; - units->type[ 5] = "flash"; - units->name[ 5] = safe[ 5] = "degasor"; - units->type[ 6] = "column"; - units->name[ 6] = safe[ 6] = "sep-sty"; - units->type[ 7] = "split"; - units->name[ 7] = safe[ 7] = "spliter"; - units->type[ 8] = "column"; - units->name[ 8] = safe[ 8] = "sep-bz"; - units->type[ 9] = "loop"; - units->name[ 9] = safe[ 9] = "looping"; - units->type[10] = "burner"; - units->name[10] = safe[10] = "fire"; - - - // executing the calculation sequence : - //------------------------------------- - double y[14]; - y[7] = y[8] = 1000.0; - - if (!units->solve_process(x,y)) - goto TERMINATE; - - // on recupere les resultats : - // --------------------------- - y[6] = s[0]->m; - y[3] = s[13]->m; - y[2] = s[13]->chem[4]->m; - y[1] = s[14]->m; - y[0] = s[14]->chem[6]->m; - - y[9 ] = 1e20; - y[10] = 1e20; - y[11] = units->get_costs_sum() * 6.192; - y[12] = 1e20; - y[13] = 1e20; - - // arrondis : - if (ARRONDI) { - y[ 6] = arrondi ( y[ 6] , 4 ); - y[ 3] = arrondi ( y[ 3] , 4 ); - y[ 2] = arrondi ( y[ 2] , 4 ); - y[ 1] = arrondi ( y[ 1] , 4 ); - y[ 0] = arrondi ( y[ 0] , 4 ); - y[11] = arrondi ( y[11] , 6 ); - } - - g0 = ( y[0] > 0 && y[0] < 1e+20 ) ? 0.0 : 1e20; - g1 = ( y[4] <= 80 ) ? 0.0 : 1.0; - g2 = ( y[5] <= 80 ) ? 0.0 : 1.0; - g3 = ( y[7] <= 200 && y[8] <= 8 ) ? 0.0 : 1.0; - g4 = ( y[1] > 0 && y[1] < 1e20 ) ? (0.99-y[0]/y[1])/0.99 : 1e20; - g5 = ( y[3] > 0 && y[3] < 1e20 ) ? (0.99-y[2]/y[3])/0.99 : 1e20; - g6 = ( y[6] > 0 && y[6] < 1e20 ) ? (0.6-y[0]/y[6])/0.6 : 1e20; - - - // bloc econo : - // ------------ - - // raw_cost : - raw_cost = 0.0; - if ( s[0]->m > EPS ) { - if ( s[0]->chem[6]->m > EPS ) { - d = (ARRONDI) ? arrondi ( s[0]->chem[6]->m , 4 ) : s[0]->chem[6]->m; - raw_cost += d * 1.39; - } - if ( s[0]->chem[2]->m > EPS ) { - d = (ARRONDI) ? arrondi ( s[0]->chem[2]->m , 4 ) : s[0]->chem[2]->m; - raw_cost += d * 0.64; - } - if ( s[0]->chem[0]->m > EPS ) { - d = (ARRONDI) ? arrondi ( s[0]->chem[0]->m , 4 ) : s[0]->chem[0]->m; - raw_cost += d * 0.11; - } - if ( s[0]->chem[4]->m > EPS ) { - d = (ARRONDI) ? arrondi ( s[0]->chem[4]->m , 4 ) : s[0]->chem[4]->m; - raw_cost += d * 1.19; - } - } - // raw_cost = raw_cost*3600.0*nb_h*nb_d : - raw_cost *= 25920000; - - // util_cost : - util_cost = (units->get_power_sum() * 0.000125 + units->get_water_sum() * 0.00008) * 25920000; - - // Coper : - Itot = y[11]; - Coper = 0.16 * Itot + 2.26 * raw_cost + util_cost; - - - // Rtot : - Rtot = 0.0; - for ( i_stream = 13 ; i_stream < 15 ; i_stream++ ) { - i_chem = 0; - max = 0.0; - mtot = 0.0; - for ( i = 0 ; i < nb_chem ; i++ ) { - m = (ARRONDI) ? arrondi ( s[i_stream]->chem[i]->m , 4 ) : s[i_stream]->chem[i]->m; - - if ( m > EPS ) { - mtot += m; - if ( m > max ) { - max = m; - i_chem = i; - } - } - } - if (mtot > EPS ) { - purity = max/mtot; - d = price[i_chem] * max; - if ( purity < 0.5 ) - d = 0.0; - else if ( purity < 0.6 ) - d *= 0.05; - else if ( purity < 0.7 ) - d *= 0.1; - else if ( purity < 0.8 ) - d *= 0.15; - else if ( purity < 0.9 ) - d *= 0.3; - else if ( purity < 0.95 ) - d *= 0.5; - else if ( purity < 0.98 ) - d *= 0.6; - else if ( purity < 0.99 ) - d *= 0.8; - else if ( purity > 0.995 ) - d *= 1.1; - Rtot += d*25920000; - } - } - - // cash flows : - F = new cashflow(15); - F->set_rates(0.1,0.4); - F->set_basics(Itot, Coper, Rtot); - OK = F->run(); - - // calculating profitability indicators : - if(OK) { - P = new profitability(F); - OK = P->run(y); - delete P; - } - - delete F; - - // arrondis : - if (ARRONDI) { - y[12] = round(y[12]); - y[13] = round(y[13]); - y[ 9] = round(y[ 9]*10)/10.0; - y[10] = round(y[10]*10)/10.0; - } - - g7 = ( y[ 9] < 1e20 ) ? ( y[9] - 4.0 ) / 4.0 : 1e20; - g8 = ( y[10] < 1e20 ) ? (0.2-y[10])/0.2 : 1e20; - g9 = ( y[11] < 1e20 ) ? (y[11]-10e6)/10e6 : 1e20; - g10 = ( y[12] > 0 && y[12] < 1e20 ) ? (y[12]-15e6) / 15e6 : 1e20; - - f = ( y[13] > 0 && y[13] < 1e20 ) ? -y[13] : 1e20; - -// cout << setprecision(10); -// cout << "\n\n"; -// for ( int i = 0 ; i < 14 ; i++ ) -// cout << "y[" << i << "] = " << y[i] << endl; - - - // menage et affichage du resultat de la boite noire : - TERMINATE: - - // cout << "\n\n"; - // cout << " g0 = " << g0 << endl - // << " g1 = " << g1 << endl - // << " g2 = " << g2 << endl - // << " g3 = " << g3 << endl - // << " g4 = " << g4 << endl - // << " g5 = " << g5 << endl - // << " g6 = " << g6 << endl - // << " g7 = " << g7 << endl - // << " g8 = " << g8 << endl - // << " g9 = " << g9 << endl - // << "g10 = " << g10 << endl - // << " f = " << f << endl; - - - cout << g0 << " " - << g1 << " " - << g2 << " " - << g3 << " " - << g4 << " " - << g5 << " " - << g6 << " " - << g7 << " " - << g8 << " " - << g9 << " " - << g10 << " " - << f << endl; - - if (units) - delete units; - if (safe) - delete [] safe; - - if (chem) { - for ( i = 0 ; i < nb_chem ; i++ ) - delete chem[i]; - delete [] chem; - } - - if (s) { - for ( i = 0 ; i < nb_s ; i++ ) - delete s[i]; - delete [] s; - } - - return 0; -} +#include "servor.hpp" +#include "profitability.hpp" +using namespace std; + +/*------------------------------------------------------------------------*/ +/* fonction principale */ +/*------------------------------------------------------------------------*/ +int main ( int argc , char ** argv ) { + + double g0 = 1e+20; + double g1 = 1e+20; + double g2 = 1e+20; + double g3 = 1e+20; + double g4 = 1e+20; + double g5 = 1e+20; + double g6 = 1e+20; + double g7 = 1e+20; + double g8 = 1e+20; + double g9 = 1e+20; + double g10 = 1e+20; + double f = 1e+20; + + bool OK; + ifstream in; + double d; + int i; + int i_stream , i_chem; + double x [8]; + long double tmp[8]; + double raw_cost; + double util_cost; + double Itot; + double Coper; + double Rtot; + double max; + double mtot; + double m; + double purity; + int nb_chem = 7; + int nb_s = 15; + int nb_u = 11; + int n = 8; + double l [8] = { 600 , 2 , 0.0001 , 0.0001 , 2 , 0.01 , 0.1 , 300 }; + double u [8] = { 1100 , 20 , 0.1 , 0.1 , 20 , 0.5 , 5 , 500 }; + double list [7] = { 0.5 , 0 , 0 , 0 , 0 , 0 , 0 }; + double price[7] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 }; + profitability * P = NULL; + cashflow * F = NULL; + chemical ** chem = NULL; + stream ** s = NULL; + servor * units = NULL; + string * safe = NULL; + + // verif. du nombre d'arguments : + if (argc!=2) { + // cout << "\nargc != 2\n\n"; + goto TERMINATE; + } + + // lecture et scaling de x : + // ------------------------- + in.open (argv[1]); + + for ( i = 0 ; i < n ; i++ ) + in >> tmp[i]; + + in.close(); + + if (in.fail()) { + // cout << "\nin.fail (1)\n\n"; + goto TERMINATE; + } + + //for ( i = 0 ; i < n ; i++ ) + // cout << "tmp[" << i << "] = " << tmp[i] << endl; + // cout << endl; + + for ( i = 0 ; i < n ; i++ ) + x[i] = (u[i]-l[i])*((double)tmp[i]/100.0) + l[i]; + + //for ( i = 0 ; i < n ; i++ ) + // cout << "x[" << i << "] = " << x[i] << endl; + + // verifs de x (j'ai pris ca dans checkup et c'est tout ce dont + // ca a besoin de checker ici) : + if ( x[6] < EPS || x[2] < 0 || x[2] > 1 || x[3] < 0 || x[3] > 1 ) + goto TERMINATE; + + // chemicals : + // ----------- + chem = new chemical * [nb_chem]; + chem[0] = new chemical ("100-41-4" ); + chem[1] = new chemical ("1333-74-0"); + chem[2] = new chemical ("108-88-3" ); + chem[3] = new chemical ("74-82-8" ); + chem[4] = new chemical ("71-43-2" ); + chem[5] = new chemical ("74-85-1" ); + chem[6] = new chemical ("100-42-5" ); + + price[6] = 1.39; + price[2] = 0.64; + price[0] = 0.11; + price[4] = 1.19; + + // streams : + // --------- + s = new stream * [nb_s]; + s[ 0] = new stream ( "feed" , nb_chem , chem ); + s[ 1] = new stream ( "2" , nb_chem , chem ); + s[ 2] = new stream ( "3" , nb_chem , chem ); + s[ 3] = new stream ( "4" , nb_chem , chem ); + s[ 4] = new stream ( "5" , nb_chem , chem ); + s[ 5] = new stream ( "6" , nb_chem , chem ); + s[ 6] = new stream ( "7" , nb_chem , chem ); + s[ 7] = new stream ( "8" , nb_chem , chem ); + s[ 8] = new stream ( "9" , nb_chem , chem ); + s[ 9] = new stream ( "10" , nb_chem , chem ); + s[10] = new stream ( "back" , nb_chem , chem ); + s[11] = new stream ( "12" , nb_chem , chem ); + s[12] = new stream ( "stack" , nb_chem , chem ); + s[13] = new stream ( "out-bz" , nb_chem , chem ); + s[14] = new stream ( "out-sty" , nb_chem , chem ); + + // initial conditions on streams : + // ------------------------------- + s[0]->P = 1.0; + s[0]->T = 298; + s[0]->set(list); + + // units settings and calculation sequence : + // ----------------------------------------- + units = new servor ( nb_u , nb_s , s ); + safe = new string[nb_u]; + + units->type[ 0] = "mix"; + units->name[ 0] = safe[ 0] = "mixfeed"; + units->type[ 1] = "pump"; + units->name[ 1] = safe[ 1] = "pump"; + units->type[ 2] = "heatx"; + units->name[ 2] = safe[ 2] = "heater"; + units->type[ 3] = "reactor"; + units->name[ 3] = safe[ 3] = "pfr"; + units->type[ 4] = "heatx"; + units->name[ 4] = safe[ 4] = "cooler"; + units->type[ 5] = "flash"; + units->name[ 5] = safe[ 5] = "degasor"; + units->type[ 6] = "column"; + units->name[ 6] = safe[ 6] = "sep-sty"; + units->type[ 7] = "split"; + units->name[ 7] = safe[ 7] = "spliter"; + units->type[ 8] = "column"; + units->name[ 8] = safe[ 8] = "sep-bz"; + units->type[ 9] = "loop"; + units->name[ 9] = safe[ 9] = "looping"; + units->type[10] = "burner"; + units->name[10] = safe[10] = "fire"; + + + // executing the calculation sequence : + //------------------------------------- + double y[14]; + y[7] = y[8] = 1000.0; + + if (!units->solve_process(x,y)) + goto TERMINATE; + + // on recupere les resultats : + // --------------------------- + y[6] = s[0]->m; + y[3] = s[13]->m; + y[2] = s[13]->chem[4]->m; + y[1] = s[14]->m; + y[0] = s[14]->chem[6]->m; + + y[9 ] = 1e20; + y[10] = 1e20; + y[11] = units->get_costs_sum() * 6.192; + y[12] = 1e20; + y[13] = 1e20; + + // arrondis : + if (ARRONDI) { + y[ 6] = arrondi ( y[ 6] , 4 ); + y[ 3] = arrondi ( y[ 3] , 4 ); + y[ 2] = arrondi ( y[ 2] , 4 ); + y[ 1] = arrondi ( y[ 1] , 4 ); + y[ 0] = arrondi ( y[ 0] , 4 ); + y[11] = arrondi ( y[11] , 6 ); + } + + g0 = ( y[0] > 0 && y[0] < 1e+20 ) ? 0.0 : 1e20; + g1 = ( y[4] <= 80 ) ? 0.0 : 1.0; + g2 = ( y[5] <= 80 ) ? 0.0 : 1.0; + g3 = ( y[7] <= 200 && y[8] <= 8 ) ? 0.0 : 1.0; + g4 = ( y[1] > 0 && y[1] < 1e20 ) ? (0.99-y[0]/y[1])/0.99 : 1e20; + g5 = ( y[3] > 0 && y[3] < 1e20 ) ? (0.99-y[2]/y[3])/0.99 : 1e20; + g6 = ( y[6] > 0 && y[6] < 1e20 ) ? (0.6-y[0]/y[6])/0.6 : 1e20; + + + // bloc econo : + // ------------ + + // raw_cost : + raw_cost = 0.0; + if ( s[0]->m > EPS ) { + if ( s[0]->chem[6]->m > EPS ) { + d = (ARRONDI) ? arrondi ( s[0]->chem[6]->m , 4 ) : s[0]->chem[6]->m; + raw_cost += d * 1.39; + } + if ( s[0]->chem[2]->m > EPS ) { + d = (ARRONDI) ? arrondi ( s[0]->chem[2]->m , 4 ) : s[0]->chem[2]->m; + raw_cost += d * 0.64; + } + if ( s[0]->chem[0]->m > EPS ) { + d = (ARRONDI) ? arrondi ( s[0]->chem[0]->m , 4 ) : s[0]->chem[0]->m; + raw_cost += d * 0.11; + } + if ( s[0]->chem[4]->m > EPS ) { + d = (ARRONDI) ? arrondi ( s[0]->chem[4]->m , 4 ) : s[0]->chem[4]->m; + raw_cost += d * 1.19; + } + } + // raw_cost = raw_cost*3600.0*nb_h*nb_d : + raw_cost *= 25920000; + + // util_cost : + util_cost = (units->get_power_sum() * 0.000125 + units->get_water_sum() * 0.00008) * 25920000; + + // Coper : + Itot = y[11]; + Coper = 0.16 * Itot + 2.26 * raw_cost + util_cost; + + + // Rtot : + Rtot = 0.0; + for ( i_stream = 13 ; i_stream < 15 ; i_stream++ ) { + i_chem = 0; + max = 0.0; + mtot = 0.0; + for ( i = 0 ; i < nb_chem ; i++ ) { + m = (ARRONDI) ? arrondi ( s[i_stream]->chem[i]->m , 4 ) : s[i_stream]->chem[i]->m; + + if ( m > EPS ) { + mtot += m; + if ( m > max ) { + max = m; + i_chem = i; + } + } + } + if (mtot > EPS ) { + purity = max/mtot; + d = price[i_chem] * max; + if ( purity < 0.5 ) + d = 0.0; + else if ( purity < 0.6 ) + d *= 0.05; + else if ( purity < 0.7 ) + d *= 0.1; + else if ( purity < 0.8 ) + d *= 0.15; + else if ( purity < 0.9 ) + d *= 0.3; + else if ( purity < 0.95 ) + d *= 0.5; + else if ( purity < 0.98 ) + d *= 0.6; + else if ( purity < 0.99 ) + d *= 0.8; + else if ( purity > 0.995 ) + d *= 1.1; + Rtot += d*25920000; + } + } + + // cash flows : + F = new cashflow(15); + F->set_rates(0.1,0.4); + F->set_basics(Itot, Coper, Rtot); + OK = F->run(); + + // calculating profitability indicators : + if(OK) { + P = new profitability(F); + OK = P->run(y); + delete P; + } + + delete F; + + // arrondis : + if (ARRONDI) { + y[12] = round(y[12]); + y[13] = round(y[13]); + y[ 9] = round(y[ 9]*10)/10.0; + y[10] = round(y[10]*10)/10.0; + } + + g7 = ( y[ 9] < 1e20 ) ? ( y[9] - 4.0 ) / 4.0 : 1e20; + g8 = ( y[10] < 1e20 ) ? (0.2-y[10])/0.2 : 1e20; + g9 = ( y[11] < 1e20 ) ? (y[11]-10e6)/10e6 : 1e20; + g10 = ( y[12] > 0 && y[12] < 1e20 ) ? (y[12]-15e6) / 15e6 : 1e20; + + f = ( y[13] > 0 && y[13] < 1e20 ) ? -y[13] : 1e20; + +// cout << setprecision(10); +// cout << "\n\n"; +// for ( int i = 0 ; i < 14 ; i++ ) +// cout << "y[" << i << "] = " << y[i] << endl; + + + // menage et affichage du resultat de la boite noire : + TERMINATE: + + // cout << "\n\n"; + // cout << " g0 = " << g0 << endl + // << " g1 = " << g1 << endl + // << " g2 = " << g2 << endl + // << " g3 = " << g3 << endl + // << " g4 = " << g4 << endl + // << " g5 = " << g5 << endl + // << " g6 = " << g6 << endl + // << " g7 = " << g7 << endl + // << " g8 = " << g8 << endl + // << " g9 = " << g9 << endl + // << "g10 = " << g10 << endl + // << " f = " << f << endl; + + + cout << g0 << " " + << g1 << " " + << g2 << " " + << g3 << " " + << g4 << " " + << g5 << " " + << g6 << " " + << g7 << " " + << g8 << " " + << g9 << " " + << g10 << " " + << f << endl; + + if (units) + delete units; + if (safe) + delete [] safe; + + if (chem) { + for ( i = 0 ; i < nb_chem ; i++ ) + delete chem[i]; + delete [] chem; + } + + if (s) { + for ( i = 0 ; i < nb_s ; i++ ) + delete s[i]; + delete [] s; + } + + return 0; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/bissection.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/bissection.cpp index 60e3d38..d23a939 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/bissection.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/bissection.cpp @@ -1,27 +1,27 @@ -#include "bissection.hpp" -using namespace std; - -template <class E> -bool bissection<E>::run() -{ - for (i=1; i<MAX_ITER_BISSECTION; i++) - { - xm=(x1+x2)/2; - // if(DEBUG) cout<<endl<<x1<<" "<<xm<<" "<<x2; - if (fabs(x1-x2)/fabs(xm) < TOL_BISSECTION) - { - i=MAX_ITER_BISSECTION; - OK=true; - } - else - { - f1 = unit->f(x1); - fm = unit->f(xm); - f2 = unit->f(x2); - if (f1*fm < 0.0) x2 = xm; - if (fm*f2 < 0.0) x1 = xm; - } - } - // if (DEBUG) system("pause"); - return OK; -} +#include "bissection.hpp" +using namespace std; + +template <class E> +bool bissection<E>::run() +{ + for (i=1; i<MAX_ITER_BISSECTION; i++) + { + xm=(x1+x2)/2; + // if(DEBUG) cout<<endl<<x1<<" "<<xm<<" "<<x2; + if (fabs(x1-x2)/fabs(xm) < TOL_BISSECTION) + { + i=MAX_ITER_BISSECTION; + OK=true; + } + else + { + f1 = unit->f(x1); + fm = unit->f(xm); + f2 = unit->f(x2); + if (f1*fm < 0.0) x2 = xm; + if (fm*f2 < 0.0) x1 = xm; + } + } + // if (DEBUG) system("pause"); + return OK; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/bissection.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/bissection.hpp index c277e29..18d4ee6 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/bissection.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/bissection.hpp @@ -1,31 +1,31 @@ -/* -To use the bissection solver to find the root of a scalar function -when the secant solver fails. - (the parametric object E must have public function such as E->f(x), - where x is the point at which evaluate f.) - 1- construct the solver : solver = new bissect<E>(); - 2- set the solver : solver->set(unit, x0, x1); //unit is usually the pointer *this, and x0 and x1 are the interval's bounds - 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed -*/ -#ifndef BISSECTION_H -#define BISSECTION_H - -#include "defines.hpp" -using namespace std; - -template <class E> -class bissection { -private: - double x1, xm, x2; - double f1, fm, f2; - int i; - bool OK; - E *unit; - -public: - bissection(){x1=xm=x2=f1=fm=f2=0; OK=false;} - void set(E* tmp, double xx1, double xx2) {unit=tmp; x1=xx1; x2=xx2;} - bool run(); - ~bissection(){} -}; -#endif +/* +To use the bissection solver to find the root of a scalar function +when the secant solver fails. + (the parametric object E must have public function such as E->f(x), + where x is the point at which evaluate f.) + 1- construct the solver : solver = new bissect<E>(); + 2- set the solver : solver->set(unit, x0, x1); //unit is usually the pointer *this, and x0 and x1 are the interval's bounds + 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed +*/ +#ifndef BISSECTION_H +#define BISSECTION_H + +#include "defines.hpp" +using namespace std; + +template <class E> +class bissection { +private: + double x1, xm, x2; + double f1, fm, f2; + int i; + bool OK; + E *unit; + +public: + bissection(){x1=xm=x2=f1=fm=f2=0; OK=false;} + void set(E* tmp, double xx1, double xx2) {unit=tmp; x1=xx1; x2=xx2;} + bool run(); + ~bissection(){} +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/burner.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/burner.cpp index eb8a223..1b6f36b 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/burner.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/burner.cpp @@ -1,287 +1,287 @@ -#include "burner.hpp" -using namespace std; - -/*----------------------------------------------------------*/ -/* arrondi pour ne conserver que n chiffres significatifs */ -/*----------------------------------------------------------*/ -double arrondi ( double x , int n ) { - if (fabs(x) < EPS) - return 0.0; - double m = pow ( 10 , ceil(-log10(x)) + n - 1 ); - return round(m*x)/m; -} - -/*---------------------------------------------------------------*/ -burner::burner ( int nb , chemical ** chem ) { - - rem_nb = nb; - - NO=NO2=N2O=CO=0.0; - m = new double[nb]; - can_burn = new bool[nb]; - - // combustion.prop : - // ----------------- - // 64-17-5 3 2 3 - // 74-82-8 2 1 2 - // 1333-74-0 0.5 0 1 - // 100-42-5 10 8 4 - // 74-85-1 3 2 2 - // 108-88-3 9 7 4 - // 100-41-4 10.5 8 5 - // 71-43-2 7.5 6 3 - - for ( i = 0 ; i < nb ; i++ ) { - - can_burn[i] = false; - - if ( chem[i]->CAS == "64-17-5" || - chem[i]->CAS == "74-82-8" || - chem[i]->CAS == "1333-74-0" || - chem[i]->CAS == "100-42-5" || - chem[i]->CAS == "74-85-1" || - chem[i]->CAS == "108-88-3" || - chem[i]->CAS == "100-41-4" || - chem[i]->CAS == "71-43-2" ) - can_burn[i] = true; - } - - O2 = new chemical ("7782-44-7"); - N2 = new chemical ("7727-37-9"); - CO2 = new chemical ("124-38-9"); - H2O = new chemical ("7732-18-5"); - - // Construct the rx array; - rx = new combrx * [nb]; - for ( i = 0 ; i < nb ; i++ ) { - if ( can_burn[i] ) - rx[i] = new combrx ( chem[i]->CAS ); - else - rx[i] = NULL; - } -} - -/*---------------------------------------------------------------*/ -burner::~burner ( void ) { - - delete [] m; - delete [] can_burn; - - for ( i = 0 ; i < rem_nb ; i++ ) - if (rx[i]) - delete rx[i]; - delete [] rx; - - delete O2; - delete N2; - delete CO2; - delete H2O; -} - -/*---------------------------------------------------------------*/ -bool burner::solve(double * y) -{ - OK=true; - //perform mass balance (neglect pollutants flows) - out->m = 0.0; - for(i=0;i<in->nb;i++) - { - if (!can_burn[i]) { - out->chem[i]->m = in->chem[i]->m; - out->m+=out->chem[i]->m; - } - else { - out->chem[i]->m=0.0; - O2->m+=rx[i]->O2_flow()*in->chem[i]->n(); - N2->m+=rx[i]->N2_flow()*in->chem[i]->n(); - CO2->m+=rx[i]->CO2_flow()*in->chem[i]->n(); - H2O->m+=rx[i]->H2O_flow()*in->chem[i]->n(); - } - } - N2->m*=(1.0+eta); - O2->m*=(1.0+eta); - //perform energy balance to find Tout - T = in->T; - - step=10; - Q=1; - // find temperature - while (fabs(step)>TOL_BURN && fabs(Q)>TOL_BURN && T<MAX_TEMP) - { - T+=step; - - if(T>MAX_TEMP) - T=MAX_TEMP; - Q = 0.0; - for ( i = 0 ; i < in->nb ; i++ ) - Q += in->chem[i]->dH ( in->T , T , in->P ) * in->chem[i]->n(); - - for ( i = 0 ; i < in->nb ; i++ ) - if ( can_burn[i] ) - Q += rx[i]->Hcomb(T) * in->chem[i]->n(); - - Q += O2->dH ( 293 , T , in->P ) * O2->n(); - Q += N2->dH ( 293 , T , in->P ) * N2->n(); - - - if (step/fabs(step)*Q >0) - step*= -0.1; - else if (fabs(Q)<10) - step*=0.25; - - } - - - - out->set_thermo(in->thermo); - // out->thermo = in->thermo; - - out->set(in->P, T); - O2->P=in->P; O2->T=T; O2->state=1; O2->find_v(); - N2->P=in->P; N2->T=T; N2->state=1; N2->find_v(); - CO2->P=in->P; CO2->T=T; CO2->state=1; CO2->find_v(); - H2O->P=in->P; H2O->T=T; H2O->state=1; H2O->find_v(); - //check if mixture can burn - m_can_burn = 0.0; - for(i=0;i<in->nb;i++) if(can_burn[i]) m_can_burn+=in->chem[i]->n(); - LFLmix=0.0; - for(i=0;i<in->nb;i++) if(can_burn[i]) LFLmix+=in->chem[i]->n()/m_can_burn*rx[i]->LFL(in->P,T); - UFLmix=0.0; - for(i=0;i<in->nb;i++) if(can_burn[i]) UFLmix+=in->chem[i]->n()/m_can_burn*rx[i]->UFL(in->P,T); - num = 0.0; - buff=in->T; in->set(in->P, T); - for(i=0;i<in->nb;i++) if(can_burn[i]) num+=in->chem[i]->n()/in->n()*in->v; - in->set(in->P, buff); - den = O2->v+N2->v+out->v; - composition = num/den; - if(!(LFLmix<=composition && composition<=UFLmix) || T==MAX_TEMP) - { -// logf.open(MESSAGES,ios::app); -// logf<<" --> Warning <-- Mixture in "<<name<<" can't burn (LFL="<<LFLmix -// <<" UFL="<<UFLmix<<" x="<<composition<<").\n"; -// logf.close(); - T=in->T; - filename = out->name; - *out=*in; - out->set(filename); - // out->write(); // WRITE TOTO - OK=false; - } - else - { - O2->P=in->P; O2->T=T; O2->state=1; O2->find_v(); - N2->P=in->P; N2->T=T; N2->state=1; N2->find_v(); - // out->write(); // WRITE TOTO - } - if(OK) //compute the pollutants production - { - fill_K_array(); - NO = 1e6*sqrt(K[0]*(N2->n()/den)*(O2->n()/den))*den*0.03/(O2->m+N2->m+out->m+H2O->m+CO2->m); - N2O = 1e6*K[1]*(N2->n()/den)*sqrt(O2->n()/den)*den*0.044/(O2->m+N2->m+out->m+H2O->m+CO2->m); - NO2 = 1e6*K[2]*sqrt(N2->n()/den)*(O2->n()/den)*den*0.046/(O2->m+N2->m+out->m+H2O->m+CO2->m); - CO = 1e6*K[3]*(CO2->n()/den)*den/sqrt(O2->n()/den)*0.028/(O2->m+N2->m+out->m+H2O->m+CO2->m); - } -// logf.open(MESSAGES,ios::app); - if (NO>EPS && NO2>EPS && N2O>EPS) { - // logf<<" --> Warning <-- Presence of NOx: "<<(NO+NO2+N2O)<<" ppm in "<<name<<".\n"; - y[7] = NO+NO2+N2O; - - if (ARRONDI) - y[7] = arrondi ( y[7] , 6 ); - - } - if (CO>EPS) { - // logf<<" --> Warning <-- Presence of CO: "<<CO<<" ppm in "<<name<<".\n"; - y[8] = CO; - if (ARRONDI) - y[8] = arrondi ( y[8] , 6 ); - - } -// logf.close(); - return OK; -} - -void burner::fill_K_array() -{ - a[0]=1.0; a[1]=1.0; a[2]=0.5; a[3]=1.0; - b[0]=1.0; b[1]=0.5; b[2]=1.0; b[3]=-0.5; - c[0]=2.0; c[1]=1.0; c[2]=1.0; c[3]=1.0; - K[0] = exp(-120.27*(173.38-T*0.012)/T); - K[1] = exp(-120.27*(103.64+T*0.074)/T); - K[2] = exp(-120.27*(51.96+T*0.061)/T); - K[3] = exp(-120.27*(283.84-T*0.087)/T); - for(i=0;i<4;i++) - K[i]*=pow(1000, c[i]-a[i]-b[i]); -} - -void burner::write() { - - cout << setprecision(6); - - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout << "\t>> " << name; - cout << endl << "\t>> stream in : " << in->name; - cout << endl << "\t>> streams out : " << out->name; - cout << endl << "\t>> P = " << in->P << " atm, T(in) = " << in->T - << " T(out) = " << T << " K"; - O2->P = 1; - O2->T = 293; - O2->state = 1; - O2->find_v(); - N2->P=1; - N2->T=293; - N2->state=1; - N2->find_v(); - cout << endl << "\t>> Required air flow = " - << (O2->m+N2->m) << " kg/s (" << (O2->v+N2->v) << " m3/s)"; - O2->P=in->P; - O2->T=T; - O2->state=1; - O2->find_v(); - N2->P=in->P; - N2->T=T; - N2->state=1; - N2->find_v(); - step=(eta*O2->v/(1+eta)+N2->v+H2O->v+CO2->v+out->v); - cout << endl << "\t>> Total flue gases = " - << (out->m+CO2->m+H2O->m+N2->m+eta*O2->m/(1+eta)) - <<" kg/s (" << step << " m3/s)"; - cout << "\n\tEND\n\n"; - cost(); -} - - -double burner::get_cost ( void ) { - - - O2->P = 1; - O2->T = 293; - O2->state = 1; - O2->find_v(); - N2->P=1; - N2->T=293; - N2->state=1; - N2->find_v(); - O2->P=in->P; - O2->T=T; - O2->state=1; - O2->find_v(); - N2->P=in->P; - N2->T=T; - N2->state=1; - N2->find_v(); - step=(eta*O2->v/(1+eta)+N2->v+H2O->v+CO2->v+out->v); - - buff = 3.1761-0.1373*log10(step) + 0.3414*pow(log10(step),2); - buff = 2.7*pow(10, buff); - buff = buff*MS_YEAR/MS_2001; - - return buff; -} - - -void burner::cost ( void ) { - cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} +#include "burner.hpp" +using namespace std; + +/*----------------------------------------------------------*/ +/* arrondi pour ne conserver que n chiffres significatifs */ +/*----------------------------------------------------------*/ +double arrondi ( double x , int n ) { + if (fabs(x) < EPS) + return 0.0; + double m = pow ( 10 , ceil(-log10(x)) + n - 1 ); + return round(m*x)/m; +} + +/*---------------------------------------------------------------*/ +burner::burner ( int nb , chemical ** chem ) { + + rem_nb = nb; + + NO=NO2=N2O=CO=0.0; + m = new double[nb]; + can_burn = new bool[nb]; + + // combustion.prop : + // ----------------- + // 64-17-5 3 2 3 + // 74-82-8 2 1 2 + // 1333-74-0 0.5 0 1 + // 100-42-5 10 8 4 + // 74-85-1 3 2 2 + // 108-88-3 9 7 4 + // 100-41-4 10.5 8 5 + // 71-43-2 7.5 6 3 + + for ( i = 0 ; i < nb ; i++ ) { + + can_burn[i] = false; + + if ( chem[i]->CAS == "64-17-5" || + chem[i]->CAS == "74-82-8" || + chem[i]->CAS == "1333-74-0" || + chem[i]->CAS == "100-42-5" || + chem[i]->CAS == "74-85-1" || + chem[i]->CAS == "108-88-3" || + chem[i]->CAS == "100-41-4" || + chem[i]->CAS == "71-43-2" ) + can_burn[i] = true; + } + + O2 = new chemical ("7782-44-7"); + N2 = new chemical ("7727-37-9"); + CO2 = new chemical ("124-38-9"); + H2O = new chemical ("7732-18-5"); + + // Construct the rx array; + rx = new combrx * [nb]; + for ( i = 0 ; i < nb ; i++ ) { + if ( can_burn[i] ) + rx[i] = new combrx ( chem[i]->CAS ); + else + rx[i] = NULL; + } +} + +/*---------------------------------------------------------------*/ +burner::~burner ( void ) { + + delete [] m; + delete [] can_burn; + + for ( i = 0 ; i < rem_nb ; i++ ) + if (rx[i]) + delete rx[i]; + delete [] rx; + + delete O2; + delete N2; + delete CO2; + delete H2O; +} + +/*---------------------------------------------------------------*/ +bool burner::solve(double * y) +{ + OK=true; + //perform mass balance (neglect pollutants flows) + out->m = 0.0; + for(i=0;i<in->nb;i++) + { + if (!can_burn[i]) { + out->chem[i]->m = in->chem[i]->m; + out->m+=out->chem[i]->m; + } + else { + out->chem[i]->m=0.0; + O2->m+=rx[i]->O2_flow()*in->chem[i]->n(); + N2->m+=rx[i]->N2_flow()*in->chem[i]->n(); + CO2->m+=rx[i]->CO2_flow()*in->chem[i]->n(); + H2O->m+=rx[i]->H2O_flow()*in->chem[i]->n(); + } + } + N2->m*=(1.0+eta); + O2->m*=(1.0+eta); + //perform energy balance to find Tout + T = in->T; + + step=10; + Q=1; + // find temperature + while (fabs(step)>TOL_BURN && fabs(Q)>TOL_BURN && T<MAX_TEMP) + { + T+=step; + + if(T>MAX_TEMP) + T=MAX_TEMP; + Q = 0.0; + for ( i = 0 ; i < in->nb ; i++ ) + Q += in->chem[i]->dH ( in->T , T , in->P ) * in->chem[i]->n(); + + for ( i = 0 ; i < in->nb ; i++ ) + if ( can_burn[i] ) + Q += rx[i]->Hcomb(T) * in->chem[i]->n(); + + Q += O2->dH ( 293 , T , in->P ) * O2->n(); + Q += N2->dH ( 293 , T , in->P ) * N2->n(); + + + if (step/fabs(step)*Q >0) + step*= -0.1; + else if (fabs(Q)<10) + step*=0.25; + + } + + + + out->set_thermo(in->thermo); + // out->thermo = in->thermo; + + out->set(in->P, T); + O2->P=in->P; O2->T=T; O2->state=1; O2->find_v(); + N2->P=in->P; N2->T=T; N2->state=1; N2->find_v(); + CO2->P=in->P; CO2->T=T; CO2->state=1; CO2->find_v(); + H2O->P=in->P; H2O->T=T; H2O->state=1; H2O->find_v(); + //check if mixture can burn + m_can_burn = 0.0; + for(i=0;i<in->nb;i++) if(can_burn[i]) m_can_burn+=in->chem[i]->n(); + LFLmix=0.0; + for(i=0;i<in->nb;i++) if(can_burn[i]) LFLmix+=in->chem[i]->n()/m_can_burn*rx[i]->LFL(in->P,T); + UFLmix=0.0; + for(i=0;i<in->nb;i++) if(can_burn[i]) UFLmix+=in->chem[i]->n()/m_can_burn*rx[i]->UFL(in->P,T); + num = 0.0; + buff=in->T; in->set(in->P, T); + for(i=0;i<in->nb;i++) if(can_burn[i]) num+=in->chem[i]->n()/in->n()*in->v; + in->set(in->P, buff); + den = O2->v+N2->v+out->v; + composition = num/den; + if(!(LFLmix<=composition && composition<=UFLmix) || T==MAX_TEMP) + { +// logf.open(MESSAGES,ios::app); +// logf<<" --> Warning <-- Mixture in "<<name<<" can't burn (LFL="<<LFLmix +// <<" UFL="<<UFLmix<<" x="<<composition<<").\n"; +// logf.close(); + T=in->T; + filename = out->name; + *out=*in; + out->set(filename); + // out->write(); // WRITE TOTO + OK=false; + } + else + { + O2->P=in->P; O2->T=T; O2->state=1; O2->find_v(); + N2->P=in->P; N2->T=T; N2->state=1; N2->find_v(); + // out->write(); // WRITE TOTO + } + if(OK) //compute the pollutants production + { + fill_K_array(); + NO = 1e6*sqrt(K[0]*(N2->n()/den)*(O2->n()/den))*den*0.03/(O2->m+N2->m+out->m+H2O->m+CO2->m); + N2O = 1e6*K[1]*(N2->n()/den)*sqrt(O2->n()/den)*den*0.044/(O2->m+N2->m+out->m+H2O->m+CO2->m); + NO2 = 1e6*K[2]*sqrt(N2->n()/den)*(O2->n()/den)*den*0.046/(O2->m+N2->m+out->m+H2O->m+CO2->m); + CO = 1e6*K[3]*(CO2->n()/den)*den/sqrt(O2->n()/den)*0.028/(O2->m+N2->m+out->m+H2O->m+CO2->m); + } +// logf.open(MESSAGES,ios::app); + if (NO>EPS && NO2>EPS && N2O>EPS) { + // logf<<" --> Warning <-- Presence of NOx: "<<(NO+NO2+N2O)<<" ppm in "<<name<<".\n"; + y[7] = NO+NO2+N2O; + + if (ARRONDI) + y[7] = arrondi ( y[7] , 6 ); + + } + if (CO>EPS) { + // logf<<" --> Warning <-- Presence of CO: "<<CO<<" ppm in "<<name<<".\n"; + y[8] = CO; + if (ARRONDI) + y[8] = arrondi ( y[8] , 6 ); + + } +// logf.close(); + return OK; +} + +void burner::fill_K_array() +{ + a[0]=1.0; a[1]=1.0; a[2]=0.5; a[3]=1.0; + b[0]=1.0; b[1]=0.5; b[2]=1.0; b[3]=-0.5; + c[0]=2.0; c[1]=1.0; c[2]=1.0; c[3]=1.0; + K[0] = exp(-120.27*(173.38-T*0.012)/T); + K[1] = exp(-120.27*(103.64+T*0.074)/T); + K[2] = exp(-120.27*(51.96+T*0.061)/T); + K[3] = exp(-120.27*(283.84-T*0.087)/T); + for(i=0;i<4;i++) + K[i]*=pow(1000, c[i]-a[i]-b[i]); +} + +void burner::write() { + + cout << setprecision(6); + + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout << "\t>> " << name; + cout << endl << "\t>> stream in : " << in->name; + cout << endl << "\t>> streams out : " << out->name; + cout << endl << "\t>> P = " << in->P << " atm, T(in) = " << in->T + << " T(out) = " << T << " K"; + O2->P = 1; + O2->T = 293; + O2->state = 1; + O2->find_v(); + N2->P=1; + N2->T=293; + N2->state=1; + N2->find_v(); + cout << endl << "\t>> Required air flow = " + << (O2->m+N2->m) << " kg/s (" << (O2->v+N2->v) << " m3/s)"; + O2->P=in->P; + O2->T=T; + O2->state=1; + O2->find_v(); + N2->P=in->P; + N2->T=T; + N2->state=1; + N2->find_v(); + step=(eta*O2->v/(1+eta)+N2->v+H2O->v+CO2->v+out->v); + cout << endl << "\t>> Total flue gases = " + << (out->m+CO2->m+H2O->m+N2->m+eta*O2->m/(1+eta)) + <<" kg/s (" << step << " m3/s)"; + cout << "\n\tEND\n\n"; + cost(); +} + + +double burner::get_cost ( void ) { + + + O2->P = 1; + O2->T = 293; + O2->state = 1; + O2->find_v(); + N2->P=1; + N2->T=293; + N2->state=1; + N2->find_v(); + O2->P=in->P; + O2->T=T; + O2->state=1; + O2->find_v(); + N2->P=in->P; + N2->T=T; + N2->state=1; + N2->find_v(); + step=(eta*O2->v/(1+eta)+N2->v+H2O->v+CO2->v+out->v); + + buff = 3.1761-0.1373*log10(step) + 0.3414*pow(log10(step),2); + buff = 2.7*pow(10, buff); + buff = buff*MS_YEAR/MS_2001; + + return buff; +} + + +void burner::cost ( void ) { + cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/burner.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/burner.hpp index 3d83403..310df0d 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/burner.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/burner.hpp @@ -1,59 +1,59 @@ -/* -This unit simulates a burner. The user must provide the air excess -and all combustion data as defined in data\\combustion.prop : - CAS nb_moles_O2 nb_moles_CO2 nb_moles_H2O -Then, mass and energy balances are performed and flows of common -combustion pollutants are estimated. -(reference : Crowl & Louvar) - -Structure in the .process file: -burner {name} {index of input stream} {index of output stream} {air excess >0 (ex.: 1.2 is a 120% excess)} - -How to use: - 1- Call the constructor: burn = new burner(in, out); burner(nb_in, chem_list) - ->set(in, out) - 2- Set the air excess : burn->set(excess); - 3- Set the name of the unit: burn->set(name); - 4- Solve: bool=burn->solve(); -*/ -#ifndef BURNER_H -#define BURNER_H -#include "stream.hpp" -#include "combrx.hpp" -using namespace std; - -class burner -{ -private: - - string filename; - int rem_nb; - stream *in, *out; - chemical *O2, *N2, *CO2, *H2O; - combrx **rx; - bool *can_burn, stop, OK; - double eta, NO, NO2, N2O, CO; - double T, LFLmix, UFLmix, composition; - string name; - double * m; - double a[4], b[4], c[4], K[4]; - int i; - double buff, Q, m_can_burn, step, num, den; - ifstream data; - // ofstream logf, results; - // terminator *end; - void fill_K_array(); - -public: - // burner(){}; - burner ( int , chemical ** ); - void set ( stream * s1 , stream * s2 ) { in=s1; out=s2; for(i=0;i<in->nb;i++) m[i] = in->chem[i]->m;} - void set ( const string & n ) { name = n; } - void set(double e) {eta = e;} - bool solve(double * y); - void write(); - void cost(); - double get_cost ( void ); - ~burner(); -}; -#endif +/* +This unit simulates a burner. The user must provide the air excess +and all combustion data as defined in data\\combustion.prop : + CAS nb_moles_O2 nb_moles_CO2 nb_moles_H2O +Then, mass and energy balances are performed and flows of common +combustion pollutants are estimated. +(reference : Crowl & Louvar) + +Structure in the .process file: +burner {name} {index of input stream} {index of output stream} {air excess >0 (ex.: 1.2 is a 120% excess)} + +How to use: + 1- Call the constructor: burn = new burner(in, out); burner(nb_in, chem_list) + ->set(in, out) + 2- Set the air excess : burn->set(excess); + 3- Set the name of the unit: burn->set(name); + 4- Solve: bool=burn->solve(); +*/ +#ifndef BURNER_H +#define BURNER_H +#include "stream.hpp" +#include "combrx.hpp" +using namespace std; + +class burner +{ +private: + + string filename; + int rem_nb; + stream *in, *out; + chemical *O2, *N2, *CO2, *H2O; + combrx **rx; + bool *can_burn, stop, OK; + double eta, NO, NO2, N2O, CO; + double T, LFLmix, UFLmix, composition; + string name; + double * m; + double a[4], b[4], c[4], K[4]; + int i; + double buff, Q, m_can_burn, step, num, den; + ifstream data; + // ofstream logf, results; + // terminator *end; + void fill_K_array(); + +public: + // burner(){}; + burner ( int , chemical ** ); + void set ( stream * s1 , stream * s2 ) { in=s1; out=s2; for(i=0;i<in->nb;i++) m[i] = in->chem[i]->m;} + void set ( const string & n ) { name = n; } + void set(double e) {eta = e;} + bool solve(double * y); + void write(); + void cost(); + double get_cost ( void ); + ~burner(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/cashflow.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/cashflow.cpp index c7174f6..a35a767 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/cashflow.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/cashflow.cpp @@ -1,114 +1,114 @@ -#include "cashflow.hpp" -using namespace std; - -cashflow::cashflow(int n) -{ - N=n+1; - Inv = new double[N]; - Coper = new double[N]; - Amort = new double[N]; - Rev = new double[N]; - Flow = new double[N]; - Flowact = new double[N]; - Itot=Ctot=Rtot=i_rate=a_rate=0.0; - - - yield_tab[ 0] = 0.515; - yield_tab[ 1] = 0.778; - yield_tab[ 2] = 0.812; - yield_tab[ 3] = 0.893; - yield_tab[ 4] = 0.985; - yield_tab[ 5] = 0.837; - yield_tab[ 6] = 0.849; - yield_tab[ 7] = 0.746; - yield_tab[ 8] = 0.812; - yield_tab[ 9] = 0.954; - yield_tab[10] = 0.999; - yield_tab[11] = 0.961; - yield_tab[12] = 0.815; - yield_tab[13] = 0.886; - yield_tab[14] = 0.922; - -} - -cashflow::~cashflow ( void ) { - delete [] Inv; - delete [] Coper; - delete [] Amort; - delete [] Rev; - delete [] Flow; - delete [] Flowact; -} - -bool cashflow::run() -{ - if(Itot<EPS || Ctot<EPS || Rtot<EPS || i_rate<EPS || a_rate<EPS) - OK=false; - else - { - //if(!MUTE)cout<<endl<<" investments flow... OK"; - set_Inv(); - //if(!MUTE)cout<<endl<<" depreciation flow... OK"; - set_Amort(); - set_C_R(); - //if(!MUTE)cout<<endl<<" costs flow... OK"; - //if(!MUTE)cout<<endl<<" revenus flow... OK"; - for(i=0;i<N;i++) - { - Flow[i] = (Rev[i]-Coper[i])*(1.0-a_rate)-(Inv[i]-a_rate*Amort[i]); - Flowact[i] = Flow[i]/pow(1.0+i_rate, i); - } - //if(!MUTE)cout<<endl<<" cash flow... OK"; - //if(!MUTE)cout<<endl<<" actualizing cash flow... OK"; - OK=true; - -// cout<<endl<<endl<<" CASH FLOW DETAILS"<<endl; -// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; -// cout<<endl<<" "<<" i "<<" Investment "<<" Deprec. " -// <<" Expenses "<<" Revenus "<<" Cash flow "<<" Act. flow "; -// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; -// cout<<setfill(' ')<<setiosflags(ios::fixed)<<setprecision(0); -// for(i=0;i<N;i++) -// cout<<endl -// <<" "<<setw(2)<<i<<" "<<setw(11) -// <<Inv[i]<<" "<<setw(11)<<Amort[i]<<" " -// <<setw(11)<<Coper[i]<<" "<<setw(11)<<Rev[i]<<" "<<setw(11)<<Flow[i]<<" "<<setw(11)<<Flowact[i]; -// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; - } - return OK; -} - -void cashflow::set_Amort() -{ - Amort[0] = 0.0; - temp=Itot; - for(i=1;i<N-1;i++) - { - temp+=Inv[i]; - Amort[i] = temp/double(N-i); - temp-=Amort[i]; - } - Amort[N-1]=Amort[N-2]; -} - -void cashflow::set_Inv() -{ - Inv[0] = Itot; - for(i=1;i<N-1;i++) - { - if((i)%5==0) Inv[i]=0.1*Itot; - else Inv[i]=0.0; - } - Inv[N-1]=0.0; - for(i=0;i<N-1;i++) Inv[N-1]-=0.1*Inv[i]; -} - -void cashflow::set_C_R() -{ - Coper[0] = Rev[0] = 0.0; - for(i=1;i<N;i++) - { - Coper[i] = yield(i)*Ctot; - Rev[i] = yield(i)*Rtot; - } -} +#include "cashflow.hpp" +using namespace std; + +cashflow::cashflow(int n) +{ + N=n+1; + Inv = new double[N]; + Coper = new double[N]; + Amort = new double[N]; + Rev = new double[N]; + Flow = new double[N]; + Flowact = new double[N]; + Itot=Ctot=Rtot=i_rate=a_rate=0.0; + + + yield_tab[ 0] = 0.515; + yield_tab[ 1] = 0.778; + yield_tab[ 2] = 0.812; + yield_tab[ 3] = 0.893; + yield_tab[ 4] = 0.985; + yield_tab[ 5] = 0.837; + yield_tab[ 6] = 0.849; + yield_tab[ 7] = 0.746; + yield_tab[ 8] = 0.812; + yield_tab[ 9] = 0.954; + yield_tab[10] = 0.999; + yield_tab[11] = 0.961; + yield_tab[12] = 0.815; + yield_tab[13] = 0.886; + yield_tab[14] = 0.922; + +} + +cashflow::~cashflow ( void ) { + delete [] Inv; + delete [] Coper; + delete [] Amort; + delete [] Rev; + delete [] Flow; + delete [] Flowact; +} + +bool cashflow::run() +{ + if(Itot<EPS || Ctot<EPS || Rtot<EPS || i_rate<EPS || a_rate<EPS) + OK=false; + else + { + //if(!MUTE)cout<<endl<<" investments flow... OK"; + set_Inv(); + //if(!MUTE)cout<<endl<<" depreciation flow... OK"; + set_Amort(); + set_C_R(); + //if(!MUTE)cout<<endl<<" costs flow... OK"; + //if(!MUTE)cout<<endl<<" revenus flow... OK"; + for(i=0;i<N;i++) + { + Flow[i] = (Rev[i]-Coper[i])*(1.0-a_rate)-(Inv[i]-a_rate*Amort[i]); + Flowact[i] = Flow[i]/pow(1.0+i_rate, i); + } + //if(!MUTE)cout<<endl<<" cash flow... OK"; + //if(!MUTE)cout<<endl<<" actualizing cash flow... OK"; + OK=true; + +// cout<<endl<<endl<<" CASH FLOW DETAILS"<<endl; +// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; +// cout<<endl<<" "<<" i "<<" Investment "<<" Deprec. " +// <<" Expenses "<<" Revenus "<<" Cash flow "<<" Act. flow "; +// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; +// cout<<setfill(' ')<<setiosflags(ios::fixed)<<setprecision(0); +// for(i=0;i<N;i++) +// cout<<endl +// <<" "<<setw(2)<<i<<" "<<setw(11) +// <<Inv[i]<<" "<<setw(11)<<Amort[i]<<" " +// <<setw(11)<<Coper[i]<<" "<<setw(11)<<Rev[i]<<" "<<setw(11)<<Flow[i]<<" "<<setw(11)<<Flowact[i]; +// cout<<endl<<" "<<setfill('-')<<setw(76)<<" "; + } + return OK; +} + +void cashflow::set_Amort() +{ + Amort[0] = 0.0; + temp=Itot; + for(i=1;i<N-1;i++) + { + temp+=Inv[i]; + Amort[i] = temp/double(N-i); + temp-=Amort[i]; + } + Amort[N-1]=Amort[N-2]; +} + +void cashflow::set_Inv() +{ + Inv[0] = Itot; + for(i=1;i<N-1;i++) + { + if((i)%5==0) Inv[i]=0.1*Itot; + else Inv[i]=0.0; + } + Inv[N-1]=0.0; + for(i=0;i<N-1;i++) Inv[N-1]-=0.1*Inv[i]; +} + +void cashflow::set_C_R() +{ + Coper[0] = Rev[0] = 0.0; + for(i=1;i<N;i++) + { + Coper[i] = yield(i)*Ctot; + Rev[i] = yield(i)*Rtot; + } +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/cashflow.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/cashflow.hpp index a71b7ab..5aa5f70 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/cashflow.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/cashflow.hpp @@ -1,33 +1,33 @@ -#ifndef CASHFLOW_H -#define CASHFLOW_H -#include "defines.hpp" -// #include <iomanip> -using namespace std; - -class cashflow -{ - private: - // char name[31], filename[41]; - // ifstream in; - // ofstream out; - double Itot, Ctot, Rtot; - void set_Inv(), set_Amort(), set_C_R(); - double temp; - int i, j, counter; - bool OK; - double yield_tab[15]; - - double yield ( int k ) const { return yield_tab[(k==15) ? 14 : k%15]; } - -public: - double *Inv, *Coper, *Amort, *Rev, *Flow, *Flowact; - double i_rate, a_rate; - int N; - cashflow(int); - ~cashflow(); - // void set(char n[31]) {strcpy(name, n);} - void set_rates(double d1, double d2){i_rate=d1; a_rate=d2;} - void set_basics(double d1, double d2, double d3){Itot=d1; Ctot=d2; Rtot=d3;} - bool run(); -}; -#endif +#ifndef CASHFLOW_H +#define CASHFLOW_H +#include "defines.hpp" +// #include <iomanip> +using namespace std; + +class cashflow +{ + private: + // char name[31], filename[41]; + // ifstream in; + // ofstream out; + double Itot, Ctot, Rtot; + void set_Inv(), set_Amort(), set_C_R(); + double temp; + int i, j, counter; + bool OK; + double yield_tab[15]; + + double yield ( int k ) const { return yield_tab[(k==15) ? 14 : k%15]; } + +public: + double *Inv, *Coper, *Amort, *Rev, *Flow, *Flowact; + double i_rate, a_rate; + int N; + cashflow(int); + ~cashflow(); + // void set(char n[31]) {strcpy(name, n);} + void set_rates(double d1, double d2){i_rate=d1; a_rate=d2;} + void set_basics(double d1, double d2, double d3){Itot=d1; Ctot=d2; Rtot=d3;} + bool run(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/chemical.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/chemical.cpp index af4d12a..2fb1052 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/chemical.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/chemical.cpp @@ -1,529 +1,529 @@ -#include "chemical.hpp" -using namespace std; - -void chemical::check_error ( void ) { - if (error>MAX_ERROR) { - cout << "ERROR 2\n\n"; - exit(0); - } - if (warning>MAX_WARNING) { - cout << "ERROR 3\n\n"; - exit(0); - } -} - -// copy-constr. : -chemical::chemical ( const chemical & chem ) { - - CAS = chem.CAS; - name = chem.name; - M = chem.M; - - state = chem.state; - Tm = chem.Tm; - Tb = chem.Tb; - Tc = chem.Tc; - Pc = chem.Pc; - Ho = chem.Ho; - rho_liq = chem.rho_liq; - dHvap = chem.dHvap; - - mu_param[0] = chem.mu_param[0]; - mu_param[1] = chem.mu_param[1]; - Cp_param[0] = chem.Cp_param[0]; - Cp_param[1] = chem.Cp_param[1]; - Cp_param[2] = chem.Cp_param[2]; - Cp_param[3] = chem.Cp_param[3]; - Cp_liq = chem.Cp_liq; - Psat_param[0] = chem.Psat_param[0]; - Psat_param[1] = chem.Psat_param[1]; - Psat_param[2] = chem.Psat_param[2]; - - thermo = new thermolib(); - thermo->send(Pc,Tc, omega()); - - P = chem.P; - T = chem.T; - m = chem.m; - v = chem.v; - - warning = chem.warning; - error = chem.error; - tmp = chem.tmp; -} - -chemical::chemical ( const string & chem_name ) { - - CAS = chem_name; - - // C. Tribes add initialization for more robustness (variables may be initialized uncorrectly dependent on the execution) - P=T=m=v=0.0; - - // 1/12 : - if (CAS=="100-41-4") { - name = "ethylbenzene"; - M = 106.17; - state = 0; - Tm = 178.2; - Tb = 409.3; - Tc = 617.1; - Pc = 35.6; - Ho = 29.79; - rho_liq = 867.0; - dHvap = 35.56; - mu_param[0] = 472.82; - mu_param[1] = 264.22; - Cp_param[0] = -43.069; - Cp_param[1] = 7.067e-01; - Cp_param[2] = -4.807e-04; - Cp_param[3] = 1.30e-07; - Cp_liq = 190.23; - Psat_param[0] = 16.0195; - Psat_param[1] = 3279.47; - Psat_param[2] = -59.95; - } - - // 2/12 : - else if (CAS=="1333-74-0") { - name = "hydrogen"; - M = 2.02; - state = 1; - Tm = 14.0; - Tb = 20.4; - Tc = 33.2; - Pc = 12.8; - Ho = 0.0; - rho_liq = 71.0; - dHvap = 0.9; - mu_param[0] = 13.82; - mu_param[1] = 5.39; - Cp_param[0] = 27.124; - Cp_param[1] = 9.267e-03; - Cp_param[2] = -1.380e-05; - Cp_param[3] = 7.64e-09; - Cp_liq = 0.0; - Psat_param[0] = 13.6333; - Psat_param[1] = 164.90; - Psat_param[2] = 3.19; - } - - // 3/12 : - else if (CAS=="108-88-3") { - name = "toluene"; - M =92.14; - state = 0; - Tm = 178.0; - Tb = 383.8; - Tc = 591.7; - Pc = 40.6; - Ho = 50.0; - rho_liq = 867; - dHvap = 33.18; - mu_param[0] = 467.33; - mu_param[1] = 255.24; - Cp_param[0] = -24.338; - Cp_param[1] = 5.121e-1; - Cp_param[2] = -2.763e-4; - Cp_param[3] = 4.91e-8; - Cp_liq = 159.85; - Psat_param[0] = 16.0137; - Psat_param[1] = 3096.52; - Psat_param[2] = -53.67; - } - - // 4/12 : - else if (CAS=="74-82-8") { - name = "methane"; - M =16.04; - state =1; - Tm = 90.7; - Tb = 111.7; - Tc = 190.6; - Pc = 45.4; - Ho = -74.85; - rho_liq = 425; - dHvap = 8.18; - mu_param[0] = 114.14; - mu_param[1] = 57.60; - Cp_param[0] = 19.238; - Cp_param[1] = 5.209e-02; - Cp_param[2] = 1.197e-05; - Cp_param[3] = -1.13e-08; - Cp_liq = 0.0; - Psat_param[0] = 15.2243; - Psat_param[1] = 897.84; - Psat_param[2] = -7.16; - } - - // 5/12 : - else if (CAS=="71-43-2") { - name = "benzene"; - M = 78.11; - state = 0; - Tm = 278.7; - Tb = 353.3; - Tc = 562.1; - Pc = 48.3; - Ho = 82.93; - rho_liq = 885; - dHvap = 30.76; - mu_param[0] = 545.64; - mu_param[1] = 265.24; - Cp_param[0] = 33.894; - Cp_param[1] = 4.74e-1; - Cp_param[2] = -3.015e-4; - Cp_param[3] = 7.13e-8; - Cp_liq = 116.03; - Psat_param[0] = 15.9008; - Psat_param[1] = 2788.51; - Psat_param[2] = -52.36; - } - - // 6/12 : - else if (CAS=="74-85-1") { - name = "ethylene"; - M = 28.05; - state =1; - Tm = 104.0; - Tb = 169.4; - Tc = 282.4; - Pc = 49.7; - Ho =52.3; - rho_liq = 577.0; - dHvap = 13.54; - mu_param[0] = 168.98; - mu_param[1] = 93.94; - Cp_param[0] = 3.803; - Cp_param[1] = 1.565e-01; - Cp_param[2] = -8.343e-05; - Cp_param[3] = 1.75e-08; - Cp_liq = 0.0; - Psat_param[0] =15.5368; - Psat_param[1] = 1347.01; - Psat_param[2] = -18.15; - } - - // 7/12 : - else if (CAS=="100-42-5") { - name = "styrene"; - M =104.15; - state = 0; - Tm = 242.5; - Tb = 418.3; - Tc =647.0; - Pc =39.4; - Ho =147.36; - rho_liq =906.0; - dHvap = 36.82; - mu_param[0] = 528.64; - mu_param[1] = 276.71; - Cp_param[0] =-28.229; - Cp_param[1] =6.155e-01; - Cp_param[2] = -4.020e-04; - Cp_param[3] = 9.93e-08; - Cp_liq =166.13; - Psat_param[0] = 16.0193; - Psat_param[1] = 3328.57; - Psat_param[2] =-63.72; - } - - // 8/12 : - else if (CAS=="7782-44-7") { - name = "oxygen"; - M = 32.00; - state = 1; - Tm = 54.4; - Tb = 90.2; - Tc = 154.6; - Pc = 49.8; - Ho =0.0 ; - rho_liq =1149.1 ; - dHvap =6.82 ; - mu_param[0] = 85.68; - mu_param[1] = 51.50; - Cp_param[0] = 28.087; - Cp_param[1] = -3.678e-06 ; - Cp_param[2] = 1.745e-05; - Cp_param[3] = -1.06e-08; - Cp_liq =0.0 ; - Psat_param[0] = 15.4075; - Psat_param[1] = 734.55 ; - Psat_param[2] =-6.45 ; - } - - // 9/12 : - else if (CAS=="7727-37-9") { - name = "nitrogen"; - M = 28.01; - state = 1; - Tm = 63.3; - Tb = 77.4; - Tc = 126.2; - Pc = 33.5; - Ho = 0.0; - rho_liq = 804.0; - dHvap = 5.58; - mu_param[0] = 90.30; - mu_param[1] = 46.41; - Cp_param[0] = 31.128; - Cp_param[1] = -1.356e-02 ; - Cp_param[2] = 2.678e-05; - Cp_param[3] =-1.17e-08 ; - Cp_liq = 0.0; - Psat_param[0] = 14.9342; - Psat_param[1] = 588.72; - Psat_param[2] = -6.60; - } - - // 10/12 : - else if (CAS=="124-38-9") { - name = "carbon-dioxide"; - M =44.01; - state = 1; - Tm = 216.6; - Tb = 194.4; - Tc = 304.2; - Pc = 72.8; - Ho = -393.41; - rho_liq = 777.0; - dHvap = 17.15; - mu_param[0] = 578.08; - mu_param[1] = 185.24 ; - Cp_param[0] = 19.782; - Cp_param[1] = 7.339e-02; - Cp_param[2] = -5.598e-05; - Cp_param[3] = 1.71e-08; - Cp_liq = 0.0; - Psat_param[0] = 22.5898; - Psat_param[1] =3103.39 ; - Psat_param[2] = -0.16; - } - - // 11/12 : - else if (CAS=="7732-18-5") { - name = "water"; - M =18.02; - state = 0; - Tm = 273.15; - Tb = 373.15; - Tc = 647.4; - Pc = 217.6; - Ho = -241.83; - rho_liq = 998 ; - dHvap = 40.66; - mu_param[0] = 658.25; - mu_param[1] = 283.16; - Cp_param[0] = 32.220; - Cp_param[1] = 1.923e-03 ; - Cp_param[2] = 1.055e-05; - Cp_param[3] = -3.59e-09; - Cp_liq = 75.24; - Psat_param[0] = 18.3036; - Psat_param[1] = 3816.44; - Psat_param[2] = -46.13; - } - - // 12/12 : - else if (CAS=="64-17-5") { - name = "ethanol"; - M =46.07; - state =0 ; - Tm =159.1 ; - Tb = 351.5; - Tc = 516.2; - Pc =63.0 ; - Ho = -234.8; - rho_liq = 789.0; - dHvap =38.74 ; - mu_param[0] = 686.64; - mu_param[1] = 300.88; - Cp_param[0] = 9.008; - Cp_param[1] = 2.139e-01; - Cp_param[2] = -8.385e-05 ; - Cp_param[3] = 1.37e-09; - Cp_liq = 2.22; - Psat_param[0] = 18.9119; - Psat_param[1] = 3803.98; - Psat_param[2] = -41.68; - } - - else { - cout << "ERROR 1\n\n"; - exit(0); - } - - thermo = new thermolib(); - thermo->send(Pc,Tc, omega()); - - -} - -double chemical::K() -{ - thermo->set(P,T,v,n()); - return thermo->K(); -} - -double chemical::mu() -{ - // Returns the fluid's viscosity in Pa.s - if (Tm<=T && T<=Tboil(P)) - return pow(10,(mu_param[0]*(1.0/T-1.0/mu_param[1])-3)); - else - { - ofstream logf; - logf.open(MESSAGES, ios::app); - logf<<" --> Warning <-- Cannot compute viscosity of "<<name<<".\n"; - logf.close(); - warning++; - check_error(); - return 1.0; - } -} - -double chemical::rho() -{ - // Returns the fluid's density in kg/m3, wether it's liquid or gas - if(state==0) tmp= rho_liq; - if(state==1) - { - find_v(); - if (v>EPS) tmp= m/v; - else tmp= 0.0; - } - return tmp; -} - -double chemical::Cp() { - // cout<<endl<<"Cp de "<<name<<" a "<<T; - // Returns the fluid's Cp in J/mol.K - if(state==0) { - - // tmp = Cp_liq; // BUG : boucle infinie !!! - return Cp_liq; // SEB - - } - if(state==1 || T>Tboil(P)) { - tmp=0; - for (int i=0;i<4;i++) - tmp+=Cp_param[i]*pow(T,i); - } - else { - T=Tb; - - tmp = Cp(); // ici boucle infinie si state==0 !!! - - } - return tmp; -} - -double chemical::Cp(bool q) -{ - // Returns the fluid's Cp in J/mol.K - if(q==0) tmp=Cp_liq; - if(q==1) - { - tmp=0; - for (int i=0;i<4;i++) tmp+=Cp_param[i]*pow(T,i); - } - return tmp; -} - -double chemical::Psat() -{ - // Returns the fluid's vapor pressure in atm, using Antoine's equation - if(Tm<=T && T<=Tc) - return (exp(Psat_param[0]-Psat_param[1]/(T+Psat_param[2]))/760.01); - else - { - - return Psat(Tb); - } -} -double chemical::Psat(double t) -{ - // Returns the fluid's vapor pressure in atm, using Antoine's equation - return (exp(Psat_param[0]-Psat_param[1]/(t+Psat_param[2]))/760.01); -} - -double chemical::dH(double T1,double T2, double pres) -{ - //Enthalpy variation in kJ/mol. Does not affect any attributes of current object. - double energy=0, TT=Tboil(pres), vap=Hvap(TT); - int sign=1, i; - if (T2<T1) {sign = -1; energy=T1; T1=T2; T2=energy; energy=0;} - if (T1==T2) energy = 0.0; - if (T2<TT) energy = Cp_liq*(T2-T1)/1000; - if (TT<T1) for (i=1;i<=4;i++) energy+=Cp_param[i-1]*(pow(T2,i)-pow(T1,i))/i/1000; - if(T1<=TT && TT<=T2) - { - energy=Cp_liq*(TT-T1)/1000; - energy+=vap; - for (i=1;i<=4;i++) energy+=Cp_param[i-1]*(pow(T2,i)-pow(TT,i))/i/1000; - } - return energy*sign; -} - -void chemical::find_T() -{ - if(n()>EPS && P>EPS) - { - thermo->set(P,T,v,n()); - T=thermo->T(); - } - else - { - ofstream logf; - logf.open(MESSAGES, ios::app); - logf<<" --> Warning <-- Cannot find T of "<<name<<".\n"; - logf.close(); - warning++; - } - check_error(); -} - -void chemical::find_P() -{ - if(n()>EPS && T>EPS) - { - thermo->set(P,T,v,n()); - P=thermo->P(); - } - else - { - ofstream logf; - logf.open(MESSAGES, ios::app); - logf<<" --> Warning <-- Cannot find P of "<<name<<".\n"; - logf.close(); - warning++; - } - check_error(); -} - -void chemical::find_v() -{ - - if(state==0) v=m/rho_liq; - if(state==1 && P>EPS && T>EPS && m>EPS) - { - thermo->set(P,T,v,n()); - v=thermo->v(); - } -} - -void chemical::find_state() -{ - ofstream logf; - if (T>Tc || P>Pc) state = 1; //T or P is bigger than Tc or Pc - if (T<=Tm) //T is smaller than melting point - { - ofstream logf; - logf.open(MESSAGES, ios::app); - logf<<" --> Warning <-- The chemical "<<name<<" is solid.\n"; - logf.close(); - warning++; - } - check_error(); - if (T<Tboil(P)) state=0; - else state=1; -} +#include "chemical.hpp" +using namespace std; + +void chemical::check_error ( void ) { + if (error>MAX_ERROR) { + cout << "ERROR 2\n\n"; + exit(0); + } + if (warning>MAX_WARNING) { + cout << "ERROR 3\n\n"; + exit(0); + } +} + +// copy-constr. : +chemical::chemical ( const chemical & chem ) { + + CAS = chem.CAS; + name = chem.name; + M = chem.M; + + state = chem.state; + Tm = chem.Tm; + Tb = chem.Tb; + Tc = chem.Tc; + Pc = chem.Pc; + Ho = chem.Ho; + rho_liq = chem.rho_liq; + dHvap = chem.dHvap; + + mu_param[0] = chem.mu_param[0]; + mu_param[1] = chem.mu_param[1]; + Cp_param[0] = chem.Cp_param[0]; + Cp_param[1] = chem.Cp_param[1]; + Cp_param[2] = chem.Cp_param[2]; + Cp_param[3] = chem.Cp_param[3]; + Cp_liq = chem.Cp_liq; + Psat_param[0] = chem.Psat_param[0]; + Psat_param[1] = chem.Psat_param[1]; + Psat_param[2] = chem.Psat_param[2]; + + thermo = new thermolib(); + thermo->send(Pc,Tc, omega()); + + P = chem.P; + T = chem.T; + m = chem.m; + v = chem.v; + + warning = chem.warning; + error = chem.error; + tmp = chem.tmp; +} + +chemical::chemical ( const string & chem_name ) { + + CAS = chem_name; + + // C. Tribes add initialization for more robustness (variables may be initialized uncorrectly dependent on the execution) + P=T=m=v=0.0; + + // 1/12 : + if (CAS=="100-41-4") { + name = "ethylbenzene"; + M = 106.17; + state = 0; + Tm = 178.2; + Tb = 409.3; + Tc = 617.1; + Pc = 35.6; + Ho = 29.79; + rho_liq = 867.0; + dHvap = 35.56; + mu_param[0] = 472.82; + mu_param[1] = 264.22; + Cp_param[0] = -43.069; + Cp_param[1] = 7.067e-01; + Cp_param[2] = -4.807e-04; + Cp_param[3] = 1.30e-07; + Cp_liq = 190.23; + Psat_param[0] = 16.0195; + Psat_param[1] = 3279.47; + Psat_param[2] = -59.95; + } + + // 2/12 : + else if (CAS=="1333-74-0") { + name = "hydrogen"; + M = 2.02; + state = 1; + Tm = 14.0; + Tb = 20.4; + Tc = 33.2; + Pc = 12.8; + Ho = 0.0; + rho_liq = 71.0; + dHvap = 0.9; + mu_param[0] = 13.82; + mu_param[1] = 5.39; + Cp_param[0] = 27.124; + Cp_param[1] = 9.267e-03; + Cp_param[2] = -1.380e-05; + Cp_param[3] = 7.64e-09; + Cp_liq = 0.0; + Psat_param[0] = 13.6333; + Psat_param[1] = 164.90; + Psat_param[2] = 3.19; + } + + // 3/12 : + else if (CAS=="108-88-3") { + name = "toluene"; + M =92.14; + state = 0; + Tm = 178.0; + Tb = 383.8; + Tc = 591.7; + Pc = 40.6; + Ho = 50.0; + rho_liq = 867; + dHvap = 33.18; + mu_param[0] = 467.33; + mu_param[1] = 255.24; + Cp_param[0] = -24.338; + Cp_param[1] = 5.121e-1; + Cp_param[2] = -2.763e-4; + Cp_param[3] = 4.91e-8; + Cp_liq = 159.85; + Psat_param[0] = 16.0137; + Psat_param[1] = 3096.52; + Psat_param[2] = -53.67; + } + + // 4/12 : + else if (CAS=="74-82-8") { + name = "methane"; + M =16.04; + state =1; + Tm = 90.7; + Tb = 111.7; + Tc = 190.6; + Pc = 45.4; + Ho = -74.85; + rho_liq = 425; + dHvap = 8.18; + mu_param[0] = 114.14; + mu_param[1] = 57.60; + Cp_param[0] = 19.238; + Cp_param[1] = 5.209e-02; + Cp_param[2] = 1.197e-05; + Cp_param[3] = -1.13e-08; + Cp_liq = 0.0; + Psat_param[0] = 15.2243; + Psat_param[1] = 897.84; + Psat_param[2] = -7.16; + } + + // 5/12 : + else if (CAS=="71-43-2") { + name = "benzene"; + M = 78.11; + state = 0; + Tm = 278.7; + Tb = 353.3; + Tc = 562.1; + Pc = 48.3; + Ho = 82.93; + rho_liq = 885; + dHvap = 30.76; + mu_param[0] = 545.64; + mu_param[1] = 265.24; + Cp_param[0] = 33.894; + Cp_param[1] = 4.74e-1; + Cp_param[2] = -3.015e-4; + Cp_param[3] = 7.13e-8; + Cp_liq = 116.03; + Psat_param[0] = 15.9008; + Psat_param[1] = 2788.51; + Psat_param[2] = -52.36; + } + + // 6/12 : + else if (CAS=="74-85-1") { + name = "ethylene"; + M = 28.05; + state =1; + Tm = 104.0; + Tb = 169.4; + Tc = 282.4; + Pc = 49.7; + Ho =52.3; + rho_liq = 577.0; + dHvap = 13.54; + mu_param[0] = 168.98; + mu_param[1] = 93.94; + Cp_param[0] = 3.803; + Cp_param[1] = 1.565e-01; + Cp_param[2] = -8.343e-05; + Cp_param[3] = 1.75e-08; + Cp_liq = 0.0; + Psat_param[0] =15.5368; + Psat_param[1] = 1347.01; + Psat_param[2] = -18.15; + } + + // 7/12 : + else if (CAS=="100-42-5") { + name = "styrene"; + M =104.15; + state = 0; + Tm = 242.5; + Tb = 418.3; + Tc =647.0; + Pc =39.4; + Ho =147.36; + rho_liq =906.0; + dHvap = 36.82; + mu_param[0] = 528.64; + mu_param[1] = 276.71; + Cp_param[0] =-28.229; + Cp_param[1] =6.155e-01; + Cp_param[2] = -4.020e-04; + Cp_param[3] = 9.93e-08; + Cp_liq =166.13; + Psat_param[0] = 16.0193; + Psat_param[1] = 3328.57; + Psat_param[2] =-63.72; + } + + // 8/12 : + else if (CAS=="7782-44-7") { + name = "oxygen"; + M = 32.00; + state = 1; + Tm = 54.4; + Tb = 90.2; + Tc = 154.6; + Pc = 49.8; + Ho =0.0 ; + rho_liq =1149.1 ; + dHvap =6.82 ; + mu_param[0] = 85.68; + mu_param[1] = 51.50; + Cp_param[0] = 28.087; + Cp_param[1] = -3.678e-06 ; + Cp_param[2] = 1.745e-05; + Cp_param[3] = -1.06e-08; + Cp_liq =0.0 ; + Psat_param[0] = 15.4075; + Psat_param[1] = 734.55 ; + Psat_param[2] =-6.45 ; + } + + // 9/12 : + else if (CAS=="7727-37-9") { + name = "nitrogen"; + M = 28.01; + state = 1; + Tm = 63.3; + Tb = 77.4; + Tc = 126.2; + Pc = 33.5; + Ho = 0.0; + rho_liq = 804.0; + dHvap = 5.58; + mu_param[0] = 90.30; + mu_param[1] = 46.41; + Cp_param[0] = 31.128; + Cp_param[1] = -1.356e-02 ; + Cp_param[2] = 2.678e-05; + Cp_param[3] =-1.17e-08 ; + Cp_liq = 0.0; + Psat_param[0] = 14.9342; + Psat_param[1] = 588.72; + Psat_param[2] = -6.60; + } + + // 10/12 : + else if (CAS=="124-38-9") { + name = "carbon-dioxide"; + M =44.01; + state = 1; + Tm = 216.6; + Tb = 194.4; + Tc = 304.2; + Pc = 72.8; + Ho = -393.41; + rho_liq = 777.0; + dHvap = 17.15; + mu_param[0] = 578.08; + mu_param[1] = 185.24 ; + Cp_param[0] = 19.782; + Cp_param[1] = 7.339e-02; + Cp_param[2] = -5.598e-05; + Cp_param[3] = 1.71e-08; + Cp_liq = 0.0; + Psat_param[0] = 22.5898; + Psat_param[1] =3103.39 ; + Psat_param[2] = -0.16; + } + + // 11/12 : + else if (CAS=="7732-18-5") { + name = "water"; + M =18.02; + state = 0; + Tm = 273.15; + Tb = 373.15; + Tc = 647.4; + Pc = 217.6; + Ho = -241.83; + rho_liq = 998 ; + dHvap = 40.66; + mu_param[0] = 658.25; + mu_param[1] = 283.16; + Cp_param[0] = 32.220; + Cp_param[1] = 1.923e-03 ; + Cp_param[2] = 1.055e-05; + Cp_param[3] = -3.59e-09; + Cp_liq = 75.24; + Psat_param[0] = 18.3036; + Psat_param[1] = 3816.44; + Psat_param[2] = -46.13; + } + + // 12/12 : + else if (CAS=="64-17-5") { + name = "ethanol"; + M =46.07; + state =0 ; + Tm =159.1 ; + Tb = 351.5; + Tc = 516.2; + Pc =63.0 ; + Ho = -234.8; + rho_liq = 789.0; + dHvap =38.74 ; + mu_param[0] = 686.64; + mu_param[1] = 300.88; + Cp_param[0] = 9.008; + Cp_param[1] = 2.139e-01; + Cp_param[2] = -8.385e-05 ; + Cp_param[3] = 1.37e-09; + Cp_liq = 2.22; + Psat_param[0] = 18.9119; + Psat_param[1] = 3803.98; + Psat_param[2] = -41.68; + } + + else { + cout << "ERROR 1\n\n"; + exit(0); + } + + thermo = new thermolib(); + thermo->send(Pc,Tc, omega()); + + +} + +double chemical::K() +{ + thermo->set(P,T,v,n()); + return thermo->K(); +} + +double chemical::mu() +{ + // Returns the fluid's viscosity in Pa.s + if (Tm<=T && T<=Tboil(P)) + return pow(10,(mu_param[0]*(1.0/T-1.0/mu_param[1])-3)); + else + { + ofstream logf; + logf.open(MESSAGES, ios::app); + logf<<" --> Warning <-- Cannot compute viscosity of "<<name<<".\n"; + logf.close(); + warning++; + check_error(); + return 1.0; + } +} + +double chemical::rho() +{ + // Returns the fluid's density in kg/m3, wether it's liquid or gas + if(state==0) tmp= rho_liq; + if(state==1) + { + find_v(); + if (v>EPS) tmp= m/v; + else tmp= 0.0; + } + return tmp; +} + +double chemical::Cp() { + // cout<<endl<<"Cp de "<<name<<" a "<<T; + // Returns the fluid's Cp in J/mol.K + if(state==0) { + + // tmp = Cp_liq; // BUG : boucle infinie !!! + return Cp_liq; // SEB + + } + if(state==1 || T>Tboil(P)) { + tmp=0; + for (int i=0;i<4;i++) + tmp+=Cp_param[i]*pow(T,i); + } + else { + T=Tb; + + tmp = Cp(); // ici boucle infinie si state==0 !!! + + } + return tmp; +} + +double chemical::Cp(bool q) +{ + // Returns the fluid's Cp in J/mol.K + if(q==0) tmp=Cp_liq; + if(q==1) + { + tmp=0; + for (int i=0;i<4;i++) tmp+=Cp_param[i]*pow(T,i); + } + return tmp; +} + +double chemical::Psat() +{ + // Returns the fluid's vapor pressure in atm, using Antoine's equation + if(Tm<=T && T<=Tc) + return (exp(Psat_param[0]-Psat_param[1]/(T+Psat_param[2]))/760.01); + else + { + + return Psat(Tb); + } +} +double chemical::Psat(double t) +{ + // Returns the fluid's vapor pressure in atm, using Antoine's equation + return (exp(Psat_param[0]-Psat_param[1]/(t+Psat_param[2]))/760.01); +} + +double chemical::dH(double T1,double T2, double pres) +{ + //Enthalpy variation in kJ/mol. Does not affect any attributes of current object. + double energy=0, TT=Tboil(pres), vap=Hvap(TT); + int sign=1, i; + if (T2<T1) {sign = -1; energy=T1; T1=T2; T2=energy; energy=0;} + if (T1==T2) energy = 0.0; + if (T2<TT) energy = Cp_liq*(T2-T1)/1000; + if (TT<T1) for (i=1;i<=4;i++) energy+=Cp_param[i-1]*(pow(T2,i)-pow(T1,i))/i/1000; + if(T1<=TT && TT<=T2) + { + energy=Cp_liq*(TT-T1)/1000; + energy+=vap; + for (i=1;i<=4;i++) energy+=Cp_param[i-1]*(pow(T2,i)-pow(TT,i))/i/1000; + } + return energy*sign; +} + +void chemical::find_T() +{ + if(n()>EPS && P>EPS) + { + thermo->set(P,T,v,n()); + T=thermo->T(); + } + else + { + ofstream logf; + logf.open(MESSAGES, ios::app); + logf<<" --> Warning <-- Cannot find T of "<<name<<".\n"; + logf.close(); + warning++; + } + check_error(); +} + +void chemical::find_P() +{ + if(n()>EPS && T>EPS) + { + thermo->set(P,T,v,n()); + P=thermo->P(); + } + else + { + ofstream logf; + logf.open(MESSAGES, ios::app); + logf<<" --> Warning <-- Cannot find P of "<<name<<".\n"; + logf.close(); + warning++; + } + check_error(); +} + +void chemical::find_v() +{ + + if(state==0) v=m/rho_liq; + if(state==1 && P>EPS && T>EPS && m>EPS) + { + thermo->set(P,T,v,n()); + v=thermo->v(); + } +} + +void chemical::find_state() +{ + ofstream logf; + if (T>Tc || P>Pc) state = 1; //T or P is bigger than Tc or Pc + if (T<=Tm) //T is smaller than melting point + { + ofstream logf; + logf.open(MESSAGES, ios::app); + logf<<" --> Warning <-- The chemical "<<name<<" is solid.\n"; + logf.close(); + warning++; + } + check_error(); + if (T<Tboil(P)) state=0; + else state=1; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/chemical.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/chemical.hpp index 71b28a9..344bd01 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/chemical.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/chemical.hpp @@ -1,48 +1,48 @@ -#ifndef CHEMICAL_H -#define CHEMICAL_H - -#include "thermolib.hpp" -#include <string> -using namespace std; - -class chemical -{ - public: - string name; - string CAS; - double M; //molar weight, in g/mol - bool state; //current state : 0=liquid 1=gas - double P, T, m, v; //current values : P in atm, T in K, m in kg/s, v in m3/s - - double n() {return 1000.0*m/M;} //mole flow in mol/s - double Hvap(double t) {return dHvap*pow((Tc-t)/(Tc-Tb),0.38);} //vaporization heat at specific T (Watson correlation) - double omega() {return ((-1.0)*log10(Psat(0.7*Tc)/Pc) -1.0);} //Pitzer acentric factor - double Tboil(double p) {return (Psat_param[1]/(Psat_param[0]-log(760.01*p))-Psat_param[2]);} //boiling tempararure at specific P - double mu(), rho(), Cp(), Cp(bool), Psat(), Psat(double); //T-dependant properties - double K(); //liquid-vapor equilibrium constant - double gamma(){return Cp(true)/(Cp(true)-8.3144);}//compressibility ratio =Cp/Cv - double dH(double, double, double); //enthalpy variation kJ/mol - void find_T(), find_P(), find_v(), find_state(); //for gases only - double Tm, Tb, Tc, Pc; //melting, boiling and critical temp. (K); critical pressure (atm) - double Ho;//standard formation heat in kJ/mol - - //private: - int warning, error; - void check_error(); - double dHvap, tmp; //vaporization heat (kJ/mol) - double mu_param[2], Cp_param[4], Cp_liq, Psat_param[3], rho_liq; //correlations parameters - thermolib *thermo; - - // public: - // chemical() {}; - - // copy-constr. : - chemical ( const chemical & chem ); - - chemical ( const string & chem_name ); //Contructor : initializes fields and reads CAS in the data file - void purge() {P=T=m=v=0.0; state=false;} - ~chemical(){delete thermo;}; -}; - -#endif - +#ifndef CHEMICAL_H +#define CHEMICAL_H + +#include "thermolib.hpp" +#include <string> +using namespace std; + +class chemical +{ + public: + string name; + string CAS; + double M; //molar weight, in g/mol + bool state; //current state : 0=liquid 1=gas + double P, T, m, v; //current values : P in atm, T in K, m in kg/s, v in m3/s + + double n() {return 1000.0*m/M;} //mole flow in mol/s + double Hvap(double t) {return dHvap*pow((Tc-t)/(Tc-Tb),0.38);} //vaporization heat at specific T (Watson correlation) + double omega() {return ((-1.0)*log10(Psat(0.7*Tc)/Pc) -1.0);} //Pitzer acentric factor + double Tboil(double p) {return (Psat_param[1]/(Psat_param[0]-log(760.01*p))-Psat_param[2]);} //boiling tempararure at specific P + double mu(), rho(), Cp(), Cp(bool), Psat(), Psat(double); //T-dependant properties + double K(); //liquid-vapor equilibrium constant + double gamma(){return Cp(true)/(Cp(true)-8.3144);}//compressibility ratio =Cp/Cv + double dH(double, double, double); //enthalpy variation kJ/mol + void find_T(), find_P(), find_v(), find_state(); //for gases only + double Tm, Tb, Tc, Pc; //melting, boiling and critical temp. (K); critical pressure (atm) + double Ho;//standard formation heat in kJ/mol + + //private: + int warning, error; + void check_error(); + double dHvap, tmp; //vaporization heat (kJ/mol) + double mu_param[2], Cp_param[4], Cp_liq, Psat_param[3], rho_liq; //correlations parameters + thermolib *thermo; + + // public: + // chemical() {}; + + // copy-constr. : + chemical ( const chemical & chem ); + + chemical ( const string & chem_name ); //Contructor : initializes fields and reads CAS in the data file + void purge() {P=T=m=v=0.0; state=false;} + ~chemical(){delete thermo;}; +}; + +#endif + diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/column.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/column.cpp index 85ab3e0..f4a35c1 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/column.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/column.cpp @@ -1,290 +1,290 @@ -#include "column.hpp" -using namespace std; - -column::column(stream* in, stream* out_B, stream* out_D) -{ - F = in; - B = out_B; - D = out_D; - L=new stream("columnL", F->nb, F->chem); - V=new stream("columnV", F->nb, F->chem); - flasher = new flash(F, L, V); - alpha_1 = new double[F->nb]; - alpha_f = new double[F->nb]; - alpha_N = new double[F->nb]; - alpha_m = new double[F->nb]; - T_d=0; T_b=0; T_f=F->T; -// for(i=0;i<F->nb;i++) -// if(F->chem[i]->Tc<F->T && F->chem[i]->m>EPS) -// { -// logf.open(MESSAGES,ios::app); -// logf<<" --> Warning <-- Presence of gas in column.\n"; -// logf.close(); -// i=F->nb; -// } -} - -column::~column() -{ - delete L; delete V; delete flasher; - delete [] alpha_1; - delete [] alpha_f; - delete [] alpha_N; - delete [] alpha_m; -} - -void column::set(double p, int lk, double xd, int hk, double xb) -{ - P=p; - HK=hk-1; x_B=xb; - LK=lk-1; x_D=xd; - //logf.open(MESSAGES, ios::app); - // F->write(); system("pause"); - // if (F->chem[LK]->m<EPS) logf<<" ==> Error <== Flow of light key in column "<<name<<" is zero.\n"; -// if (F->chem[HK]->m<EPS) logf<<" ==> Error <== Flow of heavy key in column "<<name<<" is zero.\n"; - //logf.close(); -} - -bool column::solve() -{ - - OK=true; - // B->thermo=F->thermo; D->thermo=F->thermo; - //flash once the feed stream - - - - flasher->set(P,F->T); - - flasher->adiabatic(); - - - T_f=flasher->T; - L->set(P, T_f); V->set(P, T_f); - // L->write(); V->write(); TOTO - //check if a column is needed; if not, bypass block - if(F->chem[LK]->n()/F->n()<0.001) OK=false; - if(F->chem[HK]->n()/F->n()<0.001) OK=false; - if(!OK) - return false; -// { -// strcpy(filename, B->name); *B=*L; B->set(filename); B->write(); -// strcpy(filename, D->name); *D=*V; D->set(filename); D->write(); -// } - else - { - - - - - - //apply the FUG method - first_split(); - Nmin = Fenske(); - N=Nmin+1; - while (fabs(N-Nmin)>0.1) - { - N=Nmin; - D->set(P, T_f); T_d=D->bp; - B->set(P, T_f); T_b=B->bp; - set_alpha(); - distribute(); - Nmin = Fenske(); - if (Nmin<1) Nmin=1; - } - D->set(P, T_d); - B->set(P, T_b); - if(fabs(Nmin)<=MIN_PLATES || fabs(Nmin)>MAX_PLATES) OK=false; - else - { - Rmin = Underwood(); - if(Rmin>100) Rmin=100; - if(L->chem[HK]->m+L->chem[LK]->m<EPS) Rmin=10.0; - if (Nmin<5) Ract = 1.5*Rmin; - if (5<Nmin && Nmin<15) Ract = 1.3*Rmin; - if (15<=Nmin) Ract = 1.1*Rmin; - N = Gilliland(); - feed = Kirkbride(); - condense(); - reboil(); - } - // B->write(); TOTO - // D->write(); TOTO - } - return OK; -} - -void column::first_split() -{ - B->purge(); D->purge(); - set_alpha(); - //Check if LK is really lighter than HK - if (alpha_m[LK]<1) - { -// logf.open(MESSAGES,ios::app); -// logf<<" --> Warning <-- Swapping keys in column "<<name<<".\n"; -// logf.close(); - feed=LK; LK=HK; HK=feed; set_alpha(); - } - for(i=0;i<F->nb;i++) - { - if (i!=LK && i!=HK && F->chem[i]->m>EPS) - { - if(alpha_f[i] > alpha_f[LK]) //volatile - { - D->chem[i]->m = (alpha_f[i]-alpha_f[LK])/alpha_f[i]*F->chem[i]->m; - D->m += D->chem[i]->m; - B->chem[i]->m = F->chem[i]->m-D->chem[i]->m; - B->m+=B->chem[i]->m; - } - if(alpha_f[i] < 1) //not volatile - { - B->chem[i]->m = (alpha_f[HK]-alpha_f[i])/alpha_f[i]*F->chem[i]->m; - B->m += B->chem[i]->m; - D->chem[i]->m = F->chem[i]->m-B->chem[i]->m; - D->m+=D->chem[i]->m; - } - if(1 <= alpha_f[i] && alpha_f[i]<=alpha_f[LK]) //ambiguous volatility - { - D->chem[i]->m = (alpha_f[i]-1)/(alpha_f[LK]-1)*F->chem[i]->m; - B->chem[i]->m = F->chem[i]->m-D->chem[i]->m; - D->m+=D->chem[i]->m; - B->m+=B->chem[i]->m; - } - } - } - D->chem[HK]->m = D->n()*x_D/(1-x_D)*D->chem[HK]->M/1000.0; - if(D->chem[HK]->m<EPS) D->chem[HK]->m=0.01*F->chem[HK]->m; - B->chem[LK]->m = B->n()*x_B/(1-x_B)*B->chem[LK]->M/1000.0; - if(B->chem[LK]->m<EPS) B->chem[LK]->m=0.01*F->chem[LK]->m; - B->chem[HK]->m = F->chem[HK]->m - D->chem[HK]->m; - D->chem[LK]->m = F->chem[LK]->m - B->chem[LK]->m; - D->m += (D->chem[LK]->m + D->chem[HK]->m); - B->m += (B->chem[LK]->m + B->chem[HK]->m); -} -void column::distribute() -{ - D->m=0; B->m=0; - for(i=0;i<F->nb;i++) - { - if (i!=LK && i!=HK && F->chem[i]->m>EPS) - { - if(alpha_m[i] > 1) //volatile and ambiguous - { - B->chem[i]->m = F->chem[i]->m/(1+D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin)); - D->chem[i]->m = F->chem[i]->m - B->chem[i]->m; - } - if(alpha_m[i] <= 1) //not volatile - { - D->chem[i]->m = F->chem[i]->m*(D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin))/(1+D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin)); - B->chem[i]->m = F->chem[i]->m - D->chem[i]->m; - } - D->m+=D->chem[i]->m; - B->m+=B->chem[i]->m; - } - } - D->m += (D->chem[LK]->m + D->chem[HK]->m); - B->m += (B->chem[LK]->m + B->chem[HK]->m); -} - -void column::set_alpha() -{ - for(i=0;i<F->nb; i++) - { - if (T_b>EPS && F->chem[i]->m>EPS) alpha_1[i] = F->chem[i]->Psat(T_b)/F->chem[HK]->Psat(T_b); - else alpha_1[i]=0; - if (T_d>EPS&& F->chem[i]->m>EPS) alpha_N[i] = F->chem[i]->Psat(T_d)/F->chem[HK]->Psat(T_d); - else alpha_N[i]=0; - if (T_f>EPS&& F->chem[i]->m>EPS) alpha_f[i] = F->chem[i]->Psat(T_f)/F->chem[HK]->Psat(T_f); - else alpha_f[i]=0; - alpha_m[i] = pow(alpha_1[i]*alpha_f[i]*alpha_N[i], 1.0/3.0); - } - for(i=0;i<F->nb;i++) if(alpha_m[i]<EPS&& F->chem[i]->m>EPS) alpha_m[i] = alpha_f[i]; -} - -void column::reboil() -{ - Q_reboil = 0.0; - for (i=0;i<F->nb;i++) if(F->chem[i]->m>EPS) - { - Q_reboil += B->chem[i]->Cp(false)*(T_b-T_f)*B->chem[i]->n()/1000.0; //energy to go from input to bottoms T - Q_reboil += D->chem[i]->Cp(false)*(T_f-T_d)*D->chem[i]->n()/1000.0; //energy to go from input to tops T - } - Q_reboil += Q_condens; -} - -void column::condense() -{ - Q_condens = 0.0; - for (i=0;i<F->nb;i++) if(F->chem[i]->m>EPS) - { - Q_condens += D->chem[i]->Hvap(T_d)*(1+Ract)*D->chem[i]->n(); - } -} - -void column::write() -{ - cout << setprecision(11); - - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout <<"\t>> "<<name; - cout <<endl<<"\t>> stream in: "<<F->name; - cout <<endl<<"\t>> streams out: "<<B->name<<" (bot.) "<<D->name<<" (top.)"; - cout <<endl<<"\t>> P = "<<P<<" atm, T(0) = "<<T_b<<", T("<<feed<<") = "<<T_f<<", T("<<int(N)<<") = "<<T_d<<" K"; - cout <<endl<<"\t>> Number of stages: "<<int(N)<<" (feeding at stage "<<feed<<")"; - cout <<endl<<setiosflags(ios::fixed|ios::showpoint)<<setprecision(5)<<"\t>> LK purity = "<<D->chem[LK]->n()/D->n()<<" HK purity = "<<B->chem[HK]->n()/B->n(); - cout <<endl<<"\t>> Reboiler duty: "<<Q_reboil<<" kW Condenser duty: "<<(-1)*Q_condens<<" kW"; - cout << "\n\tEND\n\n"; - cost(); water(); power(); -} - -double column::get_cost() -{ - //cost of vessel - vol=(0.45*N)*(pow(300*D->v, 1.5)/2.4/sqrt(B->v))*sqrt(D->m/B->m); - if(vol<0.3) vol=0.3; if(vol>520)vol=520; - money = 3.4974+0.4485*log10(vol)+0.1074*pow(log10(vol),2); - money = pow(10, money); - P= (P-1)*101.325/100; - diam=sqrt(4.0*vol/pi/N/0.45); - vol=(P+1)*diam/(317.46*(850-0.6*(P+1)))+0.0315; - money *=(2.25+ 1.82*vol*2.2); - //cost of trays - vol = (pow(300*D->v, 1.5)/2.4/sqrt(B->v))*sqrt(D->m/B->m); - diam = 2.9949+0.4465*log10(vol)+0.3961*pow(log10(vol),2); - money+=1.5*pow(10, diam); - //cost of reboiler U=5250W/m2.K - vol=fabs(Q_reboil)/0.85/5.25/15.0; - if(vol<10) vol=10; if(vol>100) vol=100; - vol = 4.4646-0.5277*log10(vol)+0.3955*pow(log10(vol),2); - money += (1.63+1.66*2.5)*pow(10, vol); - //cost of condenser U=1850W/m2.K - vol=fabs(Q_condens)/0.85/1.85/(0.5*(T_d-298)); - if(vol<1) vol=1; if(vol>100) vol=100; - vol = 3.9912+0.0668*log10(vol)+0.243*pow(log10(vol),2); - money += (1.74+1.55*2.5)*pow(10, vol); - money = money*MS_YEAR/MS_2001; - return money; -} - - -void column::cost() -{ - cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} -void column::power() -{ - cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; - money =(Q_reboil/0.85-Q_condens); - cout << "\t>>" << money; - cout << "\n\tEND\n\n"; -} -void column::water() -{ - cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; - money = (fabs(Q_condens)/(4.185*0.85*0.25*fabs(T_d-298))); - cout << "\t>>" << money; - cout << "\n\tEND\n\n"; -} +#include "column.hpp" +using namespace std; + +column::column(stream* in, stream* out_B, stream* out_D) +{ + F = in; + B = out_B; + D = out_D; + L=new stream("columnL", F->nb, F->chem); + V=new stream("columnV", F->nb, F->chem); + flasher = new flash(F, L, V); + alpha_1 = new double[F->nb]; + alpha_f = new double[F->nb]; + alpha_N = new double[F->nb]; + alpha_m = new double[F->nb]; + T_d=0; T_b=0; T_f=F->T; +// for(i=0;i<F->nb;i++) +// if(F->chem[i]->Tc<F->T && F->chem[i]->m>EPS) +// { +// logf.open(MESSAGES,ios::app); +// logf<<" --> Warning <-- Presence of gas in column.\n"; +// logf.close(); +// i=F->nb; +// } +} + +column::~column() +{ + delete L; delete V; delete flasher; + delete [] alpha_1; + delete [] alpha_f; + delete [] alpha_N; + delete [] alpha_m; +} + +void column::set(double p, int lk, double xd, int hk, double xb) +{ + P=p; + HK=hk-1; x_B=xb; + LK=lk-1; x_D=xd; + //logf.open(MESSAGES, ios::app); + // F->write(); system("pause"); + // if (F->chem[LK]->m<EPS) logf<<" ==> Error <== Flow of light key in column "<<name<<" is zero.\n"; +// if (F->chem[HK]->m<EPS) logf<<" ==> Error <== Flow of heavy key in column "<<name<<" is zero.\n"; + //logf.close(); +} + +bool column::solve() +{ + + OK=true; + // B->thermo=F->thermo; D->thermo=F->thermo; + //flash once the feed stream + + + + flasher->set(P,F->T); + + flasher->adiabatic(); + + + T_f=flasher->T; + L->set(P, T_f); V->set(P, T_f); + // L->write(); V->write(); TOTO + //check if a column is needed; if not, bypass block + if(F->chem[LK]->n()/F->n()<0.001) OK=false; + if(F->chem[HK]->n()/F->n()<0.001) OK=false; + if(!OK) + return false; +// { +// strcpy(filename, B->name); *B=*L; B->set(filename); B->write(); +// strcpy(filename, D->name); *D=*V; D->set(filename); D->write(); +// } + else + { + + + + + + //apply the FUG method + first_split(); + Nmin = Fenske(); + N=Nmin+1; + while (fabs(N-Nmin)>0.1) + { + N=Nmin; + D->set(P, T_f); T_d=D->bp; + B->set(P, T_f); T_b=B->bp; + set_alpha(); + distribute(); + Nmin = Fenske(); + if (Nmin<1) Nmin=1; + } + D->set(P, T_d); + B->set(P, T_b); + if(fabs(Nmin)<=MIN_PLATES || fabs(Nmin)>MAX_PLATES) OK=false; + else + { + Rmin = Underwood(); + if(Rmin>100) Rmin=100; + if(L->chem[HK]->m+L->chem[LK]->m<EPS) Rmin=10.0; + if (Nmin<5) Ract = 1.5*Rmin; + if (5<Nmin && Nmin<15) Ract = 1.3*Rmin; + if (15<=Nmin) Ract = 1.1*Rmin; + N = Gilliland(); + feed = Kirkbride(); + condense(); + reboil(); + } + // B->write(); TOTO + // D->write(); TOTO + } + return OK; +} + +void column::first_split() +{ + B->purge(); D->purge(); + set_alpha(); + //Check if LK is really lighter than HK + if (alpha_m[LK]<1) + { +// logf.open(MESSAGES,ios::app); +// logf<<" --> Warning <-- Swapping keys in column "<<name<<".\n"; +// logf.close(); + feed=LK; LK=HK; HK=feed; set_alpha(); + } + for(i=0;i<F->nb;i++) + { + if (i!=LK && i!=HK && F->chem[i]->m>EPS) + { + if(alpha_f[i] > alpha_f[LK]) //volatile + { + D->chem[i]->m = (alpha_f[i]-alpha_f[LK])/alpha_f[i]*F->chem[i]->m; + D->m += D->chem[i]->m; + B->chem[i]->m = F->chem[i]->m-D->chem[i]->m; + B->m+=B->chem[i]->m; + } + if(alpha_f[i] < 1) //not volatile + { + B->chem[i]->m = (alpha_f[HK]-alpha_f[i])/alpha_f[i]*F->chem[i]->m; + B->m += B->chem[i]->m; + D->chem[i]->m = F->chem[i]->m-B->chem[i]->m; + D->m+=D->chem[i]->m; + } + if(1 <= alpha_f[i] && alpha_f[i]<=alpha_f[LK]) //ambiguous volatility + { + D->chem[i]->m = (alpha_f[i]-1)/(alpha_f[LK]-1)*F->chem[i]->m; + B->chem[i]->m = F->chem[i]->m-D->chem[i]->m; + D->m+=D->chem[i]->m; + B->m+=B->chem[i]->m; + } + } + } + D->chem[HK]->m = D->n()*x_D/(1-x_D)*D->chem[HK]->M/1000.0; + if(D->chem[HK]->m<EPS) D->chem[HK]->m=0.01*F->chem[HK]->m; + B->chem[LK]->m = B->n()*x_B/(1-x_B)*B->chem[LK]->M/1000.0; + if(B->chem[LK]->m<EPS) B->chem[LK]->m=0.01*F->chem[LK]->m; + B->chem[HK]->m = F->chem[HK]->m - D->chem[HK]->m; + D->chem[LK]->m = F->chem[LK]->m - B->chem[LK]->m; + D->m += (D->chem[LK]->m + D->chem[HK]->m); + B->m += (B->chem[LK]->m + B->chem[HK]->m); +} +void column::distribute() +{ + D->m=0; B->m=0; + for(i=0;i<F->nb;i++) + { + if (i!=LK && i!=HK && F->chem[i]->m>EPS) + { + if(alpha_m[i] > 1) //volatile and ambiguous + { + B->chem[i]->m = F->chem[i]->m/(1+D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin)); + D->chem[i]->m = F->chem[i]->m - B->chem[i]->m; + } + if(alpha_m[i] <= 1) //not volatile + { + D->chem[i]->m = F->chem[i]->m*(D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin))/(1+D->chem[HK]->n()/B->chem[HK]->n()*pow(alpha_m[i], Nmin)); + B->chem[i]->m = F->chem[i]->m - D->chem[i]->m; + } + D->m+=D->chem[i]->m; + B->m+=B->chem[i]->m; + } + } + D->m += (D->chem[LK]->m + D->chem[HK]->m); + B->m += (B->chem[LK]->m + B->chem[HK]->m); +} + +void column::set_alpha() +{ + for(i=0;i<F->nb; i++) + { + if (T_b>EPS && F->chem[i]->m>EPS) alpha_1[i] = F->chem[i]->Psat(T_b)/F->chem[HK]->Psat(T_b); + else alpha_1[i]=0; + if (T_d>EPS&& F->chem[i]->m>EPS) alpha_N[i] = F->chem[i]->Psat(T_d)/F->chem[HK]->Psat(T_d); + else alpha_N[i]=0; + if (T_f>EPS&& F->chem[i]->m>EPS) alpha_f[i] = F->chem[i]->Psat(T_f)/F->chem[HK]->Psat(T_f); + else alpha_f[i]=0; + alpha_m[i] = pow(alpha_1[i]*alpha_f[i]*alpha_N[i], 1.0/3.0); + } + for(i=0;i<F->nb;i++) if(alpha_m[i]<EPS&& F->chem[i]->m>EPS) alpha_m[i] = alpha_f[i]; +} + +void column::reboil() +{ + Q_reboil = 0.0; + for (i=0;i<F->nb;i++) if(F->chem[i]->m>EPS) + { + Q_reboil += B->chem[i]->Cp(false)*(T_b-T_f)*B->chem[i]->n()/1000.0; //energy to go from input to bottoms T + Q_reboil += D->chem[i]->Cp(false)*(T_f-T_d)*D->chem[i]->n()/1000.0; //energy to go from input to tops T + } + Q_reboil += Q_condens; +} + +void column::condense() +{ + Q_condens = 0.0; + for (i=0;i<F->nb;i++) if(F->chem[i]->m>EPS) + { + Q_condens += D->chem[i]->Hvap(T_d)*(1+Ract)*D->chem[i]->n(); + } +} + +void column::write() +{ + cout << setprecision(11); + + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout <<"\t>> "<<name; + cout <<endl<<"\t>> stream in: "<<F->name; + cout <<endl<<"\t>> streams out: "<<B->name<<" (bot.) "<<D->name<<" (top.)"; + cout <<endl<<"\t>> P = "<<P<<" atm, T(0) = "<<T_b<<", T("<<feed<<") = "<<T_f<<", T("<<int(N)<<") = "<<T_d<<" K"; + cout <<endl<<"\t>> Number of stages: "<<int(N)<<" (feeding at stage "<<feed<<")"; + cout <<endl<<setiosflags(ios::fixed|ios::showpoint)<<setprecision(5)<<"\t>> LK purity = "<<D->chem[LK]->n()/D->n()<<" HK purity = "<<B->chem[HK]->n()/B->n(); + cout <<endl<<"\t>> Reboiler duty: "<<Q_reboil<<" kW Condenser duty: "<<(-1)*Q_condens<<" kW"; + cout << "\n\tEND\n\n"; + cost(); water(); power(); +} + +double column::get_cost() +{ + //cost of vessel + vol=(0.45*N)*(pow(300*D->v, 1.5)/2.4/sqrt(B->v))*sqrt(D->m/B->m); + if(vol<0.3) vol=0.3; if(vol>520)vol=520; + money = 3.4974+0.4485*log10(vol)+0.1074*pow(log10(vol),2); + money = pow(10, money); + P= (P-1)*101.325/100; + diam=sqrt(4.0*vol/pi/N/0.45); + vol=(P+1)*diam/(317.46*(850-0.6*(P+1)))+0.0315; + money *=(2.25+ 1.82*vol*2.2); + //cost of trays + vol = (pow(300*D->v, 1.5)/2.4/sqrt(B->v))*sqrt(D->m/B->m); + diam = 2.9949+0.4465*log10(vol)+0.3961*pow(log10(vol),2); + money+=1.5*pow(10, diam); + //cost of reboiler U=5250W/m2.K + vol=fabs(Q_reboil)/0.85/5.25/15.0; + if(vol<10) vol=10; if(vol>100) vol=100; + vol = 4.4646-0.5277*log10(vol)+0.3955*pow(log10(vol),2); + money += (1.63+1.66*2.5)*pow(10, vol); + //cost of condenser U=1850W/m2.K + vol=fabs(Q_condens)/0.85/1.85/(0.5*(T_d-298)); + if(vol<1) vol=1; if(vol>100) vol=100; + vol = 3.9912+0.0668*log10(vol)+0.243*pow(log10(vol),2); + money += (1.74+1.55*2.5)*pow(10, vol); + money = money*MS_YEAR/MS_2001; + return money; +} + + +void column::cost() +{ + cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} +void column::power() +{ + cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; + money =(Q_reboil/0.85-Q_condens); + cout << "\t>>" << money; + cout << "\n\tEND\n\n"; +} +void column::water() +{ + cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; + money = (fabs(Q_condens)/(4.185*0.85*0.25*fabs(T_d-298))); + cout << "\t>>" << money; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/column.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/column.hpp index cfd1daf..8dedb5a 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/column.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/column.hpp @@ -1,61 +1,61 @@ -/* -This unit simulates a distillation column, using -the FUG method. -(ref : Seader & Henley). - -Structure in the .process file: -column {name} {pressure} {index of input stream} {index of bottoms and heads} {indexes of light key and heavy key} {x_LK and x_HK} - -How to use: - 1- Call the constructor : col = new column(in, out_B, out_D); //in is F, out_B is B, out_D is D column(nb, chem_list) - set(in, out_B, out_D) - 2- Set operating conditions : col->set(pressure, LK, x_LK, HK, x_HK); // LK and HK and integer indexes, x_LK is the undesired mole fraction of LK in B, x_HK... - 3- Set the name : col->set(name); - 4- Run the model: col->solve(); -*/ -#ifndef COLUMN_H -#define COLUMN_H - -#include "flash.hpp" -using namespace std; - -class column -{ -private: - // ofstream results, logf; - bool OK; - string name; - stream *F, *B, *D, *L, *V ; - int LK, HK, feed, i; - double x_B, x_D, T_b, T_d, T_f, vol, money, diam; - double Nmin, N, Rmin, Ract, tmp, Q_condens, Q_reboil; - double *alpha_1, *alpha_f, *alpha_N, *alpha_m; - flash *flasher; - void set_alpha(), first_split(), distribute(), condense(), reboil(); - double Fenske() { return log10(D->chem[LK]->n()*B->chem[HK]->n()/D->chem[HK]->n()/B->chem[LK]->n())/log10(alpha_m[LK]);} - double Underwood() {return L->n()*(D->chem[LK]->n()/L->chem[LK]->n()-alpha_m[LK]*D->chem[HK]->n()/L->chem[HK]->n())/(D->n()*(alpha_m[LK]-1));} - double Gilliland(){N=(Ract-Rmin)/(Ract+1); tmp=1-exp((1+54.4*N)*(N-1)/(11+117.2*N)/pow(N, 0.5)); return (tmp+Nmin)/(1-tmp);} - int Kirkbride() {tmp=pow(B->n()*F->chem[HK]->n()*pow(x_B/x_D,2)/F->chem[LK]->n()/D->n(), 0.206); return int(N/(tmp+1));} - -public: - // column(){P=0.0;} - // column(int, chemical*); - // void set(stream*&, stream*&, stream*&); - column(stream*, stream*, stream*); - ~column(); - double P; - void set(double, int, double, int, double); - void set( const string & n ) { name = n; } - bool solve(); - void write(); - void cost(), water(), power(); - - double get_cost ( void ); - double get_power ( void ) const { return Q_reboil/0.85-Q_condens; } - - double get_water ( void ) const { return fabs(Q_condens)/(4.185*0.85*0.25*fabs(T_d-298)); } - - int get_N ( void ) const { return (int) N; } - -}; -#endif +/* +This unit simulates a distillation column, using +the FUG method. +(ref : Seader & Henley). + +Structure in the .process file: +column {name} {pressure} {index of input stream} {index of bottoms and heads} {indexes of light key and heavy key} {x_LK and x_HK} + +How to use: + 1- Call the constructor : col = new column(in, out_B, out_D); //in is F, out_B is B, out_D is D column(nb, chem_list) + set(in, out_B, out_D) + 2- Set operating conditions : col->set(pressure, LK, x_LK, HK, x_HK); // LK and HK and integer indexes, x_LK is the undesired mole fraction of LK in B, x_HK... + 3- Set the name : col->set(name); + 4- Run the model: col->solve(); +*/ +#ifndef COLUMN_H +#define COLUMN_H + +#include "flash.hpp" +using namespace std; + +class column +{ +private: + // ofstream results, logf; + bool OK; + string name; + stream *F, *B, *D, *L, *V ; + int LK, HK, feed, i; + double x_B, x_D, T_b, T_d, T_f, vol, money, diam; + double Nmin, N, Rmin, Ract, tmp, Q_condens, Q_reboil; + double *alpha_1, *alpha_f, *alpha_N, *alpha_m; + flash *flasher; + void set_alpha(), first_split(), distribute(), condense(), reboil(); + double Fenske() { return log10(D->chem[LK]->n()*B->chem[HK]->n()/D->chem[HK]->n()/B->chem[LK]->n())/log10(alpha_m[LK]);} + double Underwood() {return L->n()*(D->chem[LK]->n()/L->chem[LK]->n()-alpha_m[LK]*D->chem[HK]->n()/L->chem[HK]->n())/(D->n()*(alpha_m[LK]-1));} + double Gilliland(){N=(Ract-Rmin)/(Ract+1); tmp=1-exp((1+54.4*N)*(N-1)/(11+117.2*N)/pow(N, 0.5)); return (tmp+Nmin)/(1-tmp);} + int Kirkbride() {tmp=pow(B->n()*F->chem[HK]->n()*pow(x_B/x_D,2)/F->chem[LK]->n()/D->n(), 0.206); return int(N/(tmp+1));} + +public: + // column(){P=0.0;} + // column(int, chemical*); + // void set(stream*&, stream*&, stream*&); + column(stream*, stream*, stream*); + ~column(); + double P; + void set(double, int, double, int, double); + void set( const string & n ) { name = n; } + bool solve(); + void write(); + void cost(), water(), power(); + + double get_cost ( void ); + double get_power ( void ) const { return Q_reboil/0.85-Q_condens; } + + double get_water ( void ) const { return fabs(Q_condens)/(4.185*0.85*0.25*fabs(T_d-298)); } + + int get_N ( void ) const { return (int) N; } + +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/combrx.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/combrx.cpp index 83ad673..0f30f1a 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/combrx.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/combrx.cpp @@ -1,66 +1,66 @@ -#include "combrx.hpp" -using namespace std; - -combrx::combrx ( const string & cas ) { - - // combustion.prop : - // ----------------- - CAS = cas; - - if (CAS=="64-17-5") { - nO2 = 3; - nCO2 = 2; - nH2O = 3; - } - else if (CAS=="74-82-8") { - nO2 = 2; - nCO2 = 1; - nH2O = 2; - } - else if (CAS=="1333-74-0") { - nO2 = 0.5; - nCO2 = 0; - nH2O = 1; - } - else if (CAS=="100-42-5") { - nO2 = 10; - nCO2 = 8; - nH2O = 4; - } - else if (CAS=="74-85-1") { - nO2 = 3; - nCO2 = 2; - nH2O = 2; - } - else if (CAS=="108-88-3") { - nO2 = 9; - nCO2 = 7; - nH2O = 4; - } - else if (CAS=="100-41-4") { - nO2 = 10.5; - nCO2 = 8; - nH2O = 5; - } - else if (CAS=="71-43-2") { - nO2 = 7.5; - nCO2 = 6; - nH2O = 3; - } - else { - cout << "ERROR 21" << endl; - exit(0); - } - - COMB = new chemical(CAS); - O2 = new chemical("7782-44-7"); - N2 = new chemical("7727-37-9"); - CO2 = new chemical("124-38-9"); - H2O = new chemical("7732-18-5"); - Hro = CO2->Ho*nCO2 + nH2O*(H2O->Ho - H2O->dHvap) - COMB->Ho; - LFLo = -3420.0/Hro + 0.569e-3*Hro + 0.0538e-6*pow(Hro,2) + 1.8; - LFLo = LFLo/100.0; - UFLo = 0.0063*Hro + 0.567e-6*pow(Hro, 2) + 23.5; - UFLo = UFLo/100.0; - -} +#include "combrx.hpp" +using namespace std; + +combrx::combrx ( const string & cas ) { + + // combustion.prop : + // ----------------- + CAS = cas; + + if (CAS=="64-17-5") { + nO2 = 3; + nCO2 = 2; + nH2O = 3; + } + else if (CAS=="74-82-8") { + nO2 = 2; + nCO2 = 1; + nH2O = 2; + } + else if (CAS=="1333-74-0") { + nO2 = 0.5; + nCO2 = 0; + nH2O = 1; + } + else if (CAS=="100-42-5") { + nO2 = 10; + nCO2 = 8; + nH2O = 4; + } + else if (CAS=="74-85-1") { + nO2 = 3; + nCO2 = 2; + nH2O = 2; + } + else if (CAS=="108-88-3") { + nO2 = 9; + nCO2 = 7; + nH2O = 4; + } + else if (CAS=="100-41-4") { + nO2 = 10.5; + nCO2 = 8; + nH2O = 5; + } + else if (CAS=="71-43-2") { + nO2 = 7.5; + nCO2 = 6; + nH2O = 3; + } + else { + cout << "ERROR 21" << endl; + exit(0); + } + + COMB = new chemical(CAS); + O2 = new chemical("7782-44-7"); + N2 = new chemical("7727-37-9"); + CO2 = new chemical("124-38-9"); + H2O = new chemical("7732-18-5"); + Hro = CO2->Ho*nCO2 + nH2O*(H2O->Ho - H2O->dHvap) - COMB->Ho; + LFLo = -3420.0/Hro + 0.569e-3*Hro + 0.0538e-6*pow(Hro,2) + 1.8; + LFLo = LFLo/100.0; + UFLo = 0.0063*Hro + 0.567e-6*pow(Hro, 2) + 23.5; + UFLo = UFLo/100.0; + +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/combrx.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/combrx.hpp index b57e643..02e098b 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/combrx.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/combrx.hpp @@ -1,29 +1,29 @@ -#ifndef COMBRX_H -#define COMBRX_H -#include "chemical.hpp" -#include "defines.hpp" -using namespace std; - -class combrx { - -private : - ifstream data; - bool stop; - double nO2, nCO2, nH2O; - char tmp[41]; - string CAS; - chemical *H2O, *N2, *O2, *CO2, *COMB; - double LFLo, UFLo, Hro, sum; - -public: - combrx( const string & cas ); - double O2_flow() { return (O2->M*nO2/1000.0); } //theoritical O2 flow, in kg/mol of COMB - double N2_flow(){return (0.79*O2_flow()/0.21);} //theoritical N2 flow, in kg/mol of COMB - double CO2_flow() {return (nCO2*CO2->M/1000.0);} //theoritical CO2 flow, in kg/mol of COMB - double H2O_flow() {return (nH2O*H2O->M/1000.0);} //theoritical H2O flow, in kg/mol of COMB - double LFL(double P, double T) {sum=LFLo + 0.03139/Hro*(T-298); if(sum<EPS) return EPS; else return sum;} //in %vol - double UFL(double P, double T) {sum=UFLo - 0.03139/Hro*(T-298) + 0.206*(log10(0.101325*P)+1); if(sum>1) return (1-EPS); else return sum;} //in %vol - double Hcomb(double T) {return (nCO2*CO2->dH(298,T,1)+ nH2O*H2O->dH(298,T,1)-nO2*O2->dH(298,T,1)-COMB->dH(298,T,1)+Hro);} //in kJ/mol - ~combrx(){delete H2O; delete N2; delete O2; delete CO2; delete COMB;} -}; -#endif +#ifndef COMBRX_H +#define COMBRX_H +#include "chemical.hpp" +#include "defines.hpp" +using namespace std; + +class combrx { + +private : + ifstream data; + bool stop; + double nO2, nCO2, nH2O; + char tmp[41]; + string CAS; + chemical *H2O, *N2, *O2, *CO2, *COMB; + double LFLo, UFLo, Hro, sum; + +public: + combrx( const string & cas ); + double O2_flow() { return (O2->M*nO2/1000.0); } //theoritical O2 flow, in kg/mol of COMB + double N2_flow(){return (0.79*O2_flow()/0.21);} //theoritical N2 flow, in kg/mol of COMB + double CO2_flow() {return (nCO2*CO2->M/1000.0);} //theoritical CO2 flow, in kg/mol of COMB + double H2O_flow() {return (nH2O*H2O->M/1000.0);} //theoritical H2O flow, in kg/mol of COMB + double LFL(double P, double T) {sum=LFLo + 0.03139/Hro*(T-298); if(sum<EPS) return EPS; else return sum;} //in %vol + double UFL(double P, double T) {sum=UFLo - 0.03139/Hro*(T-298) + 0.206*(log10(0.101325*P)+1); if(sum>1) return (1-EPS); else return sum;} //in %vol + double Hcomb(double T) {return (nCO2*CO2->dH(298,T,1)+ nH2O*H2O->dH(298,T,1)-nO2*O2->dH(298,T,1)-COMB->dH(298,T,1)+Hro);} //in kJ/mol + ~combrx(){delete H2O; delete N2; delete O2; delete CO2; delete COMB;} +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/defines.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/defines.hpp index 76a08ba..5f6ad7e 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/defines.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/defines.hpp @@ -1,89 +1,89 @@ -/***************************************************************************/ -/* CONFIGURATION OF THE OPERATING SYSTEM */ -/* */ -/* If Windows platform, put a "0" */ -/* If Linux, Unix or Mac platform, put a "1" */ -/* */ -#define PLATFORM 1 /* */ -/***************************************************************************/ - -#include <iostream> -#include <fstream> -#include <cmath> - -// #include <iomanip> -// #include <cstring> -// #include <cctype> -#include <cstdlib> -// #include <ctime> -using namespace std; - - -double arrondi ( double x , int n ); - - -#define ARRONDI 1 // arrondir ou pas - -#define DEBUG 0 //choose the debug (1) or normal (0) mode -#define MUTE 0 //choose 1 to avoid all screen output, 0 to have the normal display -#define EPS 1e-10 //the software "0" - -// Platform-dependant declarations -#define WIN 0 /* all versions */ -#define OTHER 1 /* Unix, Linux, SunOS, MacIntosh */ -#define MESSAGES "runtime/messages.r" -#define RUNTIME "runtime/" -#define DATA "data/" - -//useful constants -#define R 0.0821 //ideal gas constant in atm.l/mol.K -#define MAX_TEMP 3000.0 //Maximal temperature in the process -#define pi 3.14159265358979323846 //the pi number -#define MAX_DIM 30 -#define MAX_STREAM 30 -#define MAX_UNIT 30 - -//For the chemical class -#define MAX_ERROR 0 -#define MAX_WARNING 10 - -//For the secant solver -#define TOL_SECANT 1e-8 -#define MAX_ITER_SECANT 250 - -//For the bissection solver -#define TOL_BISSECTION 1e-8 -#define MAX_ITER_BISSECTION 250 - -//For the Newton solver -#define TOL_NEWTON 1e-6 -#define MAX_ITER_NEWTON 250 -#define STEP_NEWTON 1e-3 - -//For the Runge-Kutta solver -#define N_INTER 250 -#define MAX_ITER_RK N_INTER+1 - -//For the Wegstein solver -#define MIN_THETA -3.0 -#define MAX_THETA 1.0 -#define TOL_WEGSTEIN 1e-3 -#define MAX_ITER_WEGSTEIN 50 - -//For the stream flashing -#define TOL_BP 1e-3 -#define TOL_DP 1e-3 - -//For the burner -#define TOL_BURN 1e-4 - -//For the column -#define MAX_PLATES 500 -#define MIN_PLATES 1 - -//For the flash -#define TOL_FLASH 1e-2 - -//For the cost estimtiors -#define MS_2001 1094.0 -#define MS_YEAR 1139.0 +/***************************************************************************/ +/* CONFIGURATION OF THE OPERATING SYSTEM */ +/* */ +/* If Windows platform, put a "0" */ +/* If Linux, Unix or Mac platform, put a "1" */ +/* */ +#define PLATFORM 1 /* */ +/***************************************************************************/ + +#include <iostream> +#include <fstream> +#include <cmath> + +// #include <iomanip> +// #include <cstring> +// #include <cctype> +#include <cstdlib> +// #include <ctime> +using namespace std; + + +double arrondi ( double x , int n ); + + +#define ARRONDI 1 // arrondir ou pas + +#define DEBUG 0 //choose the debug (1) or normal (0) mode +#define MUTE 0 //choose 1 to avoid all screen output, 0 to have the normal display +#define EPS 1e-10 //the software "0" + +// Platform-dependant declarations +#define WIN 0 /* all versions */ +#define OTHER 1 /* Unix, Linux, SunOS, MacIntosh */ +#define MESSAGES "runtime/messages.r" +#define RUNTIME "runtime/" +#define DATA "data/" + +//useful constants +#define R 0.0821 //ideal gas constant in atm.l/mol.K +#define MAX_TEMP 3000.0 //Maximal temperature in the process +#define pi 3.14159265358979323846 //the pi number +#define MAX_DIM 30 +#define MAX_STREAM 30 +#define MAX_UNIT 30 + +//For the chemical class +#define MAX_ERROR 0 +#define MAX_WARNING 10 + +//For the secant solver +#define TOL_SECANT 1e-8 +#define MAX_ITER_SECANT 250 + +//For the bissection solver +#define TOL_BISSECTION 1e-8 +#define MAX_ITER_BISSECTION 250 + +//For the Newton solver +#define TOL_NEWTON 1e-6 +#define MAX_ITER_NEWTON 250 +#define STEP_NEWTON 1e-3 + +//For the Runge-Kutta solver +#define N_INTER 250 +#define MAX_ITER_RK N_INTER+1 + +//For the Wegstein solver +#define MIN_THETA -3.0 +#define MAX_THETA 1.0 +#define TOL_WEGSTEIN 1e-3 +#define MAX_ITER_WEGSTEIN 50 + +//For the stream flashing +#define TOL_BP 1e-3 +#define TOL_DP 1e-3 + +//For the burner +#define TOL_BURN 1e-4 + +//For the column +#define MAX_PLATES 500 +#define MIN_PLATES 1 + +//For the flash +#define TOL_FLASH 1e-2 + +//For the cost estimtiors +#define MS_2001 1094.0 +#define MS_YEAR 1139.0 diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/flash.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/flash.cpp index 930ea8f..027ad0e 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/flash.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/flash.cpp @@ -1,220 +1,220 @@ -#include "flash.hpp" -#include "bissection.cpp" -using namespace std; - -flash::flash ( stream * in , stream * out_L , stream * out_V ) { - F = in; - Fcopy = new stream("Fcopy", F->nb, F->chem); - Tin = F->T; - z = new double[F->nb]; - for ( i = 0 ; i < F->nb ; i++ ) - z[i] = F->chem[i]->n()/F->n(); - - L = out_L; - V = out_V; - success = true; - K = new double[F->nb]; - task=0; - solver = new bissection<flash>(); -} - -void flash::set(double p, double t) -{ - P=p; - T=t; - for (i=0;i<F->nb;i++) - { - if(F->chem[i]->Tc<T) K[i] = F->chem[i]->Psat(T)/P; - else K[i]=1; - } - F->set(P,T); -} - -bool flash::solve() -{ - L->purge(); - V->purge(); - f_x=F->quality(); - - if( 0.0 < f_x && f_x < 1.0) - { - - // TOTO - for ( i = 0 ; i < F->nb ; i++ ) { - if ( F->chem[i]->Tc < T ) { - F->m -= F->chem[i]->m; - F->chem[i]->m = 0; - } - } - - for ( i = 0 ; i < F->nb ; i++ ) - z[i] = F->chem[i]->n()/F->n(); - - solver->set(this, 0.0, 1.0); - - success=solver->run(); - - if (!success) - { -// if(task==0){ -// log.open(MESSAGES, ios::app); -// log<<" --> Warning <-- Solver of FLASH "<<name<<" did not converge.\n"; -// log.close();} - for (i=0;i<F->nb;i++) - { - if (T<F->chem[i]->Tc && T>F->chem[i]->Tboil(P)) {V->chem[i]->m=F->chem[i]->m; V->m+=V->chem[i]->m;} - if (T<F->chem[i]->Tc && T<=F->chem[i]->Tboil(P)) {L->chem[i]->m=F->chem[i]->m; L->m+=L->chem[i]->m;} - } - } - else - { - - V->m = x*F->n(); - L->m = F->n() - V->m; - //Distribute liquid components - for (i=0;i<L->nb;i++) - { - L->chem[i]->m = (L->m*z[i])/(1+x*(K[i]-1))*L->chem[i]->M/1000.0; - L->chem[i]->state=0; - } - - - L->m=0.0; for(i=0;i<L->nb;i++) L->m+=L->chem[i]->m; - //Distribute vapor components - for (i=0;i<V->nb;i++) - { - V->chem[i]->m = V->m*L->chem[i]->n()*K[i]/L->n()*V->chem[i]->M/1000.0; - V->chem[i]->state=1; - } - V->m=0.0; for(i=0;i<V->nb;i++) V->m+=V->chem[i]->m; - } - for(i=0;i<F->nb;i++) - if(F->chem[i]->Tc<T){V->chem[i]->m=Fcopy->chem[i]->m; V->m+=Fcopy->chem[i]->m;} - - } - else - { - /* if(task==0) - { - log.open("runtime\\messages.r", ios::app); - if (T<F->dp) log<<" --> Warning <-- Mixture in "<<name<<" can't be flashed (bp="<<F->bp<<" dp="<<F->dp<<").\n"; - log.close(); - } */ - for (i=0;i<F->nb;i++) - { - if (F->chem[i]->Tc<T || f_x>=1) {V->chem[i]->m=Fcopy->chem[i]->m; V->m+=V->chem[i]->m; } - else {L->chem[i]->m=Fcopy->chem[i]->m; L->m+=L->chem[i]->m;} - - } - success = true; - } - L->set(P,T); - V->set(P,T); - Q = 0.0; - for (i=0;i<F->nb;i++) - { - Q += L->chem[i]->dH(Tin, T, P)*L->chem[i]->n(); - Q += V->chem[i]->dH(Tin, T, P)*V->chem[i]->n(); - } - F->m=0; - for(i=0;i<Fcopy->nb;i++) {F->chem[i]->m = Fcopy->chem[i]->m; F->m+=F->chem[i]->m;} - F->set(F->P,Tin); -// if(fabs(V->m+L->m-F->m)>sqrt(EPS)) -// { -// log.open(MESSAGES, ios::app); -// log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(V->m+L->m-F->m)/F->m<<").\n"; -// log.close(); -// } -// V->write();// TOTO - // L->write(); // TOTO - - return success; -} - -double flash::f(double psy) -{ - x=psy; - f_x=0.0; - for(i=0;i<F->nb;i++) f_x += (z[i]*(1-K[i]))/(1+psy*(K[i]-1)); - return f_x; -} - -bool flash::adiabatic() -{ - task=1; - F->set(P,T); T=F->dp; - step=-5; - Q=1; - - - while (fabs(step)>0.01 && fabs(Q)>0.1) - { - T+=step; - F->set(P,T); - - for (i=0;i<F->nb;i++) - K[i] = F->chem[i]->Psat(T)/P; - - success=solve(); - - - if (Q<0 && step<0) step*=-0.5; - if (Q>0 && step>0) step*=-0.5; - } - if (fabs(Q)<0.1) return true; - else return false; -} - -void flash::write() { - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout << "\t>> "<<name; - cout << endl << "\t>> stream in : "<<F->name; - cout <<endl<<"\t>> streams out : "<<L->name<<" (liq.) "<<V->name<<" (vap.)"; - cout <<endl<<"\t>> P = "<<P<<" atm, T = "<<T<<" K"; - cout <<endl<<"\t>> Heat duty = "<<Q; - if (success==true) cout <<" kW (converge normally)"; - cout << "\n\tEND\n\n"; - cost(); - power(); - water(); -} - - -double flash::get_cost ( void ) { - vol=15.0*(L->v+V->v); - if(vol<0.3) vol=0.3; if(vol>520)vol=520; - step = 3.4974+0.4485*log10(vol)+0.1074*pow(log10(vol),2); - step = pow(10, step); - P= (P-1)*101.325/100; - f_x=pow(2.0*vol/pi, 1.0/3.0); - vol=(P+1)*f_x/(317.46*(850-0.6*(P+1)))+0.0315; - step *=(2.25+ 1.82*vol*2.2); - step = step*MS_YEAR/MS_2001; - return step; -} - -void flash::cost() { - cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} -void flash::power() { - cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; - cout << "\t>>" << Q; - cout << "\n\tEND\n\n"; -} - -double flash::get_water ( void ) { - step = (Q<0.0) ? fabs(Q)/(4.185*0.10*(Tin-298)) : 0.0; - return step; -} - -void flash::water() { - cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; - if(Q<0.0) - step= (fabs(Q)/(4.185*0.10*(Tin-298))); - else - step= 0.0; - cout << "\t>>" << step; - cout << "\n\tEND\n\n"; -} +#include "flash.hpp" +#include "bissection.cpp" +using namespace std; + +flash::flash ( stream * in , stream * out_L , stream * out_V ) { + F = in; + Fcopy = new stream("Fcopy", F->nb, F->chem); + Tin = F->T; + z = new double[F->nb]; + for ( i = 0 ; i < F->nb ; i++ ) + z[i] = F->chem[i]->n()/F->n(); + + L = out_L; + V = out_V; + success = true; + K = new double[F->nb]; + task=0; + solver = new bissection<flash>(); +} + +void flash::set(double p, double t) +{ + P=p; + T=t; + for (i=0;i<F->nb;i++) + { + if(F->chem[i]->Tc<T) K[i] = F->chem[i]->Psat(T)/P; + else K[i]=1; + } + F->set(P,T); +} + +bool flash::solve() +{ + L->purge(); + V->purge(); + f_x=F->quality(); + + if( 0.0 < f_x && f_x < 1.0) + { + + // TOTO + for ( i = 0 ; i < F->nb ; i++ ) { + if ( F->chem[i]->Tc < T ) { + F->m -= F->chem[i]->m; + F->chem[i]->m = 0; + } + } + + for ( i = 0 ; i < F->nb ; i++ ) + z[i] = F->chem[i]->n()/F->n(); + + solver->set(this, 0.0, 1.0); + + success=solver->run(); + + if (!success) + { +// if(task==0){ +// log.open(MESSAGES, ios::app); +// log<<" --> Warning <-- Solver of FLASH "<<name<<" did not converge.\n"; +// log.close();} + for (i=0;i<F->nb;i++) + { + if (T<F->chem[i]->Tc && T>F->chem[i]->Tboil(P)) {V->chem[i]->m=F->chem[i]->m; V->m+=V->chem[i]->m;} + if (T<F->chem[i]->Tc && T<=F->chem[i]->Tboil(P)) {L->chem[i]->m=F->chem[i]->m; L->m+=L->chem[i]->m;} + } + } + else + { + + V->m = x*F->n(); + L->m = F->n() - V->m; + //Distribute liquid components + for (i=0;i<L->nb;i++) + { + L->chem[i]->m = (L->m*z[i])/(1+x*(K[i]-1))*L->chem[i]->M/1000.0; + L->chem[i]->state=0; + } + + + L->m=0.0; for(i=0;i<L->nb;i++) L->m+=L->chem[i]->m; + //Distribute vapor components + for (i=0;i<V->nb;i++) + { + V->chem[i]->m = V->m*L->chem[i]->n()*K[i]/L->n()*V->chem[i]->M/1000.0; + V->chem[i]->state=1; + } + V->m=0.0; for(i=0;i<V->nb;i++) V->m+=V->chem[i]->m; + } + for(i=0;i<F->nb;i++) + if(F->chem[i]->Tc<T){V->chem[i]->m=Fcopy->chem[i]->m; V->m+=Fcopy->chem[i]->m;} + + } + else + { + /* if(task==0) + { + log.open("runtime\\messages.r", ios::app); + if (T<F->dp) log<<" --> Warning <-- Mixture in "<<name<<" can't be flashed (bp="<<F->bp<<" dp="<<F->dp<<").\n"; + log.close(); + } */ + for (i=0;i<F->nb;i++) + { + if (F->chem[i]->Tc<T || f_x>=1) {V->chem[i]->m=Fcopy->chem[i]->m; V->m+=V->chem[i]->m; } + else {L->chem[i]->m=Fcopy->chem[i]->m; L->m+=L->chem[i]->m;} + + } + success = true; + } + L->set(P,T); + V->set(P,T); + Q = 0.0; + for (i=0;i<F->nb;i++) + { + Q += L->chem[i]->dH(Tin, T, P)*L->chem[i]->n(); + Q += V->chem[i]->dH(Tin, T, P)*V->chem[i]->n(); + } + F->m=0; + for(i=0;i<Fcopy->nb;i++) {F->chem[i]->m = Fcopy->chem[i]->m; F->m+=F->chem[i]->m;} + F->set(F->P,Tin); +// if(fabs(V->m+L->m-F->m)>sqrt(EPS)) +// { +// log.open(MESSAGES, ios::app); +// log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(V->m+L->m-F->m)/F->m<<").\n"; +// log.close(); +// } +// V->write();// TOTO + // L->write(); // TOTO + + return success; +} + +double flash::f(double psy) +{ + x=psy; + f_x=0.0; + for(i=0;i<F->nb;i++) f_x += (z[i]*(1-K[i]))/(1+psy*(K[i]-1)); + return f_x; +} + +bool flash::adiabatic() +{ + task=1; + F->set(P,T); T=F->dp; + step=-5; + Q=1; + + + while (fabs(step)>0.01 && fabs(Q)>0.1) + { + T+=step; + F->set(P,T); + + for (i=0;i<F->nb;i++) + K[i] = F->chem[i]->Psat(T)/P; + + success=solve(); + + + if (Q<0 && step<0) step*=-0.5; + if (Q>0 && step>0) step*=-0.5; + } + if (fabs(Q)<0.1) return true; + else return false; +} + +void flash::write() { + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout << "\t>> "<<name; + cout << endl << "\t>> stream in : "<<F->name; + cout <<endl<<"\t>> streams out : "<<L->name<<" (liq.) "<<V->name<<" (vap.)"; + cout <<endl<<"\t>> P = "<<P<<" atm, T = "<<T<<" K"; + cout <<endl<<"\t>> Heat duty = "<<Q; + if (success==true) cout <<" kW (converge normally)"; + cout << "\n\tEND\n\n"; + cost(); + power(); + water(); +} + + +double flash::get_cost ( void ) { + vol=15.0*(L->v+V->v); + if(vol<0.3) vol=0.3; if(vol>520)vol=520; + step = 3.4974+0.4485*log10(vol)+0.1074*pow(log10(vol),2); + step = pow(10, step); + P= (P-1)*101.325/100; + f_x=pow(2.0*vol/pi, 1.0/3.0); + vol=(P+1)*f_x/(317.46*(850-0.6*(P+1)))+0.0315; + step *=(2.25+ 1.82*vol*2.2); + step = step*MS_YEAR/MS_2001; + return step; +} + +void flash::cost() { + cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} +void flash::power() { + cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; + cout << "\t>>" << Q; + cout << "\n\tEND\n\n"; +} + +double flash::get_water ( void ) { + step = (Q<0.0) ? fabs(Q)/(4.185*0.10*(Tin-298)) : 0.0; + return step; +} + +void flash::water() { + cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; + if(Q<0.0) + step= (fabs(Q)/(4.185*0.10*(Tin-298))); + else + step= 0.0; + cout << "\t>>" << step; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/flash.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/flash.hpp index 29bc250..b6cdb41 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/flash.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/flash.hpp @@ -1,55 +1,55 @@ -/* -This unit takes operating P and T, and indexes of streams. It applies -the Rachford-Rice procedure to solve the isothermal flash problem -(ref : Seader & Henley). - -Structure in the .process file: -flash {name} {pressure} {temperature} {index of input stream} {index of output liquid and output vapor} - -How to use: - 1- Call the constructor : flash1 = new flash(in, out_L, out_V); //in is the feed, out_L is the liquid output and out_V is the vapor output - 2- Set P and T: flash1->set(P,T); - 3- Set the name: flash1->set(name); - 4a- Perform an isothermal flash : flash1->solve(); - 4b- Perform an adiabatic flash: flash1->adiabatic(); -*/ -#ifndef FLASH_H -#define FLASH_H - -#include "stream.hpp" -#include "bissection.hpp" -using namespace std; - -class flash { -private: - bool success; - bissection<flash> *solver; - // ofstream log, results; -// char name[31], filename[41]; //name of the unit - - string name; - - int i, task; //task=0: isothermal flash; task=1:adiabatic flash - stream *F, *Fcopy; //pointer to the input stream - stream *L, *V; //pointers to liquid and vapor output streams - double f_x, x, *K, *z; //pressure (given) and temperature (given) - double Q, Tin, step, vol; //required power, in kW - -public: - flash(){P=0.0; T=0.0;} - flash(stream*, stream*, stream*); //defines the connectivities of this unit - ~flash(){delete Fcopy; delete [] K; delete [] z; delete solver;} - double P ,T; - void set(double, double); - void set( const string & n ) { name = n; } - bool solve(); //applies the Rachford-Rice procedure - bool adiabatic(); //adiabatic isobaric flash - double f(double); //returns the function to the solver - void write(); - double get_water ( void ); - double get_cost ( void ); - - double get_power ( void ) const { return Q; } - void cost(), water(), power(); -}; -#endif +/* +This unit takes operating P and T, and indexes of streams. It applies +the Rachford-Rice procedure to solve the isothermal flash problem +(ref : Seader & Henley). + +Structure in the .process file: +flash {name} {pressure} {temperature} {index of input stream} {index of output liquid and output vapor} + +How to use: + 1- Call the constructor : flash1 = new flash(in, out_L, out_V); //in is the feed, out_L is the liquid output and out_V is the vapor output + 2- Set P and T: flash1->set(P,T); + 3- Set the name: flash1->set(name); + 4a- Perform an isothermal flash : flash1->solve(); + 4b- Perform an adiabatic flash: flash1->adiabatic(); +*/ +#ifndef FLASH_H +#define FLASH_H + +#include "stream.hpp" +#include "bissection.hpp" +using namespace std; + +class flash { +private: + bool success; + bissection<flash> *solver; + // ofstream log, results; +// char name[31], filename[41]; //name of the unit + + string name; + + int i, task; //task=0: isothermal flash; task=1:adiabatic flash + stream *F, *Fcopy; //pointer to the input stream + stream *L, *V; //pointers to liquid and vapor output streams + double f_x, x, *K, *z; //pressure (given) and temperature (given) + double Q, Tin, step, vol; //required power, in kW + +public: + flash(){P=0.0; T=0.0;} + flash(stream*, stream*, stream*); //defines the connectivities of this unit + ~flash(){delete Fcopy; delete [] K; delete [] z; delete solver;} + double P ,T; + void set(double, double); + void set( const string & n ) { name = n; } + bool solve(); //applies the Rachford-Rice procedure + bool adiabatic(); //adiabatic isobaric flash + double f(double); //returns the function to the solver + void write(); + double get_water ( void ); + double get_cost ( void ); + + double get_power ( void ) const { return Q; } + void cost(), water(), power(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/heatx.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/heatx.cpp index fd8942e..3c23822 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/heatx.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/heatx.cpp @@ -1,146 +1,146 @@ -#include "heatx.hpp" -#include "bissection.cpp" - -heatx::heatx(bool m, stream* s1, stream* s2) -{ - in = s1; - out = s2; - out->m=0; - for(i=0;i<in->nb;i++) - { - out->chem[i]->m=in->chem[i]->m; - out->m+=out->chem[i]->m; - } - solver = new bissection<heatx>(); - mode = m; - success = true; -} - -void heatx::set(double d1, double d2) -{ - if(mode==0) T=d1; - if(mode==1) Q=d1; - eta = d2; -} - -bool heatx::solve() -{ - if(mode==0) - { - Q = 0.0; - out->set(in->P, T); - // out->write(); // WRITE TOTO - for(i=0;i<in->nb;i++) - Q+=out->chem[i]->dH(in->T, out->T, in->P)*out->chem[i]->n(); - if(eta>EPS) - Qreal = Q/eta; - else { - Qreal=Q; - success=false; - } - } - if(mode==1) - { - Qreal = eta*Q; - min = in->T; - max = 2000; - solver->set(this, min, max); - success = solver->run(); - out->set(in->P, T); - //out->write(); // WRITE TOTO - } - return success; -} - - -double heatx::f(double x) -{ - T=x; - max = Qreal; - for(i=0;i<in->nb;i++) - max -= out->chem[i]->dH(in->T, T, in->P)*out->chem[i]->n(); - return max; -} - -void heatx::write() -{ - - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout << "\t>> " << name; - cout << endl << "\t>> stream in: " << in->name << " T = " << in->T <<" K"; - cout << endl << "\t>> stream out: " << out->name << " T = " << out->T <<" K"; - if (mode==0) - cout<<endl<<"\t>> Heat duty : "<<Qreal<<" kW"; - if (mode==1) - cout<<endl<<"\t>> Heat duty : "<<Q<<" kW"; - if (success) - cout<<endl<<"\t>> Heat losses "<<fabs(Qreal-Q)<<" kW (converged normally)"; - cout << "\n\tEND\n\n"; - - cost(); - power(); - water(); -} - - - -double heatx::get_cost ( void ) { - if(mode==1) min=fabs(Q)/0.225/(eta)/fabs(out->T-in->T); - if(mode==0) min=fabs(Qreal)/0.25/(eta)/fabs(out->T-in->T); - if(min<10) min=10; if(min>1000) min=1000; - max = 4.3247-0.303*log10(min)+0.1634*pow(log10(min),2); - T=in->P; - T = (T-1)*1.01325; - if (fabs(T)<EPS) T=0.1; if(T>100) T=100; - min=0.03881-0.11272*log10(T)+0.08183*pow(log10(T),2); - min=pow(10, min); - max = (1.63+1.66*2.5*min)*pow(10, max); - max = max*MS_YEAR/MS_2001; - return max; -} - - -void heatx::cost() -{ - cout << setprecision(5); - cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} - - - -double heatx::get_water ( void ) -{ - max = (Q<0.0) ? fabs(Q)/(4.185*0.10*(out->T-298)) : 0.0; - return max; -} - - -void heatx::water() -{ - if(Q<0.0) max = fabs(Q)/(4.185*0.10*(out->T-298)); - else max = 0.0; - cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; - cout << "\t>>" << max; - cout << "\n\tEND\n\n"; - -} - -double heatx::get_power ( void ) { - max = (mode) ? Q : Qreal; - if (max>EPS) - return max; - return 0.0; -} - -void heatx::power() -{ - if(mode==0) max = Qreal; - if(mode==1) max = Q; - - cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; - if(max>EPS) cout<< "\t>>" << max; - else cout<< "\t>>" << 0; - cout << "\n\tEND\n\n"; -} +#include "heatx.hpp" +#include "bissection.cpp" + +heatx::heatx(bool m, stream* s1, stream* s2) +{ + in = s1; + out = s2; + out->m=0; + for(i=0;i<in->nb;i++) + { + out->chem[i]->m=in->chem[i]->m; + out->m+=out->chem[i]->m; + } + solver = new bissection<heatx>(); + mode = m; + success = true; +} + +void heatx::set(double d1, double d2) +{ + if(mode==0) T=d1; + if(mode==1) Q=d1; + eta = d2; +} + +bool heatx::solve() +{ + if(mode==0) + { + Q = 0.0; + out->set(in->P, T); + // out->write(); // WRITE TOTO + for(i=0;i<in->nb;i++) + Q+=out->chem[i]->dH(in->T, out->T, in->P)*out->chem[i]->n(); + if(eta>EPS) + Qreal = Q/eta; + else { + Qreal=Q; + success=false; + } + } + if(mode==1) + { + Qreal = eta*Q; + min = in->T; + max = 2000; + solver->set(this, min, max); + success = solver->run(); + out->set(in->P, T); + //out->write(); // WRITE TOTO + } + return success; +} + + +double heatx::f(double x) +{ + T=x; + max = Qreal; + for(i=0;i<in->nb;i++) + max -= out->chem[i]->dH(in->T, T, in->P)*out->chem[i]->n(); + return max; +} + +void heatx::write() +{ + + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout << "\t>> " << name; + cout << endl << "\t>> stream in: " << in->name << " T = " << in->T <<" K"; + cout << endl << "\t>> stream out: " << out->name << " T = " << out->T <<" K"; + if (mode==0) + cout<<endl<<"\t>> Heat duty : "<<Qreal<<" kW"; + if (mode==1) + cout<<endl<<"\t>> Heat duty : "<<Q<<" kW"; + if (success) + cout<<endl<<"\t>> Heat losses "<<fabs(Qreal-Q)<<" kW (converged normally)"; + cout << "\n\tEND\n\n"; + + cost(); + power(); + water(); +} + + + +double heatx::get_cost ( void ) { + if(mode==1) min=fabs(Q)/0.225/(eta)/fabs(out->T-in->T); + if(mode==0) min=fabs(Qreal)/0.25/(eta)/fabs(out->T-in->T); + if(min<10) min=10; if(min>1000) min=1000; + max = 4.3247-0.303*log10(min)+0.1634*pow(log10(min),2); + T=in->P; + T = (T-1)*1.01325; + if (fabs(T)<EPS) T=0.1; if(T>100) T=100; + min=0.03881-0.11272*log10(T)+0.08183*pow(log10(T),2); + min=pow(10, min); + max = (1.63+1.66*2.5*min)*pow(10, max); + max = max*MS_YEAR/MS_2001; + return max; +} + + +void heatx::cost() +{ + cout << setprecision(5); + cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} + + + +double heatx::get_water ( void ) +{ + max = (Q<0.0) ? fabs(Q)/(4.185*0.10*(out->T-298)) : 0.0; + return max; +} + + +void heatx::water() +{ + if(Q<0.0) max = fabs(Q)/(4.185*0.10*(out->T-298)); + else max = 0.0; + cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; + cout << "\t>>" << max; + cout << "\n\tEND\n\n"; + +} + +double heatx::get_power ( void ) { + max = (mode) ? Q : Qreal; + if (max>EPS) + return max; + return 0.0; +} + +void heatx::power() +{ + if(mode==0) max = Qreal; + if(mode==1) max = Q; + + cout << "WRITE FILE " << RUNTIME << name << ".power" << " :\n\tBEGIN\n"; + if(max>EPS) cout<< "\t>>" << max; + else cout<< "\t>>" << 0; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/heatx.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/heatx.hpp index d3b7dff..f9854ad 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/heatx.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/heatx.hpp @@ -1,49 +1,49 @@ -/* -This unit performs the heating of a stream (mode 0) or the heat -exchange to a stream (mode 1). -(ref : McCabe, Smith & Harriott) - -Structure in the .process file: -mode 0 : heatx {name} 0 {index of input stream} {index of output stream} {T out} {efficiency} //efficiency is a fraction between 0 and 1 -mode 1 : heatx {name} 1 {index of input stream} {index of output stream} {Q} {efficiency} //Q is the heat flow in kW -How to use: - 1- Call the constructor: heat = new heatx(mode, in, out); - 2- Set the operating conditions : heat->set(T_out, eta); //mode 0 - or : heat->set(Q, eta); //mode 1 - 3- Set the name of the unit: heat->set(name); - 4- Solve: bool=heat->solve(); -*/ -#ifndef HEATX_H -#define HEATX_H - -#include "stream.hpp" -#include "bissection.hpp" -using namespace std; - -class heatx -{ -private: - int i; - bool success, mode; - bissection<heatx> *solver; - // ofstream logf, results; - double min, max; - string name; - stream *in, *out; //streams of the unit - double eta, Q, Qreal, T; - -public: - heatx(){} - heatx(bool, stream*, stream*); //defines the connectivities of this unit - ~heatx(){delete solver;} - void set(double, double); - void set(const string & n) { name = n; } - double f(double); - bool solve(); - void write(); - void power(), water(), cost(); - double get_cost(); - double get_power(); - double get_water(); -}; -#endif +/* +This unit performs the heating of a stream (mode 0) or the heat +exchange to a stream (mode 1). +(ref : McCabe, Smith & Harriott) + +Structure in the .process file: +mode 0 : heatx {name} 0 {index of input stream} {index of output stream} {T out} {efficiency} //efficiency is a fraction between 0 and 1 +mode 1 : heatx {name} 1 {index of input stream} {index of output stream} {Q} {efficiency} //Q is the heat flow in kW +How to use: + 1- Call the constructor: heat = new heatx(mode, in, out); + 2- Set the operating conditions : heat->set(T_out, eta); //mode 0 + or : heat->set(Q, eta); //mode 1 + 3- Set the name of the unit: heat->set(name); + 4- Solve: bool=heat->solve(); +*/ +#ifndef HEATX_H +#define HEATX_H + +#include "stream.hpp" +#include "bissection.hpp" +using namespace std; + +class heatx +{ +private: + int i; + bool success, mode; + bissection<heatx> *solver; + // ofstream logf, results; + double min, max; + string name; + stream *in, *out; //streams of the unit + double eta, Q, Qreal, T; + +public: + heatx(){} + heatx(bool, stream*, stream*); //defines the connectivities of this unit + ~heatx(){delete solver;} + void set(double, double); + void set(const string & n) { name = n; } + double f(double); + bool solve(); + void write(); + void power(), water(), cost(); + double get_cost(); + double get_power(); + double get_water(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/mix.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/mix.cpp index dc02dc7..00202a2 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/mix.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/mix.cpp @@ -1,80 +1,80 @@ -#include "mix.hpp" -#include "bissection.cpp" -using namespace std; - -mix::mix ( int n , stream ** s1 , stream * s2 ) { - nb_in=n; - in = s1; - out= s2; - success = true; - solver = new bissection<mix>(); -} - -bool mix::solve() -{ - //Mass balance - out->m=0; - out->purge(); - for (j=0; j<out->nb;j++) - for (i=0;i<nb_in;i++) if(in[i]->chem[j]->m>EPS) - { - out->chem[j]->m+=in[i]->chem[j]->m; - out->m+=in[i]->chem[j]->m; - } - //Find the temperature - double max=0.0; double min=1e6; - for(i=0;i<nb_in;i++) - for(j=0;j<out->nb;j++) - { - if(in[i]->chem[j]->T>max && in[i]->chem[j]->m>EPS) max=in[i]->chem[j]->T; - if(in[i]->chem[j]->T<min && in[i]->chem[j]->m>EPS) min=in[i]->chem[j]->T; - } - if(fabs(max-min)<EPS) T=max; - else - { - solver->set(this, min, max); - success = solver->run(); - } - out->set(P,T); - // if (success==false) - // { - // log.open(MESSAGES, ios::app); - // log<<" --> Warning <-- Solver of "<<name<<" did not converge.\n"; - // log.close(); - // } - // min = 0; - // for(i=0;i<nb_in;i++) - // min+=in[i]->m; - // if(fabs(min-out->m)>sqrt(EPS)) - // { - // log.open(MESSAGES, ios::app); - // log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(min-out->m)/min<<").\n"; - // log.close(); - // } - - // out->write(); // WRITE TOTO - return success; -} - -double mix::f(double x) -{ - T=x; - double energy=0.0; //in kW - for (j=0; j<out->nb;j++) - for (i=0;i<nb_in;i++) - energy += in[i]->chem[j]->dH(in[i]->T, T, P)*in[i]->chem[j]->n()/1000; - return energy; -} - -void mix::write() { - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout << "\t>> " << name - << endl << "\t>> streams in: "; - for ( int i = 0 ; i < nb_in ; i++ ) - cout << in[i]->name << " "; - cout << endl << "\t>> stream out: " << out->name; - cout <<endl << "\t>> P = " << P << " atm, T = " << T; - if (success) - cout << " K (converged normally)"; - cout << "\n\tEND\n\n"; -} +#include "mix.hpp" +#include "bissection.cpp" +using namespace std; + +mix::mix ( int n , stream ** s1 , stream * s2 ) { + nb_in=n; + in = s1; + out= s2; + success = true; + solver = new bissection<mix>(); +} + +bool mix::solve() +{ + //Mass balance + out->m=0; + out->purge(); + for (j=0; j<out->nb;j++) + for (i=0;i<nb_in;i++) if(in[i]->chem[j]->m>EPS) + { + out->chem[j]->m+=in[i]->chem[j]->m; + out->m+=in[i]->chem[j]->m; + } + //Find the temperature + double max=0.0; double min=1e6; + for(i=0;i<nb_in;i++) + for(j=0;j<out->nb;j++) + { + if(in[i]->chem[j]->T>max && in[i]->chem[j]->m>EPS) max=in[i]->chem[j]->T; + if(in[i]->chem[j]->T<min && in[i]->chem[j]->m>EPS) min=in[i]->chem[j]->T; + } + if(fabs(max-min)<EPS) T=max; + else + { + solver->set(this, min, max); + success = solver->run(); + } + out->set(P,T); + // if (success==false) + // { + // log.open(MESSAGES, ios::app); + // log<<" --> Warning <-- Solver of "<<name<<" did not converge.\n"; + // log.close(); + // } + // min = 0; + // for(i=0;i<nb_in;i++) + // min+=in[i]->m; + // if(fabs(min-out->m)>sqrt(EPS)) + // { + // log.open(MESSAGES, ios::app); + // log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(min-out->m)/min<<").\n"; + // log.close(); + // } + + // out->write(); // WRITE TOTO + return success; +} + +double mix::f(double x) +{ + T=x; + double energy=0.0; //in kW + for (j=0; j<out->nb;j++) + for (i=0;i<nb_in;i++) + energy += in[i]->chem[j]->dH(in[i]->T, T, P)*in[i]->chem[j]->n()/1000; + return energy; +} + +void mix::write() { + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout << "\t>> " << name + << endl << "\t>> streams in: "; + for ( int i = 0 ; i < nb_in ; i++ ) + cout << in[i]->name << " "; + cout << endl << "\t>> stream out: " << out->name; + cout <<endl << "\t>> P = " << P << " atm, T = " << T; + if (success) + cout << " K (converged normally)"; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/mix.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/mix.hpp index 6d4ee0f..85b8d77 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/mix.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/mix.hpp @@ -1,44 +1,44 @@ -/* -This unit takes more than two input streams and merge them in one -output stream. The pressure must be specified by the user, and the -temperature of the output stream is computed. - -Structure in the .process file: -mix {name} {pressure} {nb_in} {indexes of input streams} {index of output stream} - -How to use: - 1- Call the constructor: mix1 = new mix(nb_in, list1_in, out); - 2- Set the operating pressure : mix1->set(P); - 3- Set the name of the unit: mix1->set(name); - 4- Solve: bool=mix1->solve(); -*/ -#ifndef MIX_H -#define MIX_H - -#include "stream.hpp" -#include "bissection.hpp" -using namespace std; - -class mix { - private: - int i, j; - bool success; - bissection<mix> *solver; - string name; - int nb_in; //number of input streams - stream **in; //list pointers to input streams - stream *out; //pointer to output stream - // double min, max; - - public: - double P, T; //pressure (given) and temperature (unknown) - mix(){P=0.0;} - mix(int, stream**, stream*); //defines the connectivities of this unit - ~mix(){delete solver;} - void set(double p) {P=p;} - void set ( const string & n ) { name = n; } - double f(double); //returns the function to the solver - bool solve(); //finds the temperature and computes mass balance - void write(); -}; -#endif +/* +This unit takes more than two input streams and merge them in one +output stream. The pressure must be specified by the user, and the +temperature of the output stream is computed. + +Structure in the .process file: +mix {name} {pressure} {nb_in} {indexes of input streams} {index of output stream} + +How to use: + 1- Call the constructor: mix1 = new mix(nb_in, list1_in, out); + 2- Set the operating pressure : mix1->set(P); + 3- Set the name of the unit: mix1->set(name); + 4- Solve: bool=mix1->solve(); +*/ +#ifndef MIX_H +#define MIX_H + +#include "stream.hpp" +#include "bissection.hpp" +using namespace std; + +class mix { + private: + int i, j; + bool success; + bissection<mix> *solver; + string name; + int nb_in; //number of input streams + stream **in; //list pointers to input streams + stream *out; //pointer to output stream + // double min, max; + + public: + double P, T; //pressure (given) and temperature (unknown) + mix(){P=0.0;} + mix(int, stream**, stream*); //defines the connectivities of this unit + ~mix(){delete solver;} + void set(double p) {P=p;} + void set ( const string & n ) { name = n; } + double f(double); //returns the function to the solver + bool solve(); //finds the temperature and computes mass balance + void write(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/pfr.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/pfr.cpp index aa12b2f..10583ce 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/pfr.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/pfr.cpp @@ -1,172 +1,172 @@ -#include "pfr.hpp" -#include "RungeKutta.cpp" -using namespace std; - -pfr::pfr ( stream * s1 , stream * s2 , double ** t , int nb_r , reaction ** rr , double u , double ta ) { - - F = s2; - F->m=0; - P=s1->P; - for ( i = 0 ; i < s1->nb ; i++ ) { - F->chem[i]->m = s1->chem[i]->m; - F->m+=F->chem[i]->m; - } - F->set(s1->P, s1->T); - m_in=F->m; - a = t; - rx = rr; - n=nb_r; - m= F->nb; - U=u; - Ta=ta; - T = F->T; - C = new double[m]; - y = new double[m+1]; - r=new double[n]; - OK=true; - explode=true; - solver = new RungeKutta<pfr>(m+1); -} - -pfr::~pfr() { - delete [] r; - delete [] C; - delete [] y; - delete solver; -} - -bool pfr::run() { - - for ( i = 0 ; i < m ; i++ ) - y[i]=F->chem[i]->n(); - - y[m]=T; - - solver->set ( this , y , 0.0 , L ); - - dL=solver->dx(); - - OK=solver->run(); - - sum = F->m; - F->m = 0; - - for ( i = 0 ; i < m ; i++ ) - F->m+=F->chem[i]->m; - for ( i = 0 ; i < m ; i++ ) - F->chem[i]->m *= sum/F->m; - // if (OK) - //mass balance! - if ( fabs(m_in-F->m) > EPS || !explode ) - OK=false; - - return OK; -} - -double pfr::f ( int eq , double l , double * y ) { - - - sum=F->m; - F->m=0; - for(i=0; i<m;i++) - { - if(y[i]<0) y[i]=0; - F->chem[i]->m = y[i]*F->chem[i]->M/1000.0; - F->m+=F->chem[i]->m; - } - - - for(i=0; i<m;i++) - F->chem[i]->m *= sum/F->m; - - - - F->m=sum; - T=y[m]; - if(T>MAX_TEMP) - { - cout << "ERROR 11\n\n"; - exit(0); - } - - - for(i=0; i<m;i++) - C[i]=F->chem[i]->n()/F->v; - - for(j=0;j<n;j++) - r[j] = rx[j]->rate(T,C); - - if(0<=eq && eq<m) //return dFi/dL - { - tmp=0.0; - for(j=0;j<n;j++) tmp+=a[eq][j]*r[j]; - tmp *= (pi*D*D/4.0); - } - - - - if(eq==m) //return dT/dL - { - - - F->set(F->P,T); - - tmp=0.0; - for(j=0;j<n;j++) - tmp -= r[j]*rx[j]->dHr(T); - - - tmp *= (pi*D*D/4.0); - - - tmp += (pi*D)*U*(Ta-T); - - - tmp1=0.0; - for(i=0;i<m;i++) { - tmp1+= y[i]*F->chem[i]->Cp()*0.001; - } - tmp /= tmp1; - - if(fabs(tmp*dL)>500.0) - { - cout << "ERROR 13\n\n"; - exit(0); - } - } - - return tmp; -} - - - -double pfr::get_cost ( void ) { - dL=L*pi*pow(D,2)/4.0; - if(dL<0.3) dL=0.3; if(dL>520) dL=520; - sum = 3.4974+0.4485*log10(dL)+0.1074*pow(log10(dL),2); - sum = pow(10, sum); - P= (P-1)*101.325/100; - dL=(P+1)*D/(317.46*(850-0.6*(P+1)))+0.0315; - sum *=(2.25+ 1.82*dL*4.2); - sum = sum*MS_YEAR/MS_2001; - return sum; -} - -double pfr::get_water() { - sum = (U>EPS && T>Ta) ? U*L*pi*pow(D,2)/4*(T-Ta)/4.185/25.0 : 0.0; - return sum; -} - -void pfr::cost() { - cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} - -void pfr::water() { - cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; - if (U>EPS && T>Ta) sum = (U*L*pi*pow(D,2)/4*(T-Ta)/4.185/25.0); - else sum = 0.0; - cout << "\t>>" << sum; - cout << "\n\tEND\n\n"; -} +#include "pfr.hpp" +#include "RungeKutta.cpp" +using namespace std; + +pfr::pfr ( stream * s1 , stream * s2 , double ** t , int nb_r , reaction ** rr , double u , double ta ) { + + F = s2; + F->m=0; + P=s1->P; + for ( i = 0 ; i < s1->nb ; i++ ) { + F->chem[i]->m = s1->chem[i]->m; + F->m+=F->chem[i]->m; + } + F->set(s1->P, s1->T); + m_in=F->m; + a = t; + rx = rr; + n=nb_r; + m= F->nb; + U=u; + Ta=ta; + T = F->T; + C = new double[m]; + y = new double[m+1]; + r=new double[n]; + OK=true; + explode=true; + solver = new RungeKutta<pfr>(m+1); +} + +pfr::~pfr() { + delete [] r; + delete [] C; + delete [] y; + delete solver; +} + +bool pfr::run() { + + for ( i = 0 ; i < m ; i++ ) + y[i]=F->chem[i]->n(); + + y[m]=T; + + solver->set ( this , y , 0.0 , L ); + + dL=solver->dx(); + + OK=solver->run(); + + sum = F->m; + F->m = 0; + + for ( i = 0 ; i < m ; i++ ) + F->m+=F->chem[i]->m; + for ( i = 0 ; i < m ; i++ ) + F->chem[i]->m *= sum/F->m; + // if (OK) + //mass balance! + if ( fabs(m_in-F->m) > EPS || !explode ) + OK=false; + + return OK; +} + +double pfr::f ( int eq , double l , double * y ) { + + + sum=F->m; + F->m=0; + for(i=0; i<m;i++) + { + if(y[i]<0) y[i]=0; + F->chem[i]->m = y[i]*F->chem[i]->M/1000.0; + F->m+=F->chem[i]->m; + } + + + for(i=0; i<m;i++) + F->chem[i]->m *= sum/F->m; + + + + F->m=sum; + T=y[m]; + if(T>MAX_TEMP) + { + cout << "ERROR 11\n\n"; + exit(0); + } + + + for(i=0; i<m;i++) + C[i]=F->chem[i]->n()/F->v; + + for(j=0;j<n;j++) + r[j] = rx[j]->rate(T,C); + + if(0<=eq && eq<m) //return dFi/dL + { + tmp=0.0; + for(j=0;j<n;j++) tmp+=a[eq][j]*r[j]; + tmp *= (pi*D*D/4.0); + } + + + + if(eq==m) //return dT/dL + { + + + F->set(F->P,T); + + tmp=0.0; + for(j=0;j<n;j++) + tmp -= r[j]*rx[j]->dHr(T); + + + tmp *= (pi*D*D/4.0); + + + tmp += (pi*D)*U*(Ta-T); + + + tmp1=0.0; + for(i=0;i<m;i++) { + tmp1+= y[i]*F->chem[i]->Cp()*0.001; + } + tmp /= tmp1; + + if(fabs(tmp*dL)>500.0) + { + cout << "ERROR 13\n\n"; + exit(0); + } + } + + return tmp; +} + + + +double pfr::get_cost ( void ) { + dL=L*pi*pow(D,2)/4.0; + if(dL<0.3) dL=0.3; if(dL>520) dL=520; + sum = 3.4974+0.4485*log10(dL)+0.1074*pow(log10(dL),2); + sum = pow(10, sum); + P= (P-1)*101.325/100; + dL=(P+1)*D/(317.46*(850-0.6*(P+1)))+0.0315; + sum *=(2.25+ 1.82*dL*4.2); + sum = sum*MS_YEAR/MS_2001; + return sum; +} + +double pfr::get_water() { + sum = (U>EPS && T>Ta) ? U*L*pi*pow(D,2)/4*(T-Ta)/4.185/25.0 : 0.0; + return sum; +} + +void pfr::cost() { + cout << "WRITE FILE " << RUNTIME << name << ".cost" << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} + +void pfr::water() { + cout << "WRITE FILE " << RUNTIME << name << ".water" << " :\n\tBEGIN\n"; + if (U>EPS && T>Ta) sum = (U*L*pi*pow(D,2)/4*(T-Ta)/4.185/25.0); + else sum = 0.0; + cout << "\t>>" << sum; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/pfr.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/pfr.hpp index 9746a50..a8f49a7 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/pfr.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/pfr.hpp @@ -1,36 +1,36 @@ -#ifndef PFR_H -#define PFR_H - -#include "reaction.hpp" -#include "RungeKutta.hpp" -#include "stream.hpp" -using namespace std; - -class pfr { -private: - // terminator *term; - // ofstream results; - string name; - bool OK, explode; - int i ,j, n, m; - double L,D,dL, U, Ta, m_in, sum, P; - stream *F; - double **a, *C, T, *y, *r, tmp, tmp1; - reaction **rx; - RungeKutta<pfr> *solver; - -public: - // pfr(){}; - pfr ( stream * , stream * , double ** , int , reaction ** , double , double ); - void set ( const string & n ) { name = n; } - void set(double l, double d) {L=l; D=d;} - bool run(); - void water(); - void cost(); - double get_cost ( void ); - double get_water ( void ); - - double f(int, double, double*); - ~pfr(); -}; -#endif +#ifndef PFR_H +#define PFR_H + +#include "reaction.hpp" +#include "RungeKutta.hpp" +#include "stream.hpp" +using namespace std; + +class pfr { +private: + // terminator *term; + // ofstream results; + string name; + bool OK, explode; + int i ,j, n, m; + double L,D,dL, U, Ta, m_in, sum, P; + stream *F; + double **a, *C, T, *y, *r, tmp, tmp1; + reaction **rx; + RungeKutta<pfr> *solver; + +public: + // pfr(){}; + pfr ( stream * , stream * , double ** , int , reaction ** , double , double ); + void set ( const string & n ) { name = n; } + void set(double l, double d) {L=l; D=d;} + bool run(); + void water(); + void cost(); + double get_cost ( void ); + double get_water ( void ); + + double f(int, double, double*); + ~pfr(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/profitability.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/profitability.cpp index 902f30d..3617b30 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/profitability.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/profitability.cpp @@ -1,138 +1,138 @@ -#include "profitability.hpp" -#include "secant.cpp" -using namespace std; - -bool profitability::run ( double * y ) -{ - OK=true; - - // cout<<setiosflags(ios::fixed); - // cout<<endl<<endl<<" PROFITABILITY ANALYSIS"<<endl; - // cout<<endl<<setprecision(1)<<" Return on investment (%)= "<<ROI()*100.0; - // cout<<endl<<" Rate of return (%)= "<<RR()*100.0; // y[10] - - y[10] = RR()*100.0; // y[10] - - ROI(); - RR(); - - // cout<<endl<<" Discounted flow rate (%)= "<<DFR()*100.0; - - DFR(); - - // cout<<endl<<endl<<" Payout time (y)= "<<PT(); // y[ 9] - y[9] = PT(); - - // cout<<endl<<setprecision(0)<<" Annual equivalent cost ($)= "<<AEC(); // y[12] - y[12] = AEC(); - - // cout<<endl<<" Net present value ($)= "<<NPV()<<endl; // y[13] - y[13] = NPV(); - - return OK; -} - -double profitability::ROI() -{ - // if(!MUTE)cout<<endl<<" return on investment..."; - num=den=0.0; - for(i=0;i<C->N;i++) - { - if(C->Inv[i]>EPS) den+=C->Inv[i]; - num+=(C->Rev[i]-C->Coper[i]-C->Amort[i]); - } - if (num>EPS && den>EPS && C->N>0) { - // if(!MUTE)cout<<" OK"; - return num/C->N/den; - } - else return 0.0; -} - -double profitability::RR() -{ - // if(!MUTE)cout<<endl<<" rate of return..."; - num=den=0.0; - for(i=0;i<C->N;i++) - { - num+=(C->Rev[i]-C->Coper[i])/pow(1.0+C->i_rate, i); - den+=C->Inv[i]/pow(1.0+C->i_rate, i); - } - if(num>EPS && den>EPS) { - // if(!MUTE)cout<<" OK"; - return num/den; - } - else return 0.0; -} - -double profitability::DFR() -{ - //if(!MUTE)cout<<endl<<" discounted cash flow rate..."; - solver = new secant<profitability>(); - solver->set(this, 0.0, 0.01); - OK = solver->run(); - - if ( OK && num>EPS && num < 1e20 ) { - // if(!MUTE)cout<<" OK"; - return num; - } - else return 0.0; -} - -double profitability::f(double x) -{ - num=x; - sum=0.0; - for(i=0;i<C->N;i++) - sum += C->Flow[i]/pow(1.0+x, i); - return sum; -} - -double profitability::PT() -{ - // if(!MUTE)cout<<endl<<" payout time..."; - sum=0.0; - for(i=0;i<C->N;i++) - { - if((sum+C->Flow[i])>0.0) - { - den=0.0; - while(sum+den*C->Flow[i]<=0.0) den+=0.001; - den+=double(i-1); - i=C->N; - } - else sum+=C->Flow[i]; - } - - if(den>EPS) { - // if(!MUTE)cout<<" OK"; - return den; - } - else return 0.0; -} - -double profitability::AEC() -{ - //if(!MUTE)cout<<endl<<" annual equivalent cost..."; - sum=0.0; - for(i=0;i<C->N;i++) sum+=(C->Coper[i]+C->Inv[i])/pow(1.0+C->i_rate, i); - if (sum>EPS) { -// if(!MUTE) -// cout<<" OK"; - return sum*(C->i_rate*pow(1.0+C->i_rate,C->N))/(pow(1.0+C->i_rate,C->N)-1.0); - } - else return 0.0; -} - -double profitability::NPV() -{ - // if(!MUTE)cout<<endl<<" net present value..."; - sum=0.0; - for ( i = 0 ; i < C->N ; i++ ) - sum += C->Flowact[i]; - if ( sum > EPS ) { -// if(!MUTE) -// cout<<" OK"; - return sum; - } - return 0.0; -} +#include "profitability.hpp" +#include "secant.cpp" +using namespace std; + +bool profitability::run ( double * y ) +{ + OK=true; + + // cout<<setiosflags(ios::fixed); + // cout<<endl<<endl<<" PROFITABILITY ANALYSIS"<<endl; + // cout<<endl<<setprecision(1)<<" Return on investment (%)= "<<ROI()*100.0; + // cout<<endl<<" Rate of return (%)= "<<RR()*100.0; // y[10] + + y[10] = RR()*100.0; // y[10] + + ROI(); + RR(); + + // cout<<endl<<" Discounted flow rate (%)= "<<DFR()*100.0; + + DFR(); + + // cout<<endl<<endl<<" Payout time (y)= "<<PT(); // y[ 9] + y[9] = PT(); + + // cout<<endl<<setprecision(0)<<" Annual equivalent cost ($)= "<<AEC(); // y[12] + y[12] = AEC(); + + // cout<<endl<<" Net present value ($)= "<<NPV()<<endl; // y[13] + y[13] = NPV(); + + return OK; +} + +double profitability::ROI() +{ + // if(!MUTE)cout<<endl<<" return on investment..."; + num=den=0.0; + for(i=0;i<C->N;i++) + { + if(C->Inv[i]>EPS) den+=C->Inv[i]; + num+=(C->Rev[i]-C->Coper[i]-C->Amort[i]); + } + if (num>EPS && den>EPS && C->N>0) { + // if(!MUTE)cout<<" OK"; + return num/C->N/den; + } + else return 0.0; +} + +double profitability::RR() +{ + // if(!MUTE)cout<<endl<<" rate of return..."; + num=den=0.0; + for(i=0;i<C->N;i++) + { + num+=(C->Rev[i]-C->Coper[i])/pow(1.0+C->i_rate, i); + den+=C->Inv[i]/pow(1.0+C->i_rate, i); + } + if(num>EPS && den>EPS) { + // if(!MUTE)cout<<" OK"; + return num/den; + } + else return 0.0; +} + +double profitability::DFR() +{ + //if(!MUTE)cout<<endl<<" discounted cash flow rate..."; + solver = new secant<profitability>(); + solver->set(this, 0.0, 0.01); + OK = solver->run(); + + if ( OK && num>EPS && num < 1e20 ) { + // if(!MUTE)cout<<" OK"; + return num; + } + else return 0.0; +} + +double profitability::f(double x) +{ + num=x; + sum=0.0; + for(i=0;i<C->N;i++) + sum += C->Flow[i]/pow(1.0+x, i); + return sum; +} + +double profitability::PT() +{ + // if(!MUTE)cout<<endl<<" payout time..."; + sum=0.0; + for(i=0;i<C->N;i++) + { + if((sum+C->Flow[i])>0.0) + { + den=0.0; + while(sum+den*C->Flow[i]<=0.0) den+=0.001; + den+=double(i-1); + i=C->N; + } + else sum+=C->Flow[i]; + } + + if(den>EPS) { + // if(!MUTE)cout<<" OK"; + return den; + } + else return 0.0; +} + +double profitability::AEC() +{ + //if(!MUTE)cout<<endl<<" annual equivalent cost..."; + sum=0.0; + for(i=0;i<C->N;i++) sum+=(C->Coper[i]+C->Inv[i])/pow(1.0+C->i_rate, i); + if (sum>EPS) { +// if(!MUTE) +// cout<<" OK"; + return sum*(C->i_rate*pow(1.0+C->i_rate,C->N))/(pow(1.0+C->i_rate,C->N)-1.0); + } + else return 0.0; +} + +double profitability::NPV() +{ + // if(!MUTE)cout<<endl<<" net present value..."; + sum=0.0; + for ( i = 0 ; i < C->N ; i++ ) + sum += C->Flowact[i]; + if ( sum > EPS ) { +// if(!MUTE) +// cout<<" OK"; + return sum; + } + return 0.0; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/profitability.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/profitability.hpp index 03f85c5..194102c 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/profitability.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/profitability.hpp @@ -1,30 +1,30 @@ -#ifndef PROFITABILITY_H -#define PROFITABILITY_H -#include "cashflow.hpp" -#include "secant.hpp" - -#include <iomanip> - -using namespace std; - -class profitability -{ -private: - cashflow *C; -// ofstream out; -// char name[41]; - bool OK; - double ROI(), RR(), DFR(); - double PT(), AEC(), NPV(); - int i; - double den, num, sum; - secant<profitability> *solver; - -public: - profitability(cashflow* c){C=c;} - ~profitability(){delete solver;}; - // void set(char n[31]) {strcpy(name, n); strcat(name, ".econo");} - bool run ( double * y ); - double f(double); -}; -#endif +#ifndef PROFITABILITY_H +#define PROFITABILITY_H +#include "cashflow.hpp" +#include "secant.hpp" + +#include <iomanip> + +using namespace std; + +class profitability +{ +private: + cashflow *C; +// ofstream out; +// char name[41]; + bool OK; + double ROI(), RR(), DFR(); + double PT(), AEC(), NPV(); + int i; + double den, num, sum; + secant<profitability> *solver; + +public: + profitability(cashflow* c){C=c;} + ~profitability(){delete solver;}; + // void set(char n[31]) {strcpy(name, n); strcat(name, ".econo");} + bool run ( double * y ); + double f(double); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/pump.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/pump.cpp index 166123f..685a0be 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/pump.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/pump.cpp @@ -1,94 +1,94 @@ -#include "pump.hpp" -using namespace std; - -bool pump::solve() { - - // out->chem = in->chem; - out->set ( in->nb , in->chem ); - out->m = in->m; - - - in->set(in->P,in->T); - for ( i = 0 ; i < in->nb ; i++ ) - if(in->chem[i]->m>EPS) { - in->chem[i]->find_v(); - if(in->chem[i]->state==1) { - W+=in->chem[i]->gamma()*in->T*0.0083144*in->chem[i]->n()/ - (in->chem[i]->gamma()-1.0)*(pow(P/in->P, 1.0-1.0/in->chem[i]->gamma())-1.0); - tmp += in->chem[i]->gamma(); - n++; - } - if(in->chem[i]->state==0) - W+=in->chem[i]->v*(P-in->P)*101.325; - } - if (fabs(state-1)<EPS) //compressing gases - out->T = in->T*pow(P/in->P, 1.0-1.0/(tmp/n)); - else //compressing liquids - out->T=in->T; - out->set(P, out->T); - if(eta>EPS) - W /= eta; - else - success=false; - // out->write(); // WRITE TOTO - return success; -} - -void pump::write() { - - cout << setprecision(6); - - string file_name = RUNTIME + name + ".unit"; - cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; - cout <<"\t>> " << name; - cout << endl << "\t>> stream in: "<<in->name<<" out: "<<out->name; - cout << endl << "\t>> P(in) = "<<in->P<<" P(out) = "<<out->P<<" atm"; - cout << endl << "\t>> T(in) = "<<in->T<<" T(out) = "<<out->T<<" K"; - cout << endl << "\t>> Shaft work = "<<W; - if (success) - cout <<" kW (converge normally)"; - cout << "\n\tEND\n\n"; - - power(); - cost(); -} - - -double pump::get_cost ( void ) { - - if ( fabs(state-1) < EPS ) { - if(W<450) W=450; if(W>3000)W=3000; - tmp=2.2891+1.3604*log10(W)-0.1027*pow(log10(W),2); - tmp=3.2*pow(10.0, tmp); - tmp1=2.4604+1.4191*log10(W)-0.1798*pow(log10(W),2); - tmp1=1.5*pow(10.0, tmp1); - tmp+=tmp1; - } - else { - if(W<1) W=1; if(W>300)W=300; - tmp=3.3892+0.0536*log10(W)+0.1538*pow(log10(W),2); - tmp=pow(10.0, tmp); - P=(P-1.0)*101.325/100.0; - if (P<EPS) P=1; if(P>100) P=100; - W = -0.3925+0.3957*log10(P)-0.00226*pow(log10(P),2); - W=pow(10.0, W); if(W<1) W=1; - tmp*=(1.89+1.35*W*1.8); - } - tmp = tmp*MS_YEAR/MS_2001; - return tmp; -} - - -void pump::cost() { - string file_name = RUNTIME + name + ".cost"; - cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; - cout << "\t>>" << get_cost(); - cout << "\n\tEND\n\n"; -} - -void pump::power() { - string file_name = RUNTIME + name + ".power"; - cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; - cout << "\t>>" << W; - cout << "\n\tEND\n\n"; -} +#include "pump.hpp" +using namespace std; + +bool pump::solve() { + + // out->chem = in->chem; + out->set ( in->nb , in->chem ); + out->m = in->m; + + + in->set(in->P,in->T); + for ( i = 0 ; i < in->nb ; i++ ) + if(in->chem[i]->m>EPS) { + in->chem[i]->find_v(); + if(in->chem[i]->state==1) { + W+=in->chem[i]->gamma()*in->T*0.0083144*in->chem[i]->n()/ + (in->chem[i]->gamma()-1.0)*(pow(P/in->P, 1.0-1.0/in->chem[i]->gamma())-1.0); + tmp += in->chem[i]->gamma(); + n++; + } + if(in->chem[i]->state==0) + W+=in->chem[i]->v*(P-in->P)*101.325; + } + if (fabs(state-1)<EPS) //compressing gases + out->T = in->T*pow(P/in->P, 1.0-1.0/(tmp/n)); + else //compressing liquids + out->T=in->T; + out->set(P, out->T); + if(eta>EPS) + W /= eta; + else + success=false; + // out->write(); // WRITE TOTO + return success; +} + +void pump::write() { + + cout << setprecision(6); + + string file_name = RUNTIME + name + ".unit"; + cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; + cout <<"\t>> " << name; + cout << endl << "\t>> stream in: "<<in->name<<" out: "<<out->name; + cout << endl << "\t>> P(in) = "<<in->P<<" P(out) = "<<out->P<<" atm"; + cout << endl << "\t>> T(in) = "<<in->T<<" T(out) = "<<out->T<<" K"; + cout << endl << "\t>> Shaft work = "<<W; + if (success) + cout <<" kW (converge normally)"; + cout << "\n\tEND\n\n"; + + power(); + cost(); +} + + +double pump::get_cost ( void ) { + + if ( fabs(state-1) < EPS ) { + if(W<450) W=450; if(W>3000)W=3000; + tmp=2.2891+1.3604*log10(W)-0.1027*pow(log10(W),2); + tmp=3.2*pow(10.0, tmp); + tmp1=2.4604+1.4191*log10(W)-0.1798*pow(log10(W),2); + tmp1=1.5*pow(10.0, tmp1); + tmp+=tmp1; + } + else { + if(W<1) W=1; if(W>300)W=300; + tmp=3.3892+0.0536*log10(W)+0.1538*pow(log10(W),2); + tmp=pow(10.0, tmp); + P=(P-1.0)*101.325/100.0; + if (P<EPS) P=1; if(P>100) P=100; + W = -0.3925+0.3957*log10(P)-0.00226*pow(log10(P),2); + W=pow(10.0, W); if(W<1) W=1; + tmp*=(1.89+1.35*W*1.8); + } + tmp = tmp*MS_YEAR/MS_2001; + return tmp; +} + + +void pump::cost() { + string file_name = RUNTIME + name + ".cost"; + cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; + cout << "\t>>" << get_cost(); + cout << "\n\tEND\n\n"; +} + +void pump::power() { + string file_name = RUNTIME + name + ".power"; + cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; + cout << "\t>>" << W; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/pump.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/pump.hpp index dbcacfd..aac9e6b 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/pump.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/pump.hpp @@ -1,46 +1,46 @@ -/* -This unit takes one input stream and divides in two or more -output streams. The pressure and temparature of output streams -are the same as the input's. -(ref : McCabe, Smith & Harriott) - -Structure in the .process file: -pump {name} {index of input stream} {index of output stream} {output pressure in atm} {efficiency, between 0 and 1} - -How to use: - 1- Call the constructor: pump1 = new pump(in, out); - 2- Set conditions: pump1->set(P_output, efficiency); - 3- Set the name: pump1->set(name); - 4- Solve: pump1->solve(); -*/ -#ifndef PUMP_H -#define PUMP_H - -#include "stream.hpp" -using namespace std; - -class pump -{ -private: - int i, j, n; - double state, tmp, tmp1; - bool success; - string name; - stream *in; //pointer to input stream - stream *out; //pointer to output stream - -public: - double P, W, eta; //output presure in atm, work in kW and efficiency - pump(stream* s1, stream* s2) {in=s1; out=s2; success=true; W=0.0; n=0; tmp=0.0;} - ~pump(){} - void set(double p, double e){P = p; eta = e; state=in->quality();} - void set(const string & n) { name = n; } - bool solve(); //finds the temperature and computes mass balance - void write(); - void cost(); - double get_cost(); // calcule W aussi - double get_power() const { return W; } - - void power(); -}; -#endif +/* +This unit takes one input stream and divides in two or more +output streams. The pressure and temparature of output streams +are the same as the input's. +(ref : McCabe, Smith & Harriott) + +Structure in the .process file: +pump {name} {index of input stream} {index of output stream} {output pressure in atm} {efficiency, between 0 and 1} + +How to use: + 1- Call the constructor: pump1 = new pump(in, out); + 2- Set conditions: pump1->set(P_output, efficiency); + 3- Set the name: pump1->set(name); + 4- Solve: pump1->solve(); +*/ +#ifndef PUMP_H +#define PUMP_H + +#include "stream.hpp" +using namespace std; + +class pump +{ +private: + int i, j, n; + double state, tmp, tmp1; + bool success; + string name; + stream *in; //pointer to input stream + stream *out; //pointer to output stream + +public: + double P, W, eta; //output presure in atm, work in kW and efficiency + pump(stream* s1, stream* s2) {in=s1; out=s2; success=true; W=0.0; n=0; tmp=0.0;} + ~pump(){} + void set(double p, double e){P = p; eta = e; state=in->quality();} + void set(const string & n) { name = n; } + bool solve(); //finds the temperature and computes mass balance + void write(); + void cost(); + double get_cost(); // calcule W aussi + double get_power() const { return W; } + + void power(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/reaction.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/reaction.cpp index ee658e5..9eaafc1 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/reaction.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/reaction.cpp @@ -1,204 +1,204 @@ -#include "reaction.hpp" -using namespace std; - - -int reaction::find_chemical ( const string & chem_name ) const { - for ( int i = 0 ; i < m ; i++ ) - if ( list[i]->CAS == chem_name ) - return i; - return -1; -} - -// donnees hardcodees -reaction::reaction ( const string & in1 , int dim , chemical ** in2 ) { - - m = dim; // nbre de chemicals - list = in2; // liste des chemicals - - n = new double[m]; - safe_n = new double[m]; - safe_a = new double[m]; - a = new double[m]; - - int i , j; - for ( i = 0 ; i < m ; i++ ) { - a[i]=0.0; - n[i]=0.0; - } - - // 1/5 : - if ( in1 == "eb2sty" ) { - k0 = 3.525e5; - E = 90.85; - if ( (j = find_chemical ("100-41-4")) < 0 ) { - cout << "ERROR 10a\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("1333-74-0")) < 0 ) { - cout << "ERROR 10b\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - if ( (j = find_chemical ("100-42-5")) < 0 ) { - cout << "ERROR 10c\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - } - - // 2/5 : - else if ( in1 == "sty2eb" ) { - k0 = 2.754e-4; - E = -18.653; - if ( (j = find_chemical ("100-41-4")) < 0 ) { - cout << "ERROR 10d\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - if ( (j = find_chemical ("1333-74-0")) < 0 ) { - cout << "ERROR 10e\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("100-42-5")) < 0 ) { - cout << "ERROR 10f\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - } - - // 3/5 : - else if ( in1 == "eb2bz" ) { - k0 = 9.577e4; - E = 111.375; - if ( (j = find_chemical ("100-41-4")) < 0 ) { - cout << "ERROR 10g\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("71-43-2")) < 0 ) { - cout << "ERROR 10h\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - if ( (j = find_chemical ("74-85-1")) < 0 ) { - cout << "ERROR 10i\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - } - - // 4/5 : - else if ( in1 == "eb2tol" ) { - k0 = 6.077e8; - E = 207.850; - if ( (j = find_chemical ("100-41-4")) < 0 ) { - cout << "ERROR 10j\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("1333-74-0")) < 0 ) { - cout << "ERROR 10k\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("108-88-3")) < 0 ) { - cout << "ERROR 10l\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - if ( (j = find_chemical ("74-82-8")) < 0 ) { - cout << "ERROR 10m\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - } - - // 5/5 : - else if ( in1 == "tol2bz" ) { - k0 = 1; - E = 19.038; - if ( (j = find_chemical ("1333-74-0")) < 0 ) { - cout << "ERROR 10n\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 0.5; - if ( (j = find_chemical ("108-88-3")) < 0 ) { - cout << "ERROR 10o\n\n"; - exit(0); - } - a[j] = -1; - n[j] = 1; - if ( (j = find_chemical ("71-43-2")) < 0 ) { - cout << "ERROR 10p\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - if ( (j = find_chemical ("74-82-8")) < 0 ) { - cout << "ERROR 10q\n\n"; - exit(0); - } - a[j] = 1; - n[j] = 0; - } - else { - cout << "ERROR 12\n\n"; - exit(0); - } - - for ( i = 0 ; i < m ; i++ ) { - safe_n[i]=n[i]; - safe_a[i]=a[i]; - } -} - -reaction::~reaction() { - delete [] a; - delete [] n; - delete [] safe_n; - delete [] safe_a; -} - -double reaction::dHr(double T) -{ - int i , j; - for (i=0;i<m;i++) - if(safe_a[i]!=a[i]) - { - if(a[i]>safe_a[i]) a[i]=safe_a[i]; - else safe_a[i]=a[i]; - } - double tmp=0.0; - for (i=0;i<m;i++) tmp += a[i]*list[i]->Ho; - if(fabs(T-298)>EPS) - for (i=0;i<m;i++) - for (j=1;j<=4;j++) tmp += a[i]*list[i]->Cp_param[j-1]*(pow(T,j)-pow(298.0,j))/j/1000.0; - return tmp; -} - -double reaction::rate(double T, double* C) -{ - double tmp = k0*exp(-1000*E/8.3144/T); - for ( int i=0;i<m;i++) - { - if(safe_n[i]!=n[i]) n[i]=safe_n[i]; - if(C[i]>EPS && fabs(n[i])>EPS) tmp *= pow(C[i], n[i]); - } - return tmp; -} +#include "reaction.hpp" +using namespace std; + + +int reaction::find_chemical ( const string & chem_name ) const { + for ( int i = 0 ; i < m ; i++ ) + if ( list[i]->CAS == chem_name ) + return i; + return -1; +} + +// donnees hardcodees +reaction::reaction ( const string & in1 , int dim , chemical ** in2 ) { + + m = dim; // nbre de chemicals + list = in2; // liste des chemicals + + n = new double[m]; + safe_n = new double[m]; + safe_a = new double[m]; + a = new double[m]; + + int i , j; + for ( i = 0 ; i < m ; i++ ) { + a[i]=0.0; + n[i]=0.0; + } + + // 1/5 : + if ( in1 == "eb2sty" ) { + k0 = 3.525e5; + E = 90.85; + if ( (j = find_chemical ("100-41-4")) < 0 ) { + cout << "ERROR 10a\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("1333-74-0")) < 0 ) { + cout << "ERROR 10b\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + if ( (j = find_chemical ("100-42-5")) < 0 ) { + cout << "ERROR 10c\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + } + + // 2/5 : + else if ( in1 == "sty2eb" ) { + k0 = 2.754e-4; + E = -18.653; + if ( (j = find_chemical ("100-41-4")) < 0 ) { + cout << "ERROR 10d\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + if ( (j = find_chemical ("1333-74-0")) < 0 ) { + cout << "ERROR 10e\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("100-42-5")) < 0 ) { + cout << "ERROR 10f\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + } + + // 3/5 : + else if ( in1 == "eb2bz" ) { + k0 = 9.577e4; + E = 111.375; + if ( (j = find_chemical ("100-41-4")) < 0 ) { + cout << "ERROR 10g\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("71-43-2")) < 0 ) { + cout << "ERROR 10h\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + if ( (j = find_chemical ("74-85-1")) < 0 ) { + cout << "ERROR 10i\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + } + + // 4/5 : + else if ( in1 == "eb2tol" ) { + k0 = 6.077e8; + E = 207.850; + if ( (j = find_chemical ("100-41-4")) < 0 ) { + cout << "ERROR 10j\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("1333-74-0")) < 0 ) { + cout << "ERROR 10k\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("108-88-3")) < 0 ) { + cout << "ERROR 10l\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + if ( (j = find_chemical ("74-82-8")) < 0 ) { + cout << "ERROR 10m\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + } + + // 5/5 : + else if ( in1 == "tol2bz" ) { + k0 = 1; + E = 19.038; + if ( (j = find_chemical ("1333-74-0")) < 0 ) { + cout << "ERROR 10n\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 0.5; + if ( (j = find_chemical ("108-88-3")) < 0 ) { + cout << "ERROR 10o\n\n"; + exit(0); + } + a[j] = -1; + n[j] = 1; + if ( (j = find_chemical ("71-43-2")) < 0 ) { + cout << "ERROR 10p\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + if ( (j = find_chemical ("74-82-8")) < 0 ) { + cout << "ERROR 10q\n\n"; + exit(0); + } + a[j] = 1; + n[j] = 0; + } + else { + cout << "ERROR 12\n\n"; + exit(0); + } + + for ( i = 0 ; i < m ; i++ ) { + safe_n[i]=n[i]; + safe_a[i]=a[i]; + } +} + +reaction::~reaction() { + delete [] a; + delete [] n; + delete [] safe_n; + delete [] safe_a; +} + +double reaction::dHr(double T) +{ + int i , j; + for (i=0;i<m;i++) + if(safe_a[i]!=a[i]) + { + if(a[i]>safe_a[i]) a[i]=safe_a[i]; + else safe_a[i]=a[i]; + } + double tmp=0.0; + for (i=0;i<m;i++) tmp += a[i]*list[i]->Ho; + if(fabs(T-298)>EPS) + for (i=0;i<m;i++) + for (j=1;j<=4;j++) tmp += a[i]*list[i]->Cp_param[j-1]*(pow(T,j)-pow(298.0,j))/j/1000.0; + return tmp; +} + +double reaction::rate(double T, double* C) +{ + double tmp = k0*exp(-1000*E/8.3144/T); + for ( int i=0;i<m;i++) + { + if(safe_n[i]!=n[i]) n[i]=safe_n[i]; + if(C[i]>EPS && fabs(n[i])>EPS) tmp *= pow(C[i], n[i]); + } + return tmp; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/reaction.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/reaction.hpp index f05b27e..1456e0d 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/reaction.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/reaction.hpp @@ -1,32 +1,32 @@ -#ifndef REACTION_H -#define REACTION_H - -#include "chemical.hpp" -using namespace std; - -class reaction { -private: - - int m; - double *n, k0, E, Hr, *safe_n, *safe_a; - // double tmp; -// char file[41], line[31]; - chemical ** list; -// ifstream in; - // ofstream logf; - // terminator *end; - - int find_chemical ( const string & chem_name ) const; - -public: - // reaction(){}; - reaction ( const string & , int , chemical ** ); - ~reaction(); - double *a; //contains the molar coefficients - double dHr(double); //returns heat of rection at T, in kJ/mol - double rate(double, double*); //returns rate of reaction aT and C[], in mol/s.m3 - -// void show_name(){cout<<name;} -}; - -#endif +#ifndef REACTION_H +#define REACTION_H + +#include "chemical.hpp" +using namespace std; + +class reaction { +private: + + int m; + double *n, k0, E, Hr, *safe_n, *safe_a; + // double tmp; +// char file[41], line[31]; + chemical ** list; +// ifstream in; + // ofstream logf; + // terminator *end; + + int find_chemical ( const string & chem_name ) const; + +public: + // reaction(){}; + reaction ( const string & , int , chemical ** ); + ~reaction(); + double *a; //contains the molar coefficients + double dHr(double); //returns heat of rection at T, in kJ/mol + double rate(double, double*); //returns rate of reaction aT and C[], in mol/s.m3 + +// void show_name(){cout<<name;} +}; + +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/reactor.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/reactor.cpp index 0f0ddae..7f6e3a9 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/reactor.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/reactor.cpp @@ -1,100 +1,100 @@ -#include "reactor.hpp" -using namespace std; - -template<class TYPE> -reactor<TYPE>::reactor(stream* s1, stream* s2) -{ - in = s1; - out = s2; - - model = NULL; -} - -template<class TYPE> -reactor<TYPE>::~reactor() { - for ( i = 0 ; i < n ; i++ ) - delete rx[i]; - delete [] rx; - for ( i = 0 ; i < m ; i++ ) - delete table[i]; - delete [] table; - - if (model) - delete model; -} - -template<class TYPE> -void reactor<TYPE>::set ( double l , double d , int nb , const string * list_rx ) { - m = in->nb; - n = nb; - L = l; - D = d; - V = pi*pow(D/2.0, 2)*L; - - double * yields = new double [n]; - - rx = new reaction * [n]; - for ( j = 0 ; j < n ; j++ ) - rx[j] = new reaction ( list_rx[j] , m , in->chem ); - - table = new double * [m]; - for ( i = 0 ; i < m ; i++ ) - table[i] = new double[n]; - for ( j = 0 ; j < n ; j++ ) - for ( i = 0 ; i < m ; i++ ) - table[i][j] = rx[j]->a[i]; - for ( j = 0 ; j < n ; j++ ) { - yields[j]=0.0; - for ( i = 0 ; i < m ; i++ ) - if ( table[i][j] < 0 ) { - yields[j]=in->chem[i]->n(); - i=m; - } - } - - delete [] yields; - -} - -template<class TYPE> -bool reactor<TYPE>::solve() { - - if (model) - delete model; - model = new TYPE(in, out, table, n, rx, U, Ta); - model->set(name); - model->set(L,D); - - success = model->run(); - - // if(fabs(in->m-out->m)>sqrt(EPS)) - // { - // log.open(MESSAGES, ios::app); - // log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(in->m-out->m)/in->m<<").\n"; - // log.close(); - // } - - - // out->write(); // WRITE TOTO - - return success; -} - -template<class TYPE> -void reactor<TYPE>::write ( void ) { - - cout << setprecision(6); - - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout << "\t>> " << name; - cout << endl << "\t>> stream in : " << in->name; - cout << endl << "\t>> stream out : " << out->name; - cout << endl << "\t>> P = " << in->P - << " atm, T(in) = " << in->T << ", T(out) = " << out->T << " K"; - cout << endl << "\t>> L = " << L << ", D = " << D << " m"; - if (success) - cout << " (converge normally)"; - cout << "\n\tEND\n\n"; - model->cost(); - model->water(); -} +#include "reactor.hpp" +using namespace std; + +template<class TYPE> +reactor<TYPE>::reactor(stream* s1, stream* s2) +{ + in = s1; + out = s2; + + model = NULL; +} + +template<class TYPE> +reactor<TYPE>::~reactor() { + for ( i = 0 ; i < n ; i++ ) + delete rx[i]; + delete [] rx; + for ( i = 0 ; i < m ; i++ ) + delete table[i]; + delete [] table; + + if (model) + delete model; +} + +template<class TYPE> +void reactor<TYPE>::set ( double l , double d , int nb , const string * list_rx ) { + m = in->nb; + n = nb; + L = l; + D = d; + V = pi*pow(D/2.0, 2)*L; + + double * yields = new double [n]; + + rx = new reaction * [n]; + for ( j = 0 ; j < n ; j++ ) + rx[j] = new reaction ( list_rx[j] , m , in->chem ); + + table = new double * [m]; + for ( i = 0 ; i < m ; i++ ) + table[i] = new double[n]; + for ( j = 0 ; j < n ; j++ ) + for ( i = 0 ; i < m ; i++ ) + table[i][j] = rx[j]->a[i]; + for ( j = 0 ; j < n ; j++ ) { + yields[j]=0.0; + for ( i = 0 ; i < m ; i++ ) + if ( table[i][j] < 0 ) { + yields[j]=in->chem[i]->n(); + i=m; + } + } + + delete [] yields; + +} + +template<class TYPE> +bool reactor<TYPE>::solve() { + + if (model) + delete model; + model = new TYPE(in, out, table, n, rx, U, Ta); + model->set(name); + model->set(L,D); + + success = model->run(); + + // if(fabs(in->m-out->m)>sqrt(EPS)) + // { + // log.open(MESSAGES, ios::app); + // log<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(in->m-out->m)/in->m<<").\n"; + // log.close(); + // } + + + // out->write(); // WRITE TOTO + + return success; +} + +template<class TYPE> +void reactor<TYPE>::write ( void ) { + + cout << setprecision(6); + + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout << "\t>> " << name; + cout << endl << "\t>> stream in : " << in->name; + cout << endl << "\t>> stream out : " << out->name; + cout << endl << "\t>> P = " << in->P + << " atm, T(in) = " << in->T << ", T(out) = " << out->T << " K"; + cout << endl << "\t>> L = " << L << ", D = " << D << " m"; + if (success) + cout << " (converge normally)"; + cout << "\n\tEND\n\n"; + model->cost(); + model->water(); +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/reactor.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/reactor.hpp index 78f936f..af0d281 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/reactor.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/reactor.hpp @@ -1,48 +1,48 @@ -/* -This unit simulates a chemical reactor. Actually, only the pfr can be used. -(ref : Fogler). - -Structure in the .process file: -reactor {name} {pfr or cstr} {index of input stream} {index of output stream} {length in m} {diameter in m} {nb_react, list of reactions occuring} {U in kW/m2.K}{Ta in K} - -How to use: - 1- Call the constructor : react = new reactor<pfr or cstr>(in, out); - 2- Set dimensions and reactions : react->set(length, diameter, nb_react, list_react); //list_react is the list of reactions names - 3- Set cooling parameters : react->set(U, Ta); - 4- Set the name : react->set(name); - 5- Run the model: react->solve(); -*/ -#ifndef REACTOR_H -#define REACTOR_H - -#include "pfr.hpp" -using namespace std; - -template<class TYPE> -class reactor { -private: - // ofstream log; - bool success; - string name; - int i ,j, m, n; - double V, L, D, U, Ta; - stream *in, *out; - TYPE *model; - reaction ** rx; - double ** table; - -public: - // reactor(){}; - reactor(stream*, stream*); - void set( const string & n) { name = n; } - void set(double, double, int, const string * ); - void set(double u, double ta) {U=u;Ta=ta;} - bool solve(); - void write(); - - double get_cost ( void ) const { return model->get_cost() ; } - double get_water ( void ) const { return model->get_water(); } - - ~reactor(); -}; -#endif +/* +This unit simulates a chemical reactor. Actually, only the pfr can be used. +(ref : Fogler). + +Structure in the .process file: +reactor {name} {pfr or cstr} {index of input stream} {index of output stream} {length in m} {diameter in m} {nb_react, list of reactions occuring} {U in kW/m2.K}{Ta in K} + +How to use: + 1- Call the constructor : react = new reactor<pfr or cstr>(in, out); + 2- Set dimensions and reactions : react->set(length, diameter, nb_react, list_react); //list_react is the list of reactions names + 3- Set cooling parameters : react->set(U, Ta); + 4- Set the name : react->set(name); + 5- Run the model: react->solve(); +*/ +#ifndef REACTOR_H +#define REACTOR_H + +#include "pfr.hpp" +using namespace std; + +template<class TYPE> +class reactor { +private: + // ofstream log; + bool success; + string name; + int i ,j, m, n; + double V, L, D, U, Ta; + stream *in, *out; + TYPE *model; + reaction ** rx; + double ** table; + +public: + // reactor(){}; + reactor(stream*, stream*); + void set( const string & n) { name = n; } + void set(double, double, int, const string * ); + void set(double u, double ta) {U=u;Ta=ta;} + bool solve(); + void write(); + + double get_cost ( void ) const { return model->get_cost() ; } + double get_water ( void ) const { return model->get_water(); } + + ~reactor(); +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/secant.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/secant.cpp index 79e5d04..e8582e0 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/secant.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/secant.cpp @@ -1,47 +1,47 @@ -#include "secant.hpp" -using namespace std; - -template <class E> -secant<E>::secant() -{ - x_last=0; - x_now=0; - x_next=0; - f_last=0; - f_now=0; - OK=false; -} - -template <class E> -void secant<E>::set(E* tmp, double x1, double x2) -{ - unit=tmp; - x_last=x1; - x_now=x2; - OK=false; -} - -template <class E> -bool secant<E>::run() -{ - // if(DEBUG) cout<<endl<<"begin solve secant"; - f_last = unit->f(x_last); - for (i=1; i<MAX_ITER_SECANT; i++) - { - f_now = unit->f(x_now); - // if(DEBUG) cout<<endl<<" x = "<<x_now<<" f(x) = "<<f_now; - x_next = x_now - (f_now*(x_now-x_last)/(f_now-f_last)); - if (fabs((x_next-x_now)/x_now)<=TOL_SECANT) - { - i=MAX_ITER_SECANT; - OK=true; - } - else - { - x_last=x_now; - f_last=f_now; - x_now=x_next; - } - } - return OK; -} +#include "secant.hpp" +using namespace std; + +template <class E> +secant<E>::secant() +{ + x_last=0; + x_now=0; + x_next=0; + f_last=0; + f_now=0; + OK=false; +} + +template <class E> +void secant<E>::set(E* tmp, double x1, double x2) +{ + unit=tmp; + x_last=x1; + x_now=x2; + OK=false; +} + +template <class E> +bool secant<E>::run() +{ + // if(DEBUG) cout<<endl<<"begin solve secant"; + f_last = unit->f(x_last); + for (i=1; i<MAX_ITER_SECANT; i++) + { + f_now = unit->f(x_now); + // if(DEBUG) cout<<endl<<" x = "<<x_now<<" f(x) = "<<f_now; + x_next = x_now - (f_now*(x_now-x_last)/(f_now-f_last)); + if (fabs((x_next-x_now)/x_now)<=TOL_SECANT) + { + i=MAX_ITER_SECANT; + OK=true; + } + else + { + x_last=x_now; + f_last=f_now; + x_now=x_next; + } + } + return OK; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/secant.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/secant.hpp index d1bb096..a04cbc5 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/secant.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/secant.hpp @@ -1,31 +1,31 @@ -/* -To use the secant solver to find the root of a scalar function: - (the parametric object E must have public function such as E->f(x), - where x is the point at which evaluate f.) - 1- construct the solver : solver = new secant<E>(); - 2- set the solver : solver->set(unit, x0, x1); //unit is usually the pointer *this, and x0 and x1 are two required initial points - 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed -*/ -#ifndef SECANT_H -#define SECANT_H - -#include "defines.hpp" -using namespace std; - - -template <class E> -class secant { -private: - double x_last, x_now, x_next; - double f_last, f_now, error; - int i; - bool OK; - E *unit; - -public: - secant(); - void set(E*, double, double); - bool run(); - ~secant(){} -}; -#endif +/* +To use the secant solver to find the root of a scalar function: + (the parametric object E must have public function such as E->f(x), + where x is the point at which evaluate f.) + 1- construct the solver : solver = new secant<E>(); + 2- set the solver : solver->set(unit, x0, x1); //unit is usually the pointer *this, and x0 and x1 are two required initial points + 3- launch the solver : bool = solver->run(); //will return true is success, false if the solver failed +*/ +#ifndef SECANT_H +#define SECANT_H + +#include "defines.hpp" +using namespace std; + + +template <class E> +class secant { +private: + double x_last, x_now, x_next; + double f_last, f_now, error; + int i; + bool OK; + E *unit; + +public: + secant(); + void set(E*, double, double); + bool run(); + ~secant(){} +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/servor.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/servor.cpp index 0b2df20..75216ae 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/servor.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/servor.cpp @@ -1,538 +1,538 @@ -#include "servor.hpp" -#include "reactor.cpp" -using namespace std; - -/*---------------------------------------------------------------------*/ -servor::servor ( int nb_u , int n2 , stream ** streams ) { - nb = nb_u; - nb_s = n2; - type = new string[nb]; - name = new string[nb]; - s = streams; - - -// for (int i=0; i<nb; i++) -// { -// type[i]=new char[31]; -// name[i]=new char[31]; -// } -// cursor=0; -// s = s_list; -// // end = new terminator("\0"); -// mix1=NULL; -// split1=NULL; -// flash1=NULL; -// pump1=NULL; -// col=NULL; -// react_pfr=NULL; -// react_cstr=NULL; -// heat=NULL; - - burn = new burner ( s[0]->nb , s[0]->chem ); -} - -/*---------------------------------------------------------------------*/ -servor::~servor() { - delete [] type; - delete [] name; - delete burn; -} - -/*---------------------------------------------------------------------*/ -bool servor::solve_process ( const double * x , double * y ) { - - - for ( i = 0 ; i < 8 ; i++ ) - costs[i] = 0.0; - - k = 0; - norm = 1.0 / TOL_WEGSTEIN; - - for ( cursor = 0 ; cursor < nb ; cursor++ ) { - - if (type[cursor] == "mix" ) { - do_mix_process(x); - } - else if ( type[cursor] == "split" ) { - do_split_process(x); - } - else if ( type[cursor] == "flash" ) { - do_flash_process(x); - } - else if ( type[cursor] == "pump" ) { - do_pump_process(x); - } - else if ( type[cursor] == "heatx") { - do_heatx_process(x); - } - else if ( type[cursor] == "burner" ) { - do_burner_process(x,y); - } - else if ( type[cursor] == "column" ) { - do_column_process(x,y); - } - else if ( type[cursor] == "reactor" ) { - do_reactor_process(x); - } - else if ( type[cursor] == "loop" ) { - - recycle = 10; - end_recycle = 0; - do_loop_process(x); - } - else { - cout << "ERROR 18\n\n"; - exit(0); - } - - } - - return true; -} - - -/*---------------------------------------------------------------------*/ -void servor::do_loop_process ( const double * x ) { - - // structure in the input file : - // loop - // name : "looping" - // index of recycle stream : 11 - // index of stream's beginning block : 7 - // index of stream's end block : 1 - - // TOTO -// if (k==0) -// cout << endl << " -> Wegstein iterations "; -// else if ( k <= 2 ) -// cout << endl << " -> loop " << setw(3) << k; -// else -// cout << endl << " -> loop " << setw(3) << k << " > error " << norm; - - // Get the two fisrst points - if ( k==0 ) { - for ( i = 0 ; i < s[0]->nb ; i++ ) - x_last[i] = s[recycle]->chem[i]->m; - end_loop = false; - } - - if ( k==1 ) { - for ( i = 0 ; i < s[0]->nb ; i++ ) { - x_now [i] = s[recycle]->chem[i]->m; - g_last[i] = s[recycle]->chem[i]->m; - } - - end_loop = false; - } - - if ( k == 2 ) { - for ( i = 0 ; i < s[0]->nb ; i++ ) - g_now[i] = s[recycle]->chem[i]->m; - end_loop=false; - } - k++; - - - // run the Wegstein algorithm - if ( k > 2 ) { - for ( i = 0 ; i < s[0]->nb ; i++ ) { - g_now[i] = s[recycle]->chem[i]->m; - - if ( fabs (x_now[i]-x_last[i]) > EPS ) - slope[i] = ( g_now[i] - g_last[i] ) / ( x_now[i] - x_last[i] ); - else - slope[i] = 0; - - theta[i] = 1.0 / (1.0-slope[i]); - if ( theta[i] < MIN_THETA ) - theta[i] = MIN_THETA; - if ( theta[i] > MAX_THETA ) - theta[i] = MAX_THETA; - x_next[i] = (1.0-theta[i])*x_now[i] + theta[i]*g_now[i]; - } - norm = 0.0; - for ( i = 0 ; i < s[0]->nb ; i++ ) - if ( fabs(x_now[i]) > EPS ) - norm += fabs (x_next[i]-x_now[i]) / fabs(x_now[i]); - - if ( norm > TOL_WEGSTEIN && k < MAX_ITER_WEGSTEIN ) { - s[recycle]->m = 0.0; - for ( i = 0 ; i < s[0]->nb ; i++ ) { - s[recycle]->chem[i]->m = x_next[i]; - s[recycle]->m += x_next[i]; - x_last[i] = x_now[i]; - g_last[i] = g_now[i]; - x_now[i] = x_next[i]; - } - end_loop=false; - } - if ( norm <= TOL_WEGSTEIN && k < MAX_ITER_WEGSTEIN ) - end_loop = true; - - } - - - if ( end_loop ) { - if ( k < MAX_ITER_WEGSTEIN && k > 3 ) { - // cout<<" OK"; // TOTO - // s[recycle]->write(); // WRITE TOTO - -// // WRITE TOTO : -// cout << "WRITE FILE " << RUNTIME << name[cursor] << ".unit" << " :\n\tBEGIN\n"; -// cout << "\t>> " << name[cursor]; -// cout << endl << "\t>> from block " << cursor+1 << " to block " << end_recycle+1; -// cout << endl << "\t>> Wegstein converged in " -// << k << " iterations (rel. err. " << norm << ")."; -// cout << "\n\tEND\n\n"; - - k = 0; - norm = 1.0/TOL_WEGSTEIN; - } -// else { -// log.open(MESSAGES, ios::app); -// log<<" ==> Error <== Wegstein algorithm did not converge.\n"; -// log.close(); -// } - } - - - if ( !end_loop && k < MAX_ITER_WEGSTEIN ) - cursor = end_recycle-1; - if ( !end_loop && k==MAX_ITER_WEGSTEIN ) { -// log.open(MESSAGES, ios::app); -// log<<" ==> Error <== Wegstein algorithm did not converge.\n"; -// log.close(); - k=0; - norm = 1.0/TOL_WEGSTEIN; - cursor=nb; - } - -} - -/*---------------------------------------------------------------------*/ -void servor::do_burner_process ( const double * x , double * y ) { - - // cout << endl << " -- " << name[cursor] << "... "; // TOTO - - // read parameters : - int i1 = 8; - int i2 = 13; - double f = x[6]; - - burn->set ( s[i1-1] , s[i2-1] ); - burn->set(f); - burn->set(name[cursor]); - - if ( burn->solve(y) ) { - // cout << "OK"; // TOTO - // burn->write(); // WRITE TOTO - costs[7] = burn->get_cost(); - } - else { - cout << "ERROR 20\n\n"; - exit(0); - } -} - -/*---------------------------------------------------------------------*/ -void servor::do_split_process ( const double * x ) -{ - // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO - - //Read parameters - int i1 = 9; - int i2 = 2; - int i_tab[2] = { 10 , 11 }; - double f_tab[2]; - f_tab[0] = x[5]; - f_tab[1] = 1-x[5]; - - stream * list1[2]; - list1[0] = s[i_tab[0]-1]; - list1[1] = s[i_tab[1]-1]; - - split * split1 = new split ( i2 , s[i1-1] , list1 ); - - split1->set(f_tab); - split1->set(name[cursor]); - if ( split1->solve() ) { - // cout<<"OK"; // TOTO - // split1->write(); // WRITE TOTO - } - else { - cout << "ERROR 19\n\n"; - exit(0); - } - delete split1; -} - -/*---------------------------------------------------------------------*/ -void servor::do_column_process ( const double * x , double * y ) { - // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO - - //Read parameters - double f1 , f2; - int i , i1 , i2; - int i_tab[2]; - double f = 1.0; - - if (name[cursor]=="sep-sty") { - i = 7; - i1 = 15; - i2 = 9; - i_tab[0] = 1; - i_tab[1] = 7; - f1 = f2 = x[2]; - } - else if (name[cursor]=="sep-bz") { - i = 10; - i1 = 12; - i2 = 14; - i_tab[0] = 5; - i_tab[1] = 1; - f1 = f2 = x[3]; - } - else { - cout << "ERROR 17\n\n"; - exit(0); - } - - column * col = new column ( s[i-1] , s[i1-1] , s[i2-1] ); - col->set ( f , i_tab[0] , f1 , i_tab[1] , f2 ); - col->set(name[cursor]); - if ( col->solve() ) { - //cout<<"OK"; // TOTO - //col->write(); // WRITE TOTO - - if (name[cursor]=="sep-sty") { - y[4] = col->get_N(); - costs[5] = col->get_cost(); - power[5] = col->get_power(); - water[5] = col->get_water(); - } - else { - y[5] = col->get_N(); - costs[6] = col->get_cost(); - power[4] = col->get_power(); - water[4] = col->get_water(); - } - } - else { - cout << "ERROR 15\n\n"; - exit(0); - } - delete col; -} - -/*---------------------------------------------------------------------*/ -void servor::do_flash_process ( const double * x ) { - // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO - - //Read parameters - double f1 = 1.0; - double f2 = x[7]; - // int i_tab [3] = { 6 , 7 , 8 }; - // flash * flash1 = new flash ( s[i_tab[0]-1] , s[i_tab[1]-1] , s[i_tab[2]-1] ); - flash * flash1 = new flash ( s[5] , s[6] , s[7] ); - - flash1->set(f1, f2); - flash1->set(name[cursor]); - if ( flash1->solve() ) { - // cout<<"OK"; // TOTO - // flash1->write(); // WRITE TOTO - costs[4] = flash1->get_cost(); - power[2] = flash1->get_power(); - water[1] = flash1->get_water(); - } - else { - cout << "ERROR 14\n\n"; - exit(0); - } - delete flash1; -} - - -/*---------------------------------------------------------------------*/ -void servor::do_mix_process ( const double * x ) { - - // cout << endl << " -- " << name[cursor] << "... "; // TOTO - - // Read parameters (hardcode avec eb2sty.process) : - double f1 = 1.0; - int i1 = 3; - int i_tab[3] = { 1 , 12 , 11 }; - int i2 = 2; - - // We can solve the unit - stream * list2 = s[i2-1] , ** list1 = new stream * [i1]; - for ( int i = 0 ; i < i1 ; i++ ) - list1[i] = s[i_tab[i]-1]; - mix * mix1 = new mix ( i1 , list1 , list2 ); - mix1->set(f1); - mix1->set(name[cursor]); - if (mix1->solve()) { - // cout<<"OK"; // TOTO - // mix1->write(); // WRITE TOTO - } - else { - cout << "ERROR 6\n\n"; - exit(0); - } - delete mix1; - delete [] list1; -} - - -/*---------------------------------------------------------------------*/ -void servor::do_pump_process ( const double * x ) { - - // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO - - //Read parameters (hardcode avec eb2sty.process) : - int i1 = 2; - int i2 = 3; - double f1 = x[4]; - double f2 = 0.75; - - pump * pump1 = new pump ( s[i1-1] , s[i2-1] ); - pump1->set(f1,f2); - pump1->set(name[cursor]); - - - - // solve : - if ( pump1->solve() ) { - // cout<<"OK"; // TOTO - // pump1->write(); // WRITE TOTO - - power[0] = pump1->get_power(); - costs[0] = pump1->get_cost(); - } - else { - cout << "ERROR 7\n\n"; - exit(0); - } - - delete pump1; -} - -/*---------------------------------------------------------------------*/ -void servor::do_heatx_process ( const double * x ) { - - // cout << endl << " -- " << name[cursor] << "... "; // TOTO - - //Read parameters (idem) : - - bool b = false; - - // heater : - int i1; - int i2; - double f1; - - // heater : - if (name[cursor]=="heater") { - i1 = 3; - i2 = 4; - f1 = x[0]; - } - - // cooler : - else if (name[cursor]=="cooler") { - i1 = 5; - i2 = 6; - f1 = x[7]; - } - else { - cout << "ERROR 16\n\n"; - exit(0); - } - - double f2 = 0.85; - - // solve : - heatx * heat = new heatx ( b , s[i1-1] , s[i2-1] ); - heat->set(f1,f2); - heat->set(name[cursor]); - if (heat->solve()) { - // cout<<"OK"; // TOTO - // heat->write(); // WRITE TOTO - if (name[cursor]=="heater") { - costs[1] = heat->get_cost(); - power[3] = heat->get_power(); - water[2] = heat->get_water(); - } - else { - costs[3] = heat->get_cost(); - power[1] = heat->get_power(); - water[0] = heat->get_water(); - } - } - else { - cout << "ERROR 8\n\n"; - exit(0); - } - delete heat; -} - -/*---------------------------------------------------------------------*/ -void servor::do_reactor_process ( const double * x ) { - - // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO - - // Read parameters (idem) : - int i1 = 4; - int i2 = 5; - - reactor<pfr> * react_pfr = new reactor<pfr> ( s[i1-1] , s[i2-1] ); - - react_pfr->set(name[cursor]); - - double f1 = x[1]; - double f2 = 0.5; - - string list[5] = { "eb2sty" , "sty2eb" , "eb2bz" , "eb2tol" , "tol2bz" }; - - i1 = 5; - - react_pfr->set(f1,f2,i1,list); - - f1 = 0.0; - f2 = 300.0; - - react_pfr->set(f1,f2); - - if ( react_pfr->solve() ) { - // cout<<"OK"; // TOTO - // react_pfr->write(); // WRITE TOTO - costs[2] = react_pfr->get_cost(); - water[3] = react_pfr->get_water(); - } - else { - cout << "ERROR 9\n\n"; - exit(0); - } - delete react_pfr; -} - - -double servor::get_costs_sum ( void ) const { - double sum = 0.0; - for ( int i = 0 ; i < 8 ; i++ ) - sum += ( (ARRONDI) ? arrondi(costs[i],6) : costs[i] ); - return sum; -} - -double servor::get_power_sum ( void ) const { - double sum = 0.0; - for ( int i = 0 ; i < 6 ; i++ ) - sum += ( (ARRONDI) ? arrondi(power[i],6) : power[i] ); - return sum; -} - -double servor::get_water_sum ( void ) const { - double sum = 0.0; - for ( int i = 0 ; i < 6 ; i++ ) - sum += ( (ARRONDI) ? arrondi(water[i],6) : water[i] ); - return sum; -} +#include "servor.hpp" +#include "reactor.cpp" +using namespace std; + +/*---------------------------------------------------------------------*/ +servor::servor ( int nb_u , int n2 , stream ** streams ) { + nb = nb_u; + nb_s = n2; + type = new string[nb]; + name = new string[nb]; + s = streams; + + +// for (int i=0; i<nb; i++) +// { +// type[i]=new char[31]; +// name[i]=new char[31]; +// } +// cursor=0; +// s = s_list; +// // end = new terminator("\0"); +// mix1=NULL; +// split1=NULL; +// flash1=NULL; +// pump1=NULL; +// col=NULL; +// react_pfr=NULL; +// react_cstr=NULL; +// heat=NULL; + + burn = new burner ( s[0]->nb , s[0]->chem ); +} + +/*---------------------------------------------------------------------*/ +servor::~servor() { + delete [] type; + delete [] name; + delete burn; +} + +/*---------------------------------------------------------------------*/ +bool servor::solve_process ( const double * x , double * y ) { + + + for ( i = 0 ; i < 8 ; i++ ) + costs[i] = 0.0; + + k = 0; + norm = 1.0 / TOL_WEGSTEIN; + + for ( cursor = 0 ; cursor < nb ; cursor++ ) { + + if (type[cursor] == "mix" ) { + do_mix_process(x); + } + else if ( type[cursor] == "split" ) { + do_split_process(x); + } + else if ( type[cursor] == "flash" ) { + do_flash_process(x); + } + else if ( type[cursor] == "pump" ) { + do_pump_process(x); + } + else if ( type[cursor] == "heatx") { + do_heatx_process(x); + } + else if ( type[cursor] == "burner" ) { + do_burner_process(x,y); + } + else if ( type[cursor] == "column" ) { + do_column_process(x,y); + } + else if ( type[cursor] == "reactor" ) { + do_reactor_process(x); + } + else if ( type[cursor] == "loop" ) { + + recycle = 10; + end_recycle = 0; + do_loop_process(x); + } + else { + cout << "ERROR 18\n\n"; + exit(0); + } + + } + + return true; +} + + +/*---------------------------------------------------------------------*/ +void servor::do_loop_process ( const double * x ) { + + // structure in the input file : + // loop + // name : "looping" + // index of recycle stream : 11 + // index of stream's beginning block : 7 + // index of stream's end block : 1 + + // TOTO +// if (k==0) +// cout << endl << " -> Wegstein iterations "; +// else if ( k <= 2 ) +// cout << endl << " -> loop " << setw(3) << k; +// else +// cout << endl << " -> loop " << setw(3) << k << " > error " << norm; + + // Get the two fisrst points + if ( k==0 ) { + for ( i = 0 ; i < s[0]->nb ; i++ ) + x_last[i] = s[recycle]->chem[i]->m; + end_loop = false; + } + + if ( k==1 ) { + for ( i = 0 ; i < s[0]->nb ; i++ ) { + x_now [i] = s[recycle]->chem[i]->m; + g_last[i] = s[recycle]->chem[i]->m; + } + + end_loop = false; + } + + if ( k == 2 ) { + for ( i = 0 ; i < s[0]->nb ; i++ ) + g_now[i] = s[recycle]->chem[i]->m; + end_loop=false; + } + k++; + + + // run the Wegstein algorithm + if ( k > 2 ) { + for ( i = 0 ; i < s[0]->nb ; i++ ) { + g_now[i] = s[recycle]->chem[i]->m; + + if ( fabs (x_now[i]-x_last[i]) > EPS ) + slope[i] = ( g_now[i] - g_last[i] ) / ( x_now[i] - x_last[i] ); + else + slope[i] = 0; + + theta[i] = 1.0 / (1.0-slope[i]); + if ( theta[i] < MIN_THETA ) + theta[i] = MIN_THETA; + if ( theta[i] > MAX_THETA ) + theta[i] = MAX_THETA; + x_next[i] = (1.0-theta[i])*x_now[i] + theta[i]*g_now[i]; + } + norm = 0.0; + for ( i = 0 ; i < s[0]->nb ; i++ ) + if ( fabs(x_now[i]) > EPS ) + norm += fabs (x_next[i]-x_now[i]) / fabs(x_now[i]); + + if ( norm > TOL_WEGSTEIN && k < MAX_ITER_WEGSTEIN ) { + s[recycle]->m = 0.0; + for ( i = 0 ; i < s[0]->nb ; i++ ) { + s[recycle]->chem[i]->m = x_next[i]; + s[recycle]->m += x_next[i]; + x_last[i] = x_now[i]; + g_last[i] = g_now[i]; + x_now[i] = x_next[i]; + } + end_loop=false; + } + if ( norm <= TOL_WEGSTEIN && k < MAX_ITER_WEGSTEIN ) + end_loop = true; + + } + + + if ( end_loop ) { + if ( k < MAX_ITER_WEGSTEIN && k > 3 ) { + // cout<<" OK"; // TOTO + // s[recycle]->write(); // WRITE TOTO + +// // WRITE TOTO : +// cout << "WRITE FILE " << RUNTIME << name[cursor] << ".unit" << " :\n\tBEGIN\n"; +// cout << "\t>> " << name[cursor]; +// cout << endl << "\t>> from block " << cursor+1 << " to block " << end_recycle+1; +// cout << endl << "\t>> Wegstein converged in " +// << k << " iterations (rel. err. " << norm << ")."; +// cout << "\n\tEND\n\n"; + + k = 0; + norm = 1.0/TOL_WEGSTEIN; + } +// else { +// log.open(MESSAGES, ios::app); +// log<<" ==> Error <== Wegstein algorithm did not converge.\n"; +// log.close(); +// } + } + + + if ( !end_loop && k < MAX_ITER_WEGSTEIN ) + cursor = end_recycle-1; + if ( !end_loop && k==MAX_ITER_WEGSTEIN ) { +// log.open(MESSAGES, ios::app); +// log<<" ==> Error <== Wegstein algorithm did not converge.\n"; +// log.close(); + k=0; + norm = 1.0/TOL_WEGSTEIN; + cursor=nb; + } + +} + +/*---------------------------------------------------------------------*/ +void servor::do_burner_process ( const double * x , double * y ) { + + // cout << endl << " -- " << name[cursor] << "... "; // TOTO + + // read parameters : + int i1 = 8; + int i2 = 13; + double f = x[6]; + + burn->set ( s[i1-1] , s[i2-1] ); + burn->set(f); + burn->set(name[cursor]); + + if ( burn->solve(y) ) { + // cout << "OK"; // TOTO + // burn->write(); // WRITE TOTO + costs[7] = burn->get_cost(); + } + else { + cout << "ERROR 20\n\n"; + exit(0); + } +} + +/*---------------------------------------------------------------------*/ +void servor::do_split_process ( const double * x ) +{ + // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO + + //Read parameters + int i1 = 9; + int i2 = 2; + int i_tab[2] = { 10 , 11 }; + double f_tab[2]; + f_tab[0] = x[5]; + f_tab[1] = 1-x[5]; + + stream * list1[2]; + list1[0] = s[i_tab[0]-1]; + list1[1] = s[i_tab[1]-1]; + + split * split1 = new split ( i2 , s[i1-1] , list1 ); + + split1->set(f_tab); + split1->set(name[cursor]); + if ( split1->solve() ) { + // cout<<"OK"; // TOTO + // split1->write(); // WRITE TOTO + } + else { + cout << "ERROR 19\n\n"; + exit(0); + } + delete split1; +} + +/*---------------------------------------------------------------------*/ +void servor::do_column_process ( const double * x , double * y ) { + // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO + + //Read parameters + double f1 , f2; + int i , i1 , i2; + int i_tab[2]; + double f = 1.0; + + if (name[cursor]=="sep-sty") { + i = 7; + i1 = 15; + i2 = 9; + i_tab[0] = 1; + i_tab[1] = 7; + f1 = f2 = x[2]; + } + else if (name[cursor]=="sep-bz") { + i = 10; + i1 = 12; + i2 = 14; + i_tab[0] = 5; + i_tab[1] = 1; + f1 = f2 = x[3]; + } + else { + cout << "ERROR 17\n\n"; + exit(0); + } + + column * col = new column ( s[i-1] , s[i1-1] , s[i2-1] ); + col->set ( f , i_tab[0] , f1 , i_tab[1] , f2 ); + col->set(name[cursor]); + if ( col->solve() ) { + //cout<<"OK"; // TOTO + //col->write(); // WRITE TOTO + + if (name[cursor]=="sep-sty") { + y[4] = col->get_N(); + costs[5] = col->get_cost(); + power[5] = col->get_power(); + water[5] = col->get_water(); + } + else { + y[5] = col->get_N(); + costs[6] = col->get_cost(); + power[4] = col->get_power(); + water[4] = col->get_water(); + } + } + else { + cout << "ERROR 15\n\n"; + exit(0); + } + delete col; +} + +/*---------------------------------------------------------------------*/ +void servor::do_flash_process ( const double * x ) { + // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO + + //Read parameters + double f1 = 1.0; + double f2 = x[7]; + // int i_tab [3] = { 6 , 7 , 8 }; + // flash * flash1 = new flash ( s[i_tab[0]-1] , s[i_tab[1]-1] , s[i_tab[2]-1] ); + flash * flash1 = new flash ( s[5] , s[6] , s[7] ); + + flash1->set(f1, f2); + flash1->set(name[cursor]); + if ( flash1->solve() ) { + // cout<<"OK"; // TOTO + // flash1->write(); // WRITE TOTO + costs[4] = flash1->get_cost(); + power[2] = flash1->get_power(); + water[1] = flash1->get_water(); + } + else { + cout << "ERROR 14\n\n"; + exit(0); + } + delete flash1; +} + + +/*---------------------------------------------------------------------*/ +void servor::do_mix_process ( const double * x ) { + + // cout << endl << " -- " << name[cursor] << "... "; // TOTO + + // Read parameters (hardcode avec eb2sty.process) : + double f1 = 1.0; + int i1 = 3; + int i_tab[3] = { 1 , 12 , 11 }; + int i2 = 2; + + // We can solve the unit + stream * list2 = s[i2-1] , ** list1 = new stream * [i1]; + for ( int i = 0 ; i < i1 ; i++ ) + list1[i] = s[i_tab[i]-1]; + mix * mix1 = new mix ( i1 , list1 , list2 ); + mix1->set(f1); + mix1->set(name[cursor]); + if (mix1->solve()) { + // cout<<"OK"; // TOTO + // mix1->write(); // WRITE TOTO + } + else { + cout << "ERROR 6\n\n"; + exit(0); + } + delete mix1; + delete [] list1; +} + + +/*---------------------------------------------------------------------*/ +void servor::do_pump_process ( const double * x ) { + + // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO + + //Read parameters (hardcode avec eb2sty.process) : + int i1 = 2; + int i2 = 3; + double f1 = x[4]; + double f2 = 0.75; + + pump * pump1 = new pump ( s[i1-1] , s[i2-1] ); + pump1->set(f1,f2); + pump1->set(name[cursor]); + + + + // solve : + if ( pump1->solve() ) { + // cout<<"OK"; // TOTO + // pump1->write(); // WRITE TOTO + + power[0] = pump1->get_power(); + costs[0] = pump1->get_cost(); + } + else { + cout << "ERROR 7\n\n"; + exit(0); + } + + delete pump1; +} + +/*---------------------------------------------------------------------*/ +void servor::do_heatx_process ( const double * x ) { + + // cout << endl << " -- " << name[cursor] << "... "; // TOTO + + //Read parameters (idem) : + + bool b = false; + + // heater : + int i1; + int i2; + double f1; + + // heater : + if (name[cursor]=="heater") { + i1 = 3; + i2 = 4; + f1 = x[0]; + } + + // cooler : + else if (name[cursor]=="cooler") { + i1 = 5; + i2 = 6; + f1 = x[7]; + } + else { + cout << "ERROR 16\n\n"; + exit(0); + } + + double f2 = 0.85; + + // solve : + heatx * heat = new heatx ( b , s[i1-1] , s[i2-1] ); + heat->set(f1,f2); + heat->set(name[cursor]); + if (heat->solve()) { + // cout<<"OK"; // TOTO + // heat->write(); // WRITE TOTO + if (name[cursor]=="heater") { + costs[1] = heat->get_cost(); + power[3] = heat->get_power(); + water[2] = heat->get_water(); + } + else { + costs[3] = heat->get_cost(); + power[1] = heat->get_power(); + water[0] = heat->get_water(); + } + } + else { + cout << "ERROR 8\n\n"; + exit(0); + } + delete heat; +} + +/*---------------------------------------------------------------------*/ +void servor::do_reactor_process ( const double * x ) { + + // cout<<endl<<" -- "<<name[cursor]<<"... "; // TOTO + + // Read parameters (idem) : + int i1 = 4; + int i2 = 5; + + reactor<pfr> * react_pfr = new reactor<pfr> ( s[i1-1] , s[i2-1] ); + + react_pfr->set(name[cursor]); + + double f1 = x[1]; + double f2 = 0.5; + + string list[5] = { "eb2sty" , "sty2eb" , "eb2bz" , "eb2tol" , "tol2bz" }; + + i1 = 5; + + react_pfr->set(f1,f2,i1,list); + + f1 = 0.0; + f2 = 300.0; + + react_pfr->set(f1,f2); + + if ( react_pfr->solve() ) { + // cout<<"OK"; // TOTO + // react_pfr->write(); // WRITE TOTO + costs[2] = react_pfr->get_cost(); + water[3] = react_pfr->get_water(); + } + else { + cout << "ERROR 9\n\n"; + exit(0); + } + delete react_pfr; +} + + +double servor::get_costs_sum ( void ) const { + double sum = 0.0; + for ( int i = 0 ; i < 8 ; i++ ) + sum += ( (ARRONDI) ? arrondi(costs[i],6) : costs[i] ); + return sum; +} + +double servor::get_power_sum ( void ) const { + double sum = 0.0; + for ( int i = 0 ; i < 6 ; i++ ) + sum += ( (ARRONDI) ? arrondi(power[i],6) : power[i] ); + return sum; +} + +double servor::get_water_sum ( void ) const { + double sum = 0.0; + for ( int i = 0 ; i < 6 ; i++ ) + sum += ( (ARRONDI) ? arrondi(water[i],6) : water[i] ); + return sum; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/servor.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/servor.hpp index e048542..73b1cd2 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/servor.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/servor.hpp @@ -1,101 +1,101 @@ -#ifndef SERVOR_H -#define SERVOR_H - -//Possible units -#include "mix.hpp" -#include "split.hpp" -#include "pump.hpp" -#include "column.hpp" -#include "reactor.hpp" -#include "heatx.hpp" -#include "burner.hpp" - -using namespace std; - -class servor { - -public: - - double norm; - int k; - int nb; - int nb_s; - string * type; - string * name; - int cursor; - stream ** s; - - int recycle; - int end_recycle; - int i; - bool end_loop; - - double x_last[MAX_DIM]; - double x_now [MAX_DIM]; - double x_next[MAX_DIM]; - double g_last[MAX_DIM]; - double g_now [MAX_DIM]; - double slope [MAX_DIM]; - double theta [MAX_DIM]; - - double costs[8]; - double power[6]; - double water[6]; - - - // clock_t beg_time, end_time; - // bool OK, b, solve_OK; - // char filename[31], kind[10], **list, process_name[31]; - // double f, f1, f2, f_tab[10], t; - // int i, i1, i2, i_tab[10], time; - // stream *list2; - -// double theta[MAX_DIM], slope[MAX_DIM], norm; -// bool end_loop; -// int k, recycle, end_recycle; -// char loop_name[31]; - -// mix *mix1; void do_mix(); -// split *split1; -// flash *flash1; void do_flash(); -// pump *pump1; void do_pump(); -// column *col; void do_column(); -// reactor<pfr> *react_pfr; void do_reactor(); -// reactor<cstr> *react_cstr; -// heatx *heat; void do_heatx(); - burner * burn; - -// stream *s; //list of streams -// friend void out_of_memory(void){exit(0);} - - - // constructeur : - servor ( int , int , stream ** ); - - // destructeur : - ~servor(); - - -// void set(int t) {time=t;} -// void set(char n[31]) {strcpy(process_name, n);} - void do_split_process ( const double * x ); - void do_column_process ( const double * x , double * y ); - void do_flash_process ( const double * x ); - void do_mix_process ( const double * x ); - void do_pump_process ( const double * x ); - void do_heatx_process ( const double * x ); - void do_reactor_process ( const double * x ); - void do_burner_process ( const double * x , double * y ); - void do_loop_process ( const double * x ); - - bool solve_process ( const double * x , double * y ); //main solver of the software. - - double get_costs_sum ( void ) const; - - double get_power_sum ( void ) const; - - double get_water_sum ( void ) const; - - -}; -#endif +#ifndef SERVOR_H +#define SERVOR_H + +//Possible units +#include "mix.hpp" +#include "split.hpp" +#include "pump.hpp" +#include "column.hpp" +#include "reactor.hpp" +#include "heatx.hpp" +#include "burner.hpp" + +using namespace std; + +class servor { + +public: + + double norm; + int k; + int nb; + int nb_s; + string * type; + string * name; + int cursor; + stream ** s; + + int recycle; + int end_recycle; + int i; + bool end_loop; + + double x_last[MAX_DIM]; + double x_now [MAX_DIM]; + double x_next[MAX_DIM]; + double g_last[MAX_DIM]; + double g_now [MAX_DIM]; + double slope [MAX_DIM]; + double theta [MAX_DIM]; + + double costs[8]; + double power[6]; + double water[6]; + + + // clock_t beg_time, end_time; + // bool OK, b, solve_OK; + // char filename[31], kind[10], **list, process_name[31]; + // double f, f1, f2, f_tab[10], t; + // int i, i1, i2, i_tab[10], time; + // stream *list2; + +// double theta[MAX_DIM], slope[MAX_DIM], norm; +// bool end_loop; +// int k, recycle, end_recycle; +// char loop_name[31]; + +// mix *mix1; void do_mix(); +// split *split1; +// flash *flash1; void do_flash(); +// pump *pump1; void do_pump(); +// column *col; void do_column(); +// reactor<pfr> *react_pfr; void do_reactor(); +// reactor<cstr> *react_cstr; +// heatx *heat; void do_heatx(); + burner * burn; + +// stream *s; //list of streams +// friend void out_of_memory(void){exit(0);} + + + // constructeur : + servor ( int , int , stream ** ); + + // destructeur : + ~servor(); + + +// void set(int t) {time=t;} +// void set(char n[31]) {strcpy(process_name, n);} + void do_split_process ( const double * x ); + void do_column_process ( const double * x , double * y ); + void do_flash_process ( const double * x ); + void do_mix_process ( const double * x ); + void do_pump_process ( const double * x ); + void do_heatx_process ( const double * x ); + void do_reactor_process ( const double * x ); + void do_burner_process ( const double * x , double * y ); + void do_loop_process ( const double * x ); + + bool solve_process ( const double * x , double * y ); //main solver of the software. + + double get_costs_sum ( void ) const; + + double get_power_sum ( void ) const; + + double get_water_sum ( void ) const; + + +}; +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/split.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/split.cpp index d3f48c9..d14c519 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/split.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/split.cpp @@ -1,53 +1,53 @@ -#include "split.hpp" -using namespace std; - -split::split(int n, stream* s1, stream** s2) -{ - nb_out=n; - in = s1; - out= s2; - success = true; -} - -bool split::solve() -{ - tmp=0; - for (i=0;i<nb_out; i++) tmp+=frac[i]; - if(fabs(1-tmp)<=EPS) - { - success = true; - for (i=0; i<nb_out;i++) - { - out[i]->m=0; - for (j=0;j<in->nb;j++) - { - - out[i]->chem[j]->m = frac[i]*in->chem[j]->m; - out[i]->m += out[i]->chem[j]->m; - } - out[i]->set(in->P, in->T); - // out[i]->write(); // TOTO - } - } - tmp=0; for(i=0;i<nb_out;i++) tmp+=out[i]->m; - if(fabs(tmp-in->m)>EPS) - { -// logf.open(MESSAGES, ios::app); -// logf<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(tmp-in->m)/tmp<<").\n"; -// logf.close(); - success = false; - } - else success = true; - return success; -} - -void split::write() -{ - cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; - cout <<"\t>> "<<name; - cout << endl<<"\t>> stream in: "<<in->name;; - cout<<endl<<"\t>> streams out: "<<setprecision(3); - for ( i = 0 ; i < nb_out ; i++ ) - cout << out[i]->name<<" ("<<frac[i]<<") "; - cout << "\n\tEND\n\n"; -} +#include "split.hpp" +using namespace std; + +split::split(int n, stream* s1, stream** s2) +{ + nb_out=n; + in = s1; + out= s2; + success = true; +} + +bool split::solve() +{ + tmp=0; + for (i=0;i<nb_out; i++) tmp+=frac[i]; + if(fabs(1-tmp)<=EPS) + { + success = true; + for (i=0; i<nb_out;i++) + { + out[i]->m=0; + for (j=0;j<in->nb;j++) + { + + out[i]->chem[j]->m = frac[i]*in->chem[j]->m; + out[i]->m += out[i]->chem[j]->m; + } + out[i]->set(in->P, in->T); + // out[i]->write(); // TOTO + } + } + tmp=0; for(i=0;i<nb_out;i++) tmp+=out[i]->m; + if(fabs(tmp-in->m)>EPS) + { +// logf.open(MESSAGES, ios::app); +// logf<<" --> Warning <-- Block "<<name<<" is not in mass balance ("<<fabs(tmp-in->m)/tmp<<").\n"; +// logf.close(); + success = false; + } + else success = true; + return success; +} + +void split::write() +{ + cout << "WRITE FILE " << RUNTIME << name << ".unit" << " :\n\tBEGIN\n"; + cout <<"\t>> "<<name; + cout << endl<<"\t>> stream in: "<<in->name;; + cout<<endl<<"\t>> streams out: "<<setprecision(3); + for ( i = 0 ; i < nb_out ; i++ ) + cout << out[i]->name<<" ("<<frac[i]<<") "; + cout << "\n\tEND\n\n"; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/split.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/split.hpp index 2c75638..7634f47 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/split.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/split.hpp @@ -1,43 +1,43 @@ -/* -This unit takes one input stream and divides in two or more -output streams. The pressure and temparature of output streams -are the same as the input's. - -Structure in the .process file: -split {name} {index of input stream} {nb_out} {indexes of output streams and fractions of input} - -How to use: - 1- Call the constructor: split1 = new split(nb_out, in, list_out); - 2- Set split fractions: split1->set(fractions); - 3- Set the name: split1->set(name); - 4- Solve: split1->solve(); -*/ -#ifndef SPLIT_H -#define SPLIT_H - -#include "stream.hpp" -using namespace std; - -class split -{ -private: - - int i, j; - bool success; - double tmp; - string name; - int nb_out; //number of input streams - stream *in; //pointer to input stream - stream **out; //list of pointers to output streams - double *frac; //list of split fractions - -public: - split(int, stream*, stream**); //defines the connectivities of this unit - ~split(){} - void set(double* f) {frac=f;} - void set(const string & n) { name = n;} - bool solve(); //finds the temperature and computes mass balance - void write(); -}; - -#endif +/* +This unit takes one input stream and divides in two or more +output streams. The pressure and temparature of output streams +are the same as the input's. + +Structure in the .process file: +split {name} {index of input stream} {nb_out} {indexes of output streams and fractions of input} + +How to use: + 1- Call the constructor: split1 = new split(nb_out, in, list_out); + 2- Set split fractions: split1->set(fractions); + 3- Set the name: split1->set(name); + 4- Solve: split1->solve(); +*/ +#ifndef SPLIT_H +#define SPLIT_H + +#include "stream.hpp" +using namespace std; + +class split +{ +private: + + int i, j; + bool success; + double tmp; + string name; + int nb_out; //number of input streams + stream *in; //pointer to input stream + stream **out; //list of pointers to output streams + double *frac; //list of split fractions + +public: + split(int, stream*, stream**); //defines the connectivities of this unit + ~split(){} + void set(double* f) {frac=f;} + void set(const string & n) { name = n;} + bool solve(); //finds the temperature and computes mass balance + void write(); +}; + +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/stream.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/stream.cpp index 8854441..408c1cb 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/stream.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/stream.cpp @@ -1,265 +1,265 @@ -#include "stream.hpp" -using namespace std; - -// destructor : -stream::~stream ( void ) { - delete thermo; - delete [] tab1; - delete [] tab2; - delete [] tab3; - delete [] tab4; - for ( i = 0 ; i < nb ; i++ ) - delete chem[i]; - delete [] chem; -} - -void stream::check_error() -{ - - if (error>MAX_ERROR) { - cout << "ERROR 4\n\n"; - exit(0); - } - if (warning>MAX_WARNING) { - cout << "ERROR 5\n\n"; - exit(0); - } -} - -void stream::set ( int _nb , chemical ** _chem) { - int i; - for ( i = 0 ; i < nb ; i++ ) - delete chem[i]; - delete [] chem; - nb = _nb; - chem = new chemical * [nb]; - for ( i = 0 ; i < nb ; i++ ) - chem[i] = new chemical(*_chem[i]); -} - -void stream::set(double pres, double temp) //set P, T, find state and resulting v -{ - if(thermo->get_dim()!=nb) - { - delete thermo; - thermo = new thermolib(nb); - } - P=pres; - T=temp; - for (i=0;i<nb;i++) {chem[i]->P=pres; chem[i]->T=temp;} - if(n()>EPS) - { - v=quality(); - tmp1=0; - for (i=0;i<nb;i++) - { - if (T>chem[i]->Tc || v==1) chem[i]->state=1; - else chem[i]->state=0; - } - v=0; - for (i=0;i<nb;i++) - { - if (chem[i]->state==0) {if (chem[i]->m>EPS) v+= chem[i]->m/chem[i]->rho(); tab4[i]=0;} - if (chem[i]->state==1) {tab4[i] = chem[i]->n(); tmp1+=tab4[i];} - } - if (tmp1>EPS) - { - for (i=0;i<nb;i++) - { - tab1[i] = chem[i]->Pc; //cout<<endl<<tab1[i]; - tab2[i] = chem[i]->Tc; // cout<<" "<<tab2[i]; - tab3[i] = chem[i]->omega(); //cout<<" "<<tab3[i]; - tab4[i]/=tmp1; // cout<<" "<<tab4[i]; - } - thermo->send(tab1,tab2,tab3, tab4); - thermo->set(P,T,0.0,tmp1); - v+=thermo->v(); - } - } - else v= 0.0; -} - -void stream::set(double *list) -{ - m=0; - for (i=0; i<nb; i++) - { - chem[i]->m=list[i]; - m+=list[i]; - } -} - -void stream::bubble() -{ - bp=1.1e6; - for(i=0;i<nb;i++) if(T<chem[i]->Tc && chem[i]->Tboil(P)<bp && chem[i]->m>EPS) bp=chem[i]->Tboil(P); - if (bp==1.1e6) bp=0.0; - else - { - step=2; - while (fabs(step)>TOL_BP && fabs(tmp1-1)>TOL_BP) - { - //if(DEBUG) cout<<endl<<bp; - bp+=step; - tmp1=tmp2=0; - for (i=0;i<nb;i++) if(T<chem[i]->Tc) {tmp2+=chem[i]->n(); tmp1+=chem[i]->n()*chem[i]->Psat(bp)/P;} - tmp1/=tmp2; - step=10*(1.0-tmp1); - } - } -} - -void stream::dew() -{ - dp=0.0; - tmp1=10; - for(i=0;i<nb;i++) if(T<chem[i]->Tc && chem[i]->Tboil(P)>dp && chem[i]->m>EPS) dp=chem[i]->Tboil(P); - if (dp>EPS) - { - dp=bp; - step=1; - while (fabs(step)>TOL_DP && fabs(tmp1/tmp2-1)>TOL_DP) - { - dp+=step; - if(dp<bp) dp=bp; - //if(DEBUG) cout<<endl<<dp; - tmp1=tmp2=0; - for (i=0;i<nb;i++) if(T<chem[i]->Tc) {tmp2+=chem[i]->n(); tmp1+=chem[i]->n()/chem[i]->Psat(dp)*P; } - if (step/fabs(step)*tmp2/tmp1 >1 || step/fabs(step)*tmp1/tmp2 <-1) step*= -0.1; - } - } -} - -double stream::quality() -{ - if(T>EPS) - { - bubble(); - dew(); - //if(DEBUG) cout<<endl<<name<<" bp="<<bp<<" dp="<<dp<<" T="<<T; system("pause"); - if (bp < dp) - { - if (bp < T && T< dp) tmp= (T-bp)/(dp-bp); - if (T<= bp) tmp= 0.0; - if (T >= dp) tmp= 1.0; - } - } - else tmp= 0.0; - return tmp; -} - -double stream::K(int i) -{ - for (j=0;j<nb;j++) - tab4[j] = chem[j]->n()/n(); - thermo->send(tab1,tab2,tab3, tab4); - if (T>EPS && P>EPS) - { - thermo->set(P,T,v,n()); - return thermo->K(i); - } - else - { - ofstream logf; - logf.open(MESSAGES, ios::app); - logf<<" --> Warning <-- Cannot compute K of "<<chem[i]->name<<" in stream "<<name<<".\n"; - logf.close(); - warning++; - check_error(); - return 1.0; - } -} - -double stream::n() -{ - tmp=0.0; - for ( k = 0 ; k < nb ; k++ ) - tmp+=chem[k]->n(); - return tmp; -} - - -// affectation : -stream & stream::operator = ( const stream & s ) { - - (*thermo) = *(s.thermo); - - delete [] tab1; - delete [] tab2; - delete [] tab3; - delete [] tab4; - for ( i = 0 ; i < nb ; i++ ) - delete chem[i]; - delete [] chem; - - P = s.P; - T = s.T; - m = s.m; - v = s.v; - i = s.i; - j = s.j; - k = s.k; - error = s.error; - warning = s.warning; - name = s.name; - nb = s.nb; - chem = new chemical *[nb]; - - tab1 = new double[nb]; - tab2 = new double[nb]; - tab3 = new double[nb]; - tab4 = new double[nb]; - - step = s.step; - - for ( i = 0 ; i < nb ; i++ ) { - chem[i] = new chemical(*s.chem[i]); - tab1[i] = s.tab1[i]; - tab2[i] = s.tab2[i]; - tab3[i] = s.tab3[i]; - tab4[i] = s.tab4[i]; - } - - tmp = s.tmp; - tmp1 = s.tmp1; - tmp2 = s.tmp2; - - return *this; -} - - -void stream::write() { - - string file_name = RUNTIME + name + ".stream"; - - cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; - - cout.unsetf(ios::scientific); - cout << setiosflags(ios::showpoint | ios::fixed)<<setprecision(1); - - cout << "\t>>" << setw(8) << P << " " << setw(9) << T <<" "; - - cout << resetiosflags(ios::fixed) << setiosflags(ios::scientific) << setprecision(3); - - if (m>EPS) - cout << setw(11) << m << setw(11) << v; - else - cout << " x x "; - for ( i = 0 ; i < nb ; i++ ) { - if ( chem[i]->m <= EPS ) - cout << " x "; - else - cout << setw(11) << chem[i]->m; - } - cout << "\n\tEND\n\n"; - - cout.setf(ios::scientific); - -} - -void stream::purge() -{ - P=T=m=v=0.0; - for(i=0;i<nb;i++) - chem[i]->purge(); -} +#include "stream.hpp" +using namespace std; + +// destructor : +stream::~stream ( void ) { + delete thermo; + delete [] tab1; + delete [] tab2; + delete [] tab3; + delete [] tab4; + for ( i = 0 ; i < nb ; i++ ) + delete chem[i]; + delete [] chem; +} + +void stream::check_error() +{ + + if (error>MAX_ERROR) { + cout << "ERROR 4\n\n"; + exit(0); + } + if (warning>MAX_WARNING) { + cout << "ERROR 5\n\n"; + exit(0); + } +} + +void stream::set ( int _nb , chemical ** _chem) { + int i; + for ( i = 0 ; i < nb ; i++ ) + delete chem[i]; + delete [] chem; + nb = _nb; + chem = new chemical * [nb]; + for ( i = 0 ; i < nb ; i++ ) + chem[i] = new chemical(*_chem[i]); +} + +void stream::set(double pres, double temp) //set P, T, find state and resulting v +{ + if(thermo->get_dim()!=nb) + { + delete thermo; + thermo = new thermolib(nb); + } + P=pres; + T=temp; + for (i=0;i<nb;i++) {chem[i]->P=pres; chem[i]->T=temp;} + if(n()>EPS) + { + v=quality(); + tmp1=0; + for (i=0;i<nb;i++) + { + if (T>chem[i]->Tc || v==1) chem[i]->state=1; + else chem[i]->state=0; + } + v=0; + for (i=0;i<nb;i++) + { + if (chem[i]->state==0) {if (chem[i]->m>EPS) v+= chem[i]->m/chem[i]->rho(); tab4[i]=0;} + if (chem[i]->state==1) {tab4[i] = chem[i]->n(); tmp1+=tab4[i];} + } + if (tmp1>EPS) + { + for (i=0;i<nb;i++) + { + tab1[i] = chem[i]->Pc; //cout<<endl<<tab1[i]; + tab2[i] = chem[i]->Tc; // cout<<" "<<tab2[i]; + tab3[i] = chem[i]->omega(); //cout<<" "<<tab3[i]; + tab4[i]/=tmp1; // cout<<" "<<tab4[i]; + } + thermo->send(tab1,tab2,tab3, tab4); + thermo->set(P,T,0.0,tmp1); + v+=thermo->v(); + } + } + else v= 0.0; +} + +void stream::set(double *list) +{ + m=0; + for (i=0; i<nb; i++) + { + chem[i]->m=list[i]; + m+=list[i]; + } +} + +void stream::bubble() +{ + bp=1.1e6; + for(i=0;i<nb;i++) if(T<chem[i]->Tc && chem[i]->Tboil(P)<bp && chem[i]->m>EPS) bp=chem[i]->Tboil(P); + if (bp==1.1e6) bp=0.0; + else + { + step=2; + while (fabs(step)>TOL_BP && fabs(tmp1-1)>TOL_BP) + { + //if(DEBUG) cout<<endl<<bp; + bp+=step; + tmp1=tmp2=0; + for (i=0;i<nb;i++) if(T<chem[i]->Tc) {tmp2+=chem[i]->n(); tmp1+=chem[i]->n()*chem[i]->Psat(bp)/P;} + tmp1/=tmp2; + step=10*(1.0-tmp1); + } + } +} + +void stream::dew() +{ + dp=0.0; + tmp1=10; + for(i=0;i<nb;i++) if(T<chem[i]->Tc && chem[i]->Tboil(P)>dp && chem[i]->m>EPS) dp=chem[i]->Tboil(P); + if (dp>EPS) + { + dp=bp; + step=1; + while (fabs(step)>TOL_DP && fabs(tmp1/tmp2-1)>TOL_DP) + { + dp+=step; + if(dp<bp) dp=bp; + //if(DEBUG) cout<<endl<<dp; + tmp1=tmp2=0; + for (i=0;i<nb;i++) if(T<chem[i]->Tc) {tmp2+=chem[i]->n(); tmp1+=chem[i]->n()/chem[i]->Psat(dp)*P; } + if (step/fabs(step)*tmp2/tmp1 >1 || step/fabs(step)*tmp1/tmp2 <-1) step*= -0.1; + } + } +} + +double stream::quality() +{ + if(T>EPS) + { + bubble(); + dew(); + //if(DEBUG) cout<<endl<<name<<" bp="<<bp<<" dp="<<dp<<" T="<<T; system("pause"); + if (bp < dp) + { + if (bp < T && T< dp) tmp= (T-bp)/(dp-bp); + if (T<= bp) tmp= 0.0; + if (T >= dp) tmp= 1.0; + } + } + else tmp= 0.0; + return tmp; +} + +double stream::K(int i) +{ + for (j=0;j<nb;j++) + tab4[j] = chem[j]->n()/n(); + thermo->send(tab1,tab2,tab3, tab4); + if (T>EPS && P>EPS) + { + thermo->set(P,T,v,n()); + return thermo->K(i); + } + else + { + ofstream logf; + logf.open(MESSAGES, ios::app); + logf<<" --> Warning <-- Cannot compute K of "<<chem[i]->name<<" in stream "<<name<<".\n"; + logf.close(); + warning++; + check_error(); + return 1.0; + } +} + +double stream::n() +{ + tmp=0.0; + for ( k = 0 ; k < nb ; k++ ) + tmp+=chem[k]->n(); + return tmp; +} + + +// affectation : +stream & stream::operator = ( const stream & s ) { + + (*thermo) = *(s.thermo); + + delete [] tab1; + delete [] tab2; + delete [] tab3; + delete [] tab4; + for ( i = 0 ; i < nb ; i++ ) + delete chem[i]; + delete [] chem; + + P = s.P; + T = s.T; + m = s.m; + v = s.v; + i = s.i; + j = s.j; + k = s.k; + error = s.error; + warning = s.warning; + name = s.name; + nb = s.nb; + chem = new chemical *[nb]; + + tab1 = new double[nb]; + tab2 = new double[nb]; + tab3 = new double[nb]; + tab4 = new double[nb]; + + step = s.step; + + for ( i = 0 ; i < nb ; i++ ) { + chem[i] = new chemical(*s.chem[i]); + tab1[i] = s.tab1[i]; + tab2[i] = s.tab2[i]; + tab3[i] = s.tab3[i]; + tab4[i] = s.tab4[i]; + } + + tmp = s.tmp; + tmp1 = s.tmp1; + tmp2 = s.tmp2; + + return *this; +} + + +void stream::write() { + + string file_name = RUNTIME + name + ".stream"; + + cout << "WRITE FILE " << file_name << " :\n\tBEGIN\n"; + + cout.unsetf(ios::scientific); + cout << setiosflags(ios::showpoint | ios::fixed)<<setprecision(1); + + cout << "\t>>" << setw(8) << P << " " << setw(9) << T <<" "; + + cout << resetiosflags(ios::fixed) << setiosflags(ios::scientific) << setprecision(3); + + if (m>EPS) + cout << setw(11) << m << setw(11) << v; + else + cout << " x x "; + for ( i = 0 ; i < nb ; i++ ) { + if ( chem[i]->m <= EPS ) + cout << " x "; + else + cout << setw(11) << chem[i]->m; + } + cout << "\n\tEND\n\n"; + + cout.setf(ios::scientific); + +} + +void stream::purge() +{ + P=T=m=v=0.0; + for(i=0;i<nb;i++) + chem[i]->purge(); +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/stream.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/stream.hpp index 94b2102..895ef3d 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/stream.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/stream.hpp @@ -1,86 +1,86 @@ -#ifndef STREAM_H -#define STREAM_H -#include "chemical.hpp" -#include <iomanip> -using namespace std; - -class stream { - -private: - - stream ( void ) {} - stream ( const stream & s ) {} - -public: - void check_error(); - - double P, T, m, v; // Pressure in atm, temperature in K, - // total mass flow in kg/s, total volume flow in m3/s - - int i, j, k, error, warning; - - string name; - - int nb; // number of chemicals to store; - - chemical ** chem; // list of stored chemicals - - thermolib *thermo; - - double tmp, tmp1,tmp2, *tab1, *tab2, *tab3, *tab4; - double step; - void bubble(), dew(); - -public: - - - - - - double dp, bp; - double rho() {if(v!=0) return m/v; else exit(0);} // Apparent density in kg/m3 - double n(); // total mole flow (mol/s) - double quality(); // returns the vapor fraction of stream (1=all vapor, 0 = all liquid) - double K(int); // returns the vapor-liquid equilibrium constant of compound i - - // constructor : - stream ( const string _name , int n , chemical ** list ) : P (0 ) , - T (0 ) , - m (0 ) , - v (0 ) , - error (0 ) , - warning(0 ) , - name (_name ) , - nb (n ) , - chem (new chemical *[nb]) , - thermo (new thermolib (nb)) , - tab1 (new double [nb]) , - tab2 (new double [nb]) , - tab3 (new double [nb]) , - tab4 (new double [nb]) { - for ( i = 0 ; i < nb ; i++ ) - chem[i] = new chemical(*list[i]); - } - - - // affectation : - stream & operator = ( const stream & s ); - - void set_thermo ( thermolib * t ) { (*thermo) = *t; } - - - void set(double, double); // Sets P and T - void set(double*); // Sets mass flows - void set( const string & n ) { name = n;} - void set ( int _nb , chemical ** _chem); - - - // destructor : - ~stream ( void ); - - void write(); - void purge(); -}; - - -#endif +#ifndef STREAM_H +#define STREAM_H +#include "chemical.hpp" +#include <iomanip> +using namespace std; + +class stream { + +private: + + stream ( void ) {} + stream ( const stream & s ) {} + +public: + void check_error(); + + double P, T, m, v; // Pressure in atm, temperature in K, + // total mass flow in kg/s, total volume flow in m3/s + + int i, j, k, error, warning; + + string name; + + int nb; // number of chemicals to store; + + chemical ** chem; // list of stored chemicals + + thermolib *thermo; + + double tmp, tmp1,tmp2, *tab1, *tab2, *tab3, *tab4; + double step; + void bubble(), dew(); + +public: + + + + + + double dp, bp; + double rho() {if(v!=0) return m/v; else exit(0);} // Apparent density in kg/m3 + double n(); // total mole flow (mol/s) + double quality(); // returns the vapor fraction of stream (1=all vapor, 0 = all liquid) + double K(int); // returns the vapor-liquid equilibrium constant of compound i + + // constructor : + stream ( const string _name , int n , chemical ** list ) : P (0 ) , + T (0 ) , + m (0 ) , + v (0 ) , + error (0 ) , + warning(0 ) , + name (_name ) , + nb (n ) , + chem (new chemical *[nb]) , + thermo (new thermolib (nb)) , + tab1 (new double [nb]) , + tab2 (new double [nb]) , + tab3 (new double [nb]) , + tab4 (new double [nb]) { + for ( i = 0 ; i < nb ; i++ ) + chem[i] = new chemical(*list[i]); + } + + + // affectation : + stream & operator = ( const stream & s ); + + void set_thermo ( thermolib * t ) { (*thermo) = *t; } + + + void set(double, double); // Sets P and T + void set(double*); // Sets mass flows + void set( const string & n ) { name = n;} + void set ( int _nb , chemical ** _chem); + + + // destructor : + ~stream ( void ); + + void write(); + void purge(); +}; + + +#endif diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/thermolib.cpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/thermolib.cpp index 13a3b35..f6bf0a1 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/thermolib.cpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/thermolib.cpp @@ -1,174 +1,174 @@ -#include "thermolib.hpp" -#include "defines.hpp" -#include "secant.cpp" -using namespace std; - - - - -// affectation : -thermolib & thermolib::operator = ( const thermolib & t ) { - - if (dim!=t.dim) - reset(t.dim); - - for ( i = 0 ; i < dim ; i++ ) { - Pc[i] = t.Pc[i]; - Tc[i] = t.Tc[i]; - omega[i] = t.omega[i]; - molefrac[i] = t.molefrac[i]; - } - - return *this; -} - -thermolib::~thermolib() { - delete solver; - delete [] Pc; - delete [] Tc; - delete [] omega; - delete [] molefrac; -} - -void thermolib::construct ( void ) { - molefrac = new double[dim]; - Pc = new double[dim]; - Tc = new double[dim]; - omega = new double[dim]; - - // C. Tribes add this for more robustness (variables may be initialized uncorrectly dependent on the execution) - for ( i = 0 ; i < dim ; i++ ) - { - Pc[i] = 0.0; - Tc[i] = 0.0; - omega[i] = 0.0; - molefrac[i] = 0.0; - } - - solver = new secant<thermolib>(); -} - -void thermolib::reset(int b) -{ - delete [] molefrac; - delete [] Pc; - delete [] Tc; - delete [] omega; - delete solver; - dim = b; - construct(); -} - -double thermolib::a_mix() -{ - if (dim>1) - { - tmp=0; - for (i=0;i<dim;i++) - for (j=0;j<dim;j++) - tmp += molefrac[i]*molefrac[j]*sqrt(a(i)*a(j)); - return tmp; - } - else return a(0); -} - -double thermolib::b_mix() -{ - if (dim>1) - { - tmp=0; - for (i=0;i<dim;i++) - tmp += molefrac[i]*b(i); - return tmp; - } - else return b(0); -} - -void thermolib::send(double* pc, double* tc, double* w, double* y) -{ - for (i=0;i<dim;i++) - { - Pc[i] = pc[i]*101.325; - Tc[i] = tc[i]; - omega[i] = w[i]; - molefrac[i] = y[i]; - } -} - -double thermolib::P() -{ - task=0; - pressure = 8.3144*temperature/molevolume; - solver->set(this, pressure, 1.001*pressure); - success=solver->run(); - return pressure/101.325; -} - -double thermolib::T() -{ - task=1; - temperature = pressure*molevolume/8.144; - solver->set(this, temperature, 1.001*temperature); - success=solver->run(); - return temperature; -} - -double thermolib::v() -{ - if (mole>EPS) - { - task=2; - molevolume = 8.3144*temperature/pressure; - solver->set(this, molevolume, 1.001*molevolume); - success=solver->run(); - return 0.001*mole*molevolume; - } - else return 0.0; -} - -double thermolib::Zv() -{ - task=4; - solver->set(this, 1.0, 0.99); - success=solver->run(); - return Z; -} - -double thermolib::phiV(int i) -{ - return exp((Z-1)*B(i)/B() - log(Z-B()) - A()/B()*(2*sqrt(A(i)/A())-B(i)/B())*log(1+B()/Z)); -} - -double thermolib::phiL(int i) -{ - Pr = pressure/Pc[i]; - Tr = temperature/Tc[i]; - tmp = 2.05135 - 2.10899/Tr - 0.19396*pow(Tr,2) + 0.02282*pow(Tr,3) + (0.08852 - 0.00872*pow(Tr,2))*Pr + (-0.00353 - 0.00203*Tr)*pow(Pr,2) - log10(Pr); - tmp += omega[i]*(-4.23893 + 8.65808*Tr - 1.2206/Tr - 3.15224*pow(Tr,3) - 0.025*(Pr-0.6)); - return pow(10, tmp); -} - -double thermolib::f(double x) -{ - if (task==0) - { - pressure=x; - x= 8.3144*temperature/(molevolume-b_mix()) - a_mix()/(pow(molevolume,2)+b_mix()*molevolume) - x; - } - if (task==1) - { - temperature=x; - x= 8.3144*x/(molevolume-b_mix()) - a_mix()/(pow(molevolume,2)+b_mix()*molevolume) - pressure; - } - if (task==2) - { - molevolume=x; - x= 8.3144*temperature/(x-b_mix()) - a_mix()/(pow(x,2)+b_mix()*x) - pressure; - } - if(task==4) - { - Z=x; - x= (pow(x,3)-pow(x,2)+(A()-B()-pow(B(),2))*x-A()*B()); - } - return x; -} +#include "thermolib.hpp" +#include "defines.hpp" +#include "secant.cpp" +using namespace std; + + + + +// affectation : +thermolib & thermolib::operator = ( const thermolib & t ) { + + if (dim!=t.dim) + reset(t.dim); + + for ( i = 0 ; i < dim ; i++ ) { + Pc[i] = t.Pc[i]; + Tc[i] = t.Tc[i]; + omega[i] = t.omega[i]; + molefrac[i] = t.molefrac[i]; + } + + return *this; +} + +thermolib::~thermolib() { + delete solver; + delete [] Pc; + delete [] Tc; + delete [] omega; + delete [] molefrac; +} + +void thermolib::construct ( void ) { + molefrac = new double[dim]; + Pc = new double[dim]; + Tc = new double[dim]; + omega = new double[dim]; + + // C. Tribes add this for more robustness (variables may be initialized uncorrectly dependent on the execution) + for ( i = 0 ; i < dim ; i++ ) + { + Pc[i] = 0.0; + Tc[i] = 0.0; + omega[i] = 0.0; + molefrac[i] = 0.0; + } + + solver = new secant<thermolib>(); +} + +void thermolib::reset(int b) +{ + delete [] molefrac; + delete [] Pc; + delete [] Tc; + delete [] omega; + delete solver; + dim = b; + construct(); +} + +double thermolib::a_mix() +{ + if (dim>1) + { + tmp=0; + for (i=0;i<dim;i++) + for (j=0;j<dim;j++) + tmp += molefrac[i]*molefrac[j]*sqrt(a(i)*a(j)); + return tmp; + } + else return a(0); +} + +double thermolib::b_mix() +{ + if (dim>1) + { + tmp=0; + for (i=0;i<dim;i++) + tmp += molefrac[i]*b(i); + return tmp; + } + else return b(0); +} + +void thermolib::send(double* pc, double* tc, double* w, double* y) +{ + for (i=0;i<dim;i++) + { + Pc[i] = pc[i]*101.325; + Tc[i] = tc[i]; + omega[i] = w[i]; + molefrac[i] = y[i]; + } +} + +double thermolib::P() +{ + task=0; + pressure = 8.3144*temperature/molevolume; + solver->set(this, pressure, 1.001*pressure); + success=solver->run(); + return pressure/101.325; +} + +double thermolib::T() +{ + task=1; + temperature = pressure*molevolume/8.144; + solver->set(this, temperature, 1.001*temperature); + success=solver->run(); + return temperature; +} + +double thermolib::v() +{ + if (mole>EPS) + { + task=2; + molevolume = 8.3144*temperature/pressure; + solver->set(this, molevolume, 1.001*molevolume); + success=solver->run(); + return 0.001*mole*molevolume; + } + else return 0.0; +} + +double thermolib::Zv() +{ + task=4; + solver->set(this, 1.0, 0.99); + success=solver->run(); + return Z; +} + +double thermolib::phiV(int i) +{ + return exp((Z-1)*B(i)/B() - log(Z-B()) - A()/B()*(2*sqrt(A(i)/A())-B(i)/B())*log(1+B()/Z)); +} + +double thermolib::phiL(int i) +{ + Pr = pressure/Pc[i]; + Tr = temperature/Tc[i]; + tmp = 2.05135 - 2.10899/Tr - 0.19396*pow(Tr,2) + 0.02282*pow(Tr,3) + (0.08852 - 0.00872*pow(Tr,2))*Pr + (-0.00353 - 0.00203*Tr)*pow(Pr,2) - log10(Pr); + tmp += omega[i]*(-4.23893 + 8.65808*Tr - 1.2206/Tr - 3.15224*pow(Tr,3) - 0.025*(Pr-0.6)); + return pow(10, tmp); +} + +double thermolib::f(double x) +{ + if (task==0) + { + pressure=x; + x= 8.3144*temperature/(molevolume-b_mix()) - a_mix()/(pow(molevolume,2)+b_mix()*molevolume) - x; + } + if (task==1) + { + temperature=x; + x= 8.3144*x/(molevolume-b_mix()) - a_mix()/(pow(molevolume,2)+b_mix()*molevolume) - pressure; + } + if (task==2) + { + molevolume=x; + x= 8.3144*temperature/(x-b_mix()) - a_mix()/(pow(x,2)+b_mix()*x) - pressure; + } + if(task==4) + { + Z=x; + x= (pow(x,3)-pow(x,2)+(A()-B()-pow(B(),2))*x-A()*B()); + } + return x; +} diff --git a/tools/SENSITIVITY/problems/styrene/black-box/truth/thermolib.hpp b/tools/SENSITIVITY/problems/styrene/black-box/truth/thermolib.hpp index 3440270..3d39c8c 100644 --- a/tools/SENSITIVITY/problems/styrene/black-box/truth/thermolib.hpp +++ b/tools/SENSITIVITY/problems/styrene/black-box/truth/thermolib.hpp @@ -1,50 +1,50 @@ -#ifndef THERMOLIB_H -#define THERMOLIB_H -#include "secant.hpp" -using namespace std; - -class thermolib -{ - private: - bool success; - int dim, i, j; - double pressure, temperature, molevolume, mole,*molefrac; - double *Pc, *Tc, *omega, Z, tmp, Tr, Pr; - void construct(); - double a(int i) {return (0.42748*pow(8.8144,2)*pow(Tc[i],2)*pow(1.0+f_omega(i)*(1.0-sqrt(temperature/Tc[i])), 2)/Pc[i]);} - double a_mix(); - double b(int i) {return (0.08664*8.3144*Tc[i]/Pc[i]);} - double b_mix(); - double A(int i) {return (a(i)*pressure/pow(8.3144, 2)/pow(temperature, 2));} - double A() {return (a_mix()*pressure/pow(8.3144, 2)/pow(temperature, 2));} - double B(int i) {return (b(i)*pressure/8.3144/temperature);} - double B(){return (b_mix()*pressure/8.3144/temperature);} - double Zv(), phiV(int), phiL(int); - double f_omega(int i) {return (0.48 + 1.574*omega[i] - 0.176*pow(omega[i], 2));} - int task; //0=find P 1=find T 2=find v 3= find K 4=find Zv - secant<thermolib> *solver; - - public: - double P(); //retruns pressure at T and v, in atm - double T(); //returns temperature at P and v, in K - double v(); //returns volume flow at P, T, n(), in m3/s - double K() {Z = Zv(); return phiL(0)/phiV(0);} //returns the vapor-liquid equilibirum constant - double K(int i) {return phiL(i)/phiV(i);} - double compres_coeff(){return 1.0;}; - - -// affectation : - thermolib & operator = ( const thermolib & t ); - - thermolib ( int d = 1 ) { dim=d; construct();} - - void send(double pc, double tc, double w) { Pc[0] = pc*101.325; Tc[0] = tc; omega[0]=w;} - void send(double*, double*, double*, double*); - void set(double p, double t, double v, double n) {pressure=p*101.325; temperature=t; molevolume=0.001*n/v; mole=n;} - double f(double); - int get_dim() {return dim;} - ~thermolib(); - void reset(int); -}; -#endif - +#ifndef THERMOLIB_H +#define THERMOLIB_H +#include "secant.hpp" +using namespace std; + +class thermolib +{ + private: + bool success; + int dim, i, j; + double pressure, temperature, molevolume, mole,*molefrac; + double *Pc, *Tc, *omega, Z, tmp, Tr, Pr; + void construct(); + double a(int i) {return (0.42748*pow(8.8144,2)*pow(Tc[i],2)*pow(1.0+f_omega(i)*(1.0-sqrt(temperature/Tc[i])), 2)/Pc[i]);} + double a_mix(); + double b(int i) {return (0.08664*8.3144*Tc[i]/Pc[i]);} + double b_mix(); + double A(int i) {return (a(i)*pressure/pow(8.3144, 2)/pow(temperature, 2));} + double A() {return (a_mix()*pressure/pow(8.3144, 2)/pow(temperature, 2));} + double B(int i) {return (b(i)*pressure/8.3144/temperature);} + double B(){return (b_mix()*pressure/8.3144/temperature);} + double Zv(), phiV(int), phiL(int); + double f_omega(int i) {return (0.48 + 1.574*omega[i] - 0.176*pow(omega[i], 2));} + int task; //0=find P 1=find T 2=find v 3= find K 4=find Zv + secant<thermolib> *solver; + + public: + double P(); //retruns pressure at T and v, in atm + double T(); //returns temperature at P and v, in K + double v(); //returns volume flow at P, T, n(), in m3/s + double K() {Z = Zv(); return phiL(0)/phiV(0);} //returns the vapor-liquid equilibirum constant + double K(int i) {return phiL(i)/phiV(i);} + double compres_coeff(){return 1.0;}; + + +// affectation : + thermolib & operator = ( const thermolib & t ); + + thermolib ( int d = 1 ) { dim=d; construct();} + + void send(double pc, double tc, double w) { Pc[0] = pc*101.325; Tc[0] = tc; omega[0]=w;} + void send(double*, double*, double*, double*); + void set(double p, double t, double v, double n) {pressure=p*101.325; temperature=t; molevolume=0.001*n/v; mole=n;} + double f(double); + int get_dim() {return dim;} + ~thermolib(); + void reset(int); +}; +#endif + diff --git a/utils/MergeCacheFiles/Readme.txt b/utils/MergeCacheFiles/Readme.txt new file mode 100644 index 0000000..20d4ad5 --- /dev/null +++ b/utils/MergeCacheFiles/Readme.txt @@ -0,0 +1,21 @@ +Cache files from different runs of the same problem can be merged and reused in a later optimization. + +Please note that binary cache files must be from the same OS. Please note that the provided cacheX.bin files have been created under OSX. + +1- Using the OS (linux and OSX) command line + +- The following sources codes allow to merge two binary files (cache1.bin and cache2.bin) into a new cache file called cache3.bin. + +- On the command line execute the make command + +- Execute ./merge.exe + +2- Using Matlab environment + +- If not already done, setup the mex Matlab External Interface with the command mex -setup at the command prompt. Please refer to Matlab documentation for details. + +- Change the Current Folder to %NOMAD_HOME%/utils/MergeCacheFiles + +- Run the command build.m + +- Run the command mergeM(‘cache1.bin’,’cache2.bin’,’cache3.bin’) diff --git a/utils/MergeCacheFiles/build.m b/utils/MergeCacheFiles/build.m new file mode 100644 index 0000000..5017f5c --- /dev/null +++ b/utils/MergeCacheFiles/build.m @@ -0,0 +1,72 @@ +%% GERAD NOMAD Build for Matlab + +% This file will help you compile NOMAD for use with MATLAB. + +% To recompile you will need to get / do the following: + +% 1) Get NOMAD +% NOMAD is available from http://www.gerad.ca/NOMAD/PHP_Forms/Download.php. +% Complete the download form then download the latest version. Define the +% $NOMAD_HOME environment variable. + +% 2) NOMAD MEX Interface +% The NOMAD MEX Interface is a simple MEX interface written to use NOMAD. + +% 3) Compile the MEX File +% The code below will build the NOMAD MEX file. Once you have completed all the +% above steps, simply run this file to compile NOMAD! You MUST BE in the +% base directory of OPTI! + +clear nomad + +switch(computer) +case 'PCWIN' +libdir = ' -Lwin32\'; +case 'PCWIN64' +libdir = ' -Lwin64\'; +case 'GLNX86' +libdir = 'glnx86/'; +case 'GLNXA64' +libdir = 'glnxa64/'; +case 'MACI64' +libdir = 'maci64/'; +end + +clear nomad_home nomad_src; + + +fprintf('\n------------------------------------------------\n'); +fprintf('NOMAD CACHE MERGE BUILD \n\n'); + +nomad_home = getenv('NOMAD_HOME'); +if (length(nomad_home)<1) + error('opti:nomad','Please set NOMAD_HOME variables properly with the command setenv(''NOMAD_HOME'',ARG1)!'); +end +nomad_src=[nomad_home filesep 'src' filesep]; + + +%Get NOMAD Libraries +post = [' -I. -I' nomad_src ' -lm -lut -output mergeM']; + +%Compile & Move +pre = ['mex -v -largeArrayDims mergeM.cpp ' nomad_src 'Parameters.cpp ' nomad_src 'Barrier.cpp ' nomad_src 'Cache.cpp '... +nomad_src 'Cache_File_Point.cpp ' nomad_src 'Cache_Point.cpp ' nomad_src 'Cache_Search.cpp ' nomad_src 'Clock.cpp '... +nomad_src 'Direction.cpp ' nomad_src 'Directions.cpp ' nomad_src 'Display.cpp '... +nomad_src 'Double.cpp ' nomad_src 'Eval_Point.cpp ' nomad_src 'Evaluator.cpp ' nomad_src 'Evaluator_Control.cpp ' nomad_src 'Exception.cpp '... +nomad_src 'Extended_Poll.cpp ' nomad_src 'L_Curve.cpp ' nomad_src 'LH_Search.cpp ' nomad_src 'OrthogonalMesh.cpp ' nomad_src 'Mads.cpp ' nomad_src 'Model_Sorted_Point.cpp '... +nomad_src 'Model_Stats.cpp ' nomad_src 'Multi_Obj_Evaluator.cpp ' nomad_src 'Parameter_Entries.cpp '... +nomad_src 'Parameter_Entry.cpp ' nomad_src 'Pareto_Front.cpp ' nomad_src 'Pareto_Point.cpp ' nomad_src 'Phase_One_Evaluator.cpp '... +nomad_src 'Phase_One_Search.cpp ' nomad_src 'Point.cpp ' nomad_src 'Priority_Eval_Point.cpp ' nomad_src 'Quad_Model.cpp '... +nomad_src 'Quad_Model_Evaluator.cpp ' nomad_src 'Quad_Model_Search.cpp ' nomad_src 'Random_Pickup.cpp ' nomad_src 'RNG.cpp '... +nomad_src 'Signature.cpp ' nomad_src 'Slave.cpp ' nomad_src 'SMesh.cpp ' nomad_src 'Speculative_Search.cpp ' nomad_src 'Stats.cpp ' nomad_src 'utils.cpp '... +nomad_src 'Variable_Group.cpp ' nomad_src 'VNS_Search.cpp ' nomad_src 'XMesh.cpp']; + +try + eval([pre post]) + clear nomad_home nomad_src cdir post pre libdir; + fprintf('Done!\n'); +catch ME + clear nomad_home nomad_src cdir post pre libdir; + error('opti:nomad','Error Compiling NOMAD!\n%s',ME.message); +end +fprintf('------------------------------------------------\n'); diff --git a/utils/MergeCacheFiles/cache1.bin b/utils/MergeCacheFiles/cache1.bin new file mode 100644 index 0000000000000000000000000000000000000000..d3c04eef56120311a637e5e4c6c4560975b47e03 GIT binary patch literal 8904 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 literal 0 HcmV?d00001 diff --git a/utils/MergeCacheFiles/cache2.bin b/utils/MergeCacheFiles/cache2.bin new file mode 100644 index 0000000000000000000000000000000000000000..c87363aa13552d0ff62f19332c1a5212459207a7 GIT binary patch literal 8815 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 literal 0 HcmV?d00001 diff --git a/utils/MergeCacheFiles/cache3.bin b/utils/MergeCacheFiles/cache3.bin new file mode 100644 index 0000000000000000000000000000000000000000..d2bc763560c37723713a363869fd2c1189d04184 GIT binary patch literal 17715 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 D8LrLM literal 0 HcmV?d00001 diff --git a/utils/MergeCacheFiles/makefile b/utils/MergeCacheFiles/makefile new file mode 100644 index 0000000..965ba81 --- /dev/null +++ b/utils/MergeCacheFiles/makefile @@ -0,0 +1,50 @@ +EXE = merge.exe + +COMPILATOR = g++ + +COMPILATOR_OPTIONS = -O2 -ansi +L1 = $(NOMAD_HOME)/lib/nomad.a +LIBS = $(L1) -lm +INCLUDE = -I$(NOMAD_HOME)/src -I. +COMPILE = $(COMPILATOR) $(COMPILATOR_OPTIONS) $(INCLUDE) -c +OBJS = merge.o + + +ifndef NOMAD_HOME +define ECHO_NOMAD + @echo Please set NOMAD_HOME environment variable! + @false +endef +endif + + +$(EXE): $(L1) $(OBJS) + $(ECHO_NOMAD) + @echo " building the scalar version ..." + @echo " exe file : "$(EXE) + @$(COMPILATOR) -o $(EXE) $(OBJS) $(LIBS) $(COMPILATOR_OPTIONS) + @strip $(EXE) + + +merge.o: merge.cpp + $(ECHO_NOMAD) + @$(COMPILE) merge.cpp + +$(L1) $(L1_MPI): ; + $(ECHO_NOMAD) + +all: $(EXE) $(EXE_MPI) + +clean: ; + @echo " cleaning obj files" + @rm -f $(OBJS) $(OBJS_MPI) + +del: ; + @echo " cleaning trash files" + @rm -f core *~ + @echo " cleaning obj files" + @rm -f $(OBJS) $(OBJS_MPI) + @echo " cleaning exe file" + @rm -f $(EXE) $(EXE_MPI) + + diff --git a/utils/MergeCacheFiles/merge.cpp b/utils/MergeCacheFiles/merge.cpp new file mode 100644 index 0000000..e4264ef --- /dev/null +++ b/utils/MergeCacheFiles/merge.cpp @@ -0,0 +1,56 @@ +/*-----------------------------------------------------*/ +/* how to use the NOMAD library with a user function */ +/*-----------------------------------------------------*/ +#include "nomad.hpp" +using namespace std; +// using namespace NOMAD; avoids putting NOMAD:: everywhere + + +/*------------------------------------------*/ +/* NOMAD main function */ +/*------------------------------------------*/ +int main ( int argc , char ** argv ) +{ + + // display: + NOMAD::Display out ( std::cout ); + out.precision ( NOMAD::DISPLAY_PRECISION_STD ); + + try + { + + // NOMAD initializations: + NOMAD::begin ( argc , argv ); + + // parameters creation: + NOMAD::Cache cache1 ( out ); + NOMAD::Cache cache2 ( out ); + NOMAD::Cache cache3 ( out ); + + cache1.load("cache1.bin"); + out << "Before merging \n cache1.bin contains " << cache1.size() << " points" << endl; + + cache2.load("cache2.bin"); + out << " cache2.bin contains " << cache2.size() << " points" << endl; + + cache3.load("cache3.bin"); + out << " cache3.bin contains " << cache3.size() << " points" << endl; + + + + cache3.insert(cache1); + cache3.insert(cache2); + + cache3.save(true); + + out << "After merging \n cache3.bin contains " << cache3.size() << " points" << endl; + + + } + catch ( exception & e ) + { + cerr << "\n Merge triggered an exception (" << e.what() << ")\n\n"; + } + + return EXIT_SUCCESS; +} diff --git a/utils/MergeCacheFiles/mergeM.cpp b/utils/MergeCacheFiles/mergeM.cpp new file mode 100644 index 0000000..fde710c --- /dev/null +++ b/utils/MergeCacheFiles/mergeM.cpp @@ -0,0 +1,90 @@ +/*-----------------------------------------------------*/ +/* Merge cache files from NOMAD */ +/*-----------------------------------------------------*/ +#include "mex.h" +#include "nomad.hpp" + +using namespace std; +// using namespace NOMAD; avoids putting NOMAD:: everywhere + + +struct printfbuf : std::streambuf { +public: + //Constructor + printfbuf() + { + setp(m_buffer, m_buffer + s_size - 2); + } +private: + enum { s_size = 1024 }; //not sure on this size + char m_buffer[s_size]; + int_type overflow(int_type c) + { + if (!traits_type::eq_int_type(c, traits_type::eof())) { + *pptr() = traits_type::to_char_type(c); + pbump(1); + } + return sync() != -1 ? traits_type::not_eof(c) : traits_type::eof(); + } + + int sync() { + *pptr() = 0; + mexPrintf(pbase()); + mexEvalString("drawnow;"); + setp(m_buffer, m_buffer + s_size - 2); + return 0; + } + }; + +// Main Entry Function +// ----------------------------------------------------------------- +void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + // display: + + + try + { + + if(nrhs != 3 || !mxIsChar(prhs[0]) || !mxIsChar(prhs[1]) || !mxIsChar(prhs[2]) ) + mexErrMsgTxt("You must supply the name of 3 cache files for merging. 2 for input and 1 for output \n"); + + + char *cache_file_name_1 = NULL; + char *cache_file_name_2 = NULL; + char *cache_file_name_3 = NULL; + cache_file_name_1 = mxArrayToString(prhs[0]); + cache_file_name_2 = mxArrayToString(prhs[1]); + cache_file_name_3 = mxArrayToString(prhs[2]); + + printfbuf buf; + std::streambuf *cout_sbuf = std::cout.rdbuf(); //keep existing buffer + std::cout.rdbuf(&buf); //redirect buffer + + NOMAD::Display out ( std::cout ); + out.precision ( NOMAD::DISPLAY_PRECISION_STD ); + + // parameters creation: + NOMAD::Cache cache1 ( out ); + NOMAD::Cache cache2 ( out ); + NOMAD::Cache cache3 ( out ); + + cache1.load(cache_file_name_1); + cache2.load(cache_file_name_2); + cache3.load(cache_file_name_3); + + + cache3.insert(cache1); + cache3.insert(cache2); + cache3.save(true); + + out << "After merging \n " << cache_file_name_3 << " contains " << cache3.size() << " points" << endl; + + + } + catch ( exception & e ) + { + cerr << "\n Merge triggered an exception (" << e.what() << ")\n\n"; + } + +} diff --git a/utils/Run_TestSuite/readme.txt b/utils/Run_TestSuite/readme.txt new file mode 100644 index 0000000..b99438f --- /dev/null +++ b/utils/Run_TestSuite/readme.txt @@ -0,0 +1,3 @@ +1- Set the NOMAD_HOME environment variable +2- Execute the perl script (perl ./runNomadAll_parallel.pl 4) +3- Check the execution logs if necessary \ No newline at end of file diff --git a/utils/Run_TestSuite/runNomadAll_parallel.pl b/utils/Run_TestSuite/runNomadAll_parallel.pl new file mode 100755 index 0000000..f7be08f --- /dev/null +++ b/utils/Run_TestSuite/runNomadAll_parallel.pl @@ -0,0 +1,309 @@ +#!/usr/bin/perl +# use strict; +use warnings; + +use Data::Dumper; + +use threads; +use threads::shared; +use Thread::Semaphore; + + +if (! exists $ENV{NOMAD_HOME}) { + print "Please provide an environment variable NOMAD_HOME. \n"; + exit 1; +} + +print "NOMAD_HOME = $ENV{NOMAD_HOME} \n"; + +#if (! exists $ENV{LIBAMPLDIR}) { +# print "!!!!!!!!!!!!!!!! The LIBAMPLDIR environment variable is not set -> ampl example may not work! \n"; +#} + +#if (! exists $ENV{CUTER} | ! exists $ENV{MYCUTER} | ! exists $ENV{SIFDEC} | ! exists $ENV{MYSIFDEC} ) { +# print "!!!!!!!!!!!!!!!! The environment variables for CUTEr are not set -> CUTEr example may not work! \n"; +#} + + +my $MPIcommand:shared; +open(aComRes,"uname |") or die "Can't run command: $!\n"; +if ( grep(/MINGW/,<aComRes>) ){ + $MPIcommand="mpiexec -localonly"; # version mingw +} else +{ + $MPIcommand="mpirun -n"; # version OSX and linux +} + +my $keySearch=" Error | error | error: | Exception | NOMAD::Exception | Failed | Arrêt | Stop"; + +my $nombre_de_jobs_en_parallele:shared; +if ( ! exists $ARGV[0]) { +$nombre_de_jobs_en_parallele = 1; # 1 but still 3 processes minimun required for mpi +} else { +$nombre_de_jobs_en_parallele = $ARGV[0]; +} + + +my $nomadEXE="nomad"; +my $nomadMPI_EXE="nomad.MPI"; + +my $maxLinesForLogProblem:shared; +$maxLinesForLogProblem = 20; + +my @list = ( + ["cd $ENV{NOMAD_HOME}/examples/basic/batch/single_obj ; if [ ! -e bb.exe ] ; then g++ -o bb.exe bb.cpp 2>&1 ; fi ; $ENV{NOMAD_HOME}/bin/$nomadEXE param.txt 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/basic/batch/single_obj_parallel ; if [ ! -e bb.exe ] ; then g++ -o bb.exe bb.cpp 2>&1 ; fi ; $ENV{NOMAD_HOME}/bin/$nomadEXE param.txt 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/basic/batch/bi_obj ; if [ ! -e bb.exe ] ; then g++ -o bb.exe bb.cpp 2>&1 ; fi ; $ENV{NOMAD_HOME}/bin/$nomadEXE param.txt 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/basic/batch/single_obj ; if [ ! -e bb.exe ] ; then g++ -o bb.exe bb.cpp 2>&1 ; fi ; $MPIcommand 3 $ENV{NOMAD_HOME}/bin/$nomadMPI_EXE param.txt 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/basic/batch/bi_obj ; if [ ! -e bb.exe ] ; then g++ -o bb.exe bb.cpp 2>&1 ; fi ; $MPIcommand 3 $ENV{NOMAD_HOME}/bin/$nomadMPI_EXE param.txt 2>&1"] , + ["cd $ENV{NOMAD_HOME}/examples/basic/library/single_obj ; if [ -e basic_lib.exe ] ; then rm -f basic_lib.exe ; fi ; make clean 2>&1 ; make 2>&1; ./basic_lib.exe 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/basic/library/bi_obj ; if [ -e basic_lib.exe ] ; then rm -f basic_lib.exe ; fi ; make clean 2>&1 ; make 2>&1 ; ./basic_lib.exe 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/basic/library/single_obj ; if [ -e basic_lib_MPI.exe ] ; then rm -f basic_lib_MPI.exe ; fi ; make clean 2>&1 ; make mpi 2>&1; $MPIcommand 3 ./basic_lib_MPI.exe 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/basic/library/bi_obj ; if [ -e basic_lib_MPI.exe ] ; then rm -f basic_lib_MPI.exe ; fi ; make clean 2>&1 ; make mpi 2>&1; $MPIcommand 3 ./basic_lib_MPI.exe 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/basic/library/single_obj_parallel ; if [ -e basic_lib.exe ] ; then rm -f basic_lib.exe ; fi ; make clean 2>&1 ; make 2>&1; ./basic_lib.exe 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/advanced/categorical/batch ; if [ ! -e bb.exe -o ! -e neighbors.exe ] ; then g++ -o bb.exe bb.cpp 2>&1 ; g++ -o neighbors.exe neighbors.cpp ; fi ; echo ; $ENV{NOMAD_HOME}/bin/$nomadEXE param.txt 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/advanced/categorical/batch ; if [ ! -e bb.exe -o ! -e neighbors.exe ] ; then g++ -o bb.exe bb.cpp 2>&1 ; g++ -o neighbors.exe neighbors.cpp ; fi ; echo ; $MPIcommand 3 $ENV{NOMAD_HOME}/bin/$nomadMPI_EXE param.txt 2>&1"], + ["cd $ENV{NOMAD_HOME}/examples/advanced/categorical/single_obj ; if [ -e categorical.exe ] ; then rm -f categorical.exe ; echo ; fi ; make clean 2>&1 ; make 2>&1; ./categorical.exe 2>&1 "], + ["cd $ENV{NOMAD_HOME}/examples/advanced/categorical/single_obj ; if [ -e categorical_MPI.exe ] ; then rm -f categorical_MPI.exe ; echo ; fi ; make clean 2>&1 ; make mpi 2>&1; $MPIcommand 3 ./categorical_MPI.exe 2>&1 "], + ["cd $ENV{NOMAD_HOME}/examples/advanced/categorical/bi_obj ; if [ -e categorical.exe ] ; then rm -f categorical.exe ; echo ; fi ; make clean 2>&1 ; make 2>&1; ./categorical.exe 2>&1 "], + ["cd $ENV{NOMAD_HOME}/examples/advanced/categorical/bi_obj ; if [ -e categorical_MPI.exe ] ; then rm -f categorical_MPI.exe ; echo ; fi ; make clean 2>&1 ; make mpi 2>&1; $MPIcommand 3 ./categorical_MPI.exe 2>&1 "], + ["cd $ENV{NOMAD_HOME}/examples/advanced/restart ; if [ -e restart.exe ] ; then rm -f restart.exe ; echo ; fi ; make clean 2>&1 ; make 2>&1; ./restart.exe 2>&1 "], + ["cd $ENV{NOMAD_HOME}/examples/advanced/restart ; if [ -e restart_MPI.exe ] ; then rm -f restart_MPI.exe ; echo ; fi ; make clean 2>&1 ; make mpi 2>&1; $MPIcommand 3 ./restart_MPI.exe 2>&1 "], + ["cd $ENV{NOMAD_HOME}/examples/advanced/multi_start ; if [ -e multi.exe ] ; then rm -f multi.exe ; echo ; fi ; make clean 2>&1 ; make 2>&1; ./multi.exe param.txt 4 5 2>&1 "], + ["cd $ENV{NOMAD_HOME}/examples/advanced/user_search ; if [ -e user_search.exe ] ; then rm -f user_search.exe ; echo ; fi ; make clean 2>&1 ; make 2>&1; ./user_search.exe 2>&1 "], + ["cd $ENV{NOMAD_HOME}/examples/advanced/user_search ; if [ -e user_search_MPI.exe ] ; then rm -f user_search_MPI.exe ; echo ; fi ; make clean 2>&1 ; make mpi 2>&1; $MPIcommand 3 ./user_search_MPI.exe 2>&1 "], +# ["cd $ENV{NOMAD_HOME}/examples/interfaces/AMPL ; if [ ! -e bb.exe ] ; then make 2>&1 ; echo ; fi ; $ENV{NOMAD_HOME}/bin/$nomadEXE param.txt 2>&1 "], +# ["cd $ENV{NOMAD_HOME}/examples/interfaces/AMPL ; if [ ! -e bb.exe ] ; then make 2>&1 ; echo ; fi ; $MPIcommand 3 $ENV{NOMAD_HOME}/bin/$nomadMPI_EXE param.txt 2>&1 "], +# ["cd $ENV{NOMAD_HOME}/examples/interfaces/CUTEr ; if [ ! -e bb ] ; then $ENV{MYSIFDEC}/bin/sifdecode PROBLEM.SIF ; ./compile 2>&1 ; fi ; $ENV{NOMAD_HOME}/bin/$nomadEXE parameters.txt 2>&1 "], +# ["cd $ENV{NOMAD_HOME}/examples/interfaces/CUTEr ; sleep 10 ; if [ ! -e bb ] ; then ./compile 2>&1 ; fi ; $MPIcommand 3 $ENV{NOMAD_HOME}/bin/$nomadMPI_EXE parameters.txt 2>&1 "], +# ["cd $ENV{NOMAD_HOME}/examples/interfaces/DLL/single_obj ; if [ -e nomad_for_dll ] ; then rm -f nomad_for_dll ; fi ; echo ; make 2>&1; ./nomad_for_dll parameters.txt 2>&1"], +# ["cd $ENV{NOMAD_HOME}/examples/interfaces/DLL/bi_obj ; if [ -e nomad_for_dll ] ; then rm -f nomad_for_dll ; fi ; echo ; make clean 2>&1 ; make 2>&1; ./nomad_for_dll parameters.txt 2>&1"], +# ["cd $ENV{NOMAD_HOME}/examples/interfaces/FORTRAN/example1 ; if [ -e test ] ; then rm -f test ; fi ; make clean 2>&1 ; make 2>&1; ./test 2>&1"], +# ["cd $ENV{NOMAD_HOME}/examples/interfaces/FORTRAN/example2 ; if [ -e test ] ; then rm -f test ; fi ; make clean 2>&1 ; make 2>&1; ./test 2>&1"], + ["cd $ENV{NOMAD_HOME}/tools/COOP-MADS ; if [ -e coopmads.exe ] ; then rm -f *.exe *.o ; fi ; make 2>&1 ; cd problems/G2_10 ; g++ -o bb.exe bb.cpp 2>&1; $MPIcommand 3 ../../coopmads.exe param.txt 2>&1"], + ["cd $ENV{NOMAD_HOME}/tools/COOP-MADS ; sleep 10 ; if [ ! -e coopmads.exe ] ; then make 2>&1 ; fi ; cd problems/RHEOLOGY ; g++ -o bb.exe bb.cpp 2>&1; $MPIcommand 3 ../../coopmads.exe param.txt 2>&1"], + ["cd $ENV{NOMAD_HOME}/tools/PSD-MADS ; if [ -e psdmads.exe ] ; then rm -f *.exe *.o ; fi ; make 2>&1 ; cd problems/G2_20 ; g++ -o bb.exe bb.cpp 2>&1; $MPIcommand 6 ../../psdmads.exe param.txt 50 5 2>&1"] + ); + +my @NOMADcompilations = ( + ["cd $ENV{NOMAD_HOME}/src ; make clean ; make all -j $nombre_de_jobs_en_parallele 2>&1"], + ["cd $ENV{NOMAD_HOME}/src ; make clean ; make mpi -j $nombre_de_jobs_en_parallele 2>&1"] + ); + + +# le sémaphore permet de réguler le nombre de jobs en simultané, bloquant le processus principal tant qu'il n'y a pas de place de libre +my $semaphoreProblems = Thread::Semaphore->new($nombre_de_jobs_en_parallele); + + +# quelques variables partagées +my $cpt:shared; +my $failed:shared; + +# Initialisation de compteur et de tests +$cpt = 0; +$failed = 0; + +my $started = 0; + +################################################################ +# Sub pour résoudre les problèmes en parallèle +################################################################ +sub RunProblem($$$$$){ + my $aRef = shift; + my $index = shift; + my $cpt_ref = shift; + my $failed_ref = shift; + my $sema_ref = shift; + + open(WRITE_LOG,"> log$index.txt"); + for my $command (@{$aRef}){ + + my $fail=1; + + my @Problem=split(/;/,$command); + my $nmax=$#Problem; + my @Path=split(/\s+/,$Problem[0]); + + print WRITE_LOG "Path to problem: $Path[1] \n Command: $Problem[$nmax] ; Managed as process $index \n"; + open(LOG,"$command |") or die "Can't run program: $!\n"; + if ($? != 0) { + print "Echec d'exécution de la commande $! du process $index \n"; + $$failed_ref++; + $fail=0; + } + else { + @lines = <LOG>; + foreach $line (@lines){ + if (my @foo = grep(/$keySearch/, $line) ) { + print "????????? Probleme a l'execution de la commande du process $index :\n -----> @foo\n"; + print WRITE_LOG " !!!!!!!!!!!!!!! @foo \n "; + $$failed_ref++; + $fail=0; + last; + } + } + my $nL=$maxLinesForLogProblem; + if ( $#lines < $maxLinesForLogProblem){ + $nL=$#lines; + } + for ($i = $#lines - $nL ; $i != $#lines+1; $i++) { + print WRITE_LOG " -----> $lines[$i] "; + } + } + if ($fail==1){ + print WRITE_LOG "++++++++++++ OK! \n"; + } + close (LOG); + } + close (WRITE_LOG); + + # incrémente le nombre de jobs finis + $$cpt_ref++; + + # on a une place de libre. Ne pas oublier de libérer le sémaphore même en cas d'erreur + $$sema_ref->up(); + + return; +} + +############################# +# Sub pour les compilations +############################# +sub CompileNOMAD($$$){ + my $aRef = shift; + my $index = shift; + my $failed = shift; + + open(WRITE_LOG,"> logNOMADCompile$index.txt"); + for my $command (@{$aRef}){ + + my @Problem=split(/;/,$command); + my @Path=split(/\s+/,$Problem[0]); + + print WRITE_LOG "Path: $Path[1] \n Command: $Problem[1] ; Managed as process $index \n"; + open(LOG,"$command |") or die "Can't run program: $!\n"; + if ($? != 0) { + print "Echec d'exécution de la compilation de NOMAD par la commande $! process $index \n"; + $$failed=0; + } + else { + while (<LOG>){ + if (my @foo = grep(/error/, $_) ) { + print "??????? Probleme a la compilation de NOMAD dans le process $index:\n -----> @foo\n"; + print WRITE_LOG " -----> @foo \n "; + $$failed=0; + last; + } + if (my @foo = grep(/warning/, $_) ) { + print WRITE_LOG " -----> @foo \n "; + } + } + } + if ($$failed==1){ + print WRITE_LOG "++++++++++ OK! \n"; + } + close (LOG); + } + close (WRITE_LOG); + return; +} + +##################################### +##### Debut du programme principal +##################################### +# nettoie les fichiers de log +print "########################################################\n"; +print "On nettoie les anciens fichiers de log \n"; +system ("rm -f log*.txt"); + + +# démarre la compilation de nomad +my $failedCompileNOMAD=1; +my $thrNOMAD = threads->create("CompileNOMAD",($NOMADcompilations[0],1,\$failedCompileNOMAD)); ### Version parallele +#CompileNOMAD($NOMADcompilations[0],1,\$failedCompileNOMAD); ### Version scalaire +print "########################################################\n"; +print "La compilation de NOMAD (non mpi) vient de commencer \n"; + + +# démarre la compilation de nomad_mpi +my $failedCompileNOMAD_MPI=1; +my $thrNOMAD_MPI = threads->create("CompileNOMAD",($NOMADcompilations[1],2,\$failedCompileNOMAD_MPI)); ### Version parallele +#CompileNOMAD($NOMADcompilations[1],2,\$failedCompileNOMAD_MPI); ### Version scalaire +print "La compilation de NOMAD (mpi) vient de commencer \n"; + +$thrNOMAD->join(); +$thrNOMAD_MPI->join(); + +if ($failedCompileNOMAD==0){ + print "La compilation de NOMAD (non mpi) a echoue. On s'arrete la! \n"; +} + +if ($failedCompileNOMAD_MPI==0){ + print "La compilation de NOMAD (mpi) a echoue. On s'arrete la! \n"; +} + +if ($failedCompileNOMAD==0 or $failedCompileNOMAD_MPI==0){ + exit 0; +} + +print "Les compilations de nomad ont réussi \n"; +print "########################################################\n\n"; + +print "########################################################\n"; +print "Démarrage des executions en parallele pour les problemes \n"; +print "########################################################\n"; + + +# démarre tous les jobs +while ($started < scalar @list ){ + my $aRefToAListOfCommands = $list[$started]; + + # incrémente le compteur + $started++; + + # avons nous une place de libre ? + $semaphoreProblems->down(); + + # si le sémaphore est a 0, le processus principal va se bloquer en attendant une nouvelle place + print "Creation du job $started\n"; + my $thr = threads->create("RunProblem", ( + $aRefToAListOfCommands, + $started, + \$cpt, + \$failed, + \$semaphoreProblems + ) + ); + # détache le job du thread principal, rend la main au thread principal + $thr->detach(); + + # si on veut attendre la fin du job pour redonner la main, on utilise + # $thr->join(); +} + +# attend les derniers jobs +while ($cpt < $started){ + print "Seul $cpt jobs finis sur $started, on patiente!\n"; + sleep(3); +} +print "$cpt jobs lances, $failed échoués, sur les ".scalar @list." prévus\n"; + +if ($failed !=0) { + print "-----> Check the readme file for the failed problem(s)!!! \n"; +} + +print "On combine tous les logs en un seul\n"; +my $i=0; +open (LOGALL, '>', "logAll.txt") or die("impossible d'ecrire dans le fichier logAll.txt, $!"); +while ($i < scalar @list ){ + # incrémente le compteur + $i++; + open (LOGI, '<', "log$i.txt") or die("Impossible de lire log$i.txt, $!\n"); + print LOGALL "*********************************************************\n"; + while (my $Ligne = <LOGI> ) { + print LOGALL $Ligne; + } + close(LOGI); +} + +print "The End.\n"; -- GitLab