From bdb8db20f5d9b6c4d01bee61085ede61f71e8306 Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Wed, 17 Jan 2024 11:26:49 -0500 Subject: [PATCH 01/51] Update AdvancedFunctionalities.rst More about hidden constraints --- doc/user_guide/source/AdvancedFunctionalities.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/user_guide/source/AdvancedFunctionalities.rst b/doc/user_guide/source/AdvancedFunctionalities.rst index a86c99be..618ed676 100644 --- a/doc/user_guide/source/AdvancedFunctionalities.rst +++ b/doc/user_guide/source/AdvancedFunctionalities.rst @@ -300,6 +300,8 @@ It is triggered when a discontinuity or a hidden constraint is revealed. A new r Hidden constraints """""""""""""""""" +In some cases, blackbox execution cannot return all or some of the outputs because the experiment failed for unexpected reasons or because the simulation crashes for the given inputs, which corresponds to the presence of hidden constraints. + To use DiscoMADS to reveal hidden constraints regions, set ``DISCO_MADS_OPTIMIZATION`` to true and ``DISCO_MADS_HID_CONST`` to true. Set ``DISCO_MADS_EXCLUSION_RADIUS`` to define the wished remoteness of the solution to discontinuities. From 664014251626f1e226cd90eb659fb7f6286d12b1 Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Tue, 6 Feb 2024 09:34:58 -0500 Subject: [PATCH 02/51] Update example2_lib.cpp --- examples/basic/library/example2/example2_lib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/basic/library/example2/example2_lib.cpp b/examples/basic/library/example2/example2_lib.cpp index b5983508..ce912d9d 100644 --- a/examples/basic/library/example2/example2_lib.cpp +++ b/examples/basic/library/example2/example2_lib.cpp @@ -57,7 +57,7 @@ /* equality constraint. */ /* */ /* Modified problem: */ -/* Geometric constraint x1+...+d=5 */ +/* Geometric constraint x1+...+x4+d=10 */ /* Pb dimension is set to n=4 */ /* Set an inequality constraint: */ /* x1+...+x4<=10 */ From 3322f3f020dbebb7b32fa9c3ce6d31aed1c32b4e Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Wed, 7 Feb 2024 11:27:10 -0500 Subject: [PATCH 03/51] Update readme.txt --- interfaces/Matlab_MEX/readme.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interfaces/Matlab_MEX/readme.txt b/interfaces/Matlab_MEX/readme.txt index c1098693..cec9fd9b 100644 --- a/interfaces/Matlab_MEX/readme.txt +++ b/interfaces/Matlab_MEX/readme.txt @@ -97,4 +97,8 @@ command in Matlab you may obtain an error such as "Invalid MEX_file .... libstdc++.so.6: version `GLIBCXX_3.4.26' not found" (example obtained on linux-Ubuntu). This is an indication that the versions of Matlab and the compiler may not be compatible (See in the preamble -the web site to check compatibility). \ No newline at end of file +the web site to check compatibility). +If the versions at not too far apart a workaround can be to preload the +libstdc++ library used to build Nomad. For example we can do +"LD_PRELOAD=/lib64/libstdc++.so.6 matlab". +See https://github.com/bbopt/nomad/issues/159 for more details. From 6c2228a275d9b075fc5ad9dfea89f5ba847694d2 Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Wed, 6 Mar 2024 11:36:54 -0500 Subject: [PATCH 04/51] Add Python - PSD-Mads example --- .../advanced/batch/PSDMadsWithPythonBB/X0.txt | 2 ++ .../advanced/batch/PSDMadsWithPythonBB/bb.py | 20 +++++++++++++++++ .../batch/PSDMadsWithPythonBB/param.txt | 22 +++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 examples/advanced/batch/PSDMadsWithPythonBB/X0.txt create mode 100755 examples/advanced/batch/PSDMadsWithPythonBB/bb.py create mode 100755 examples/advanced/batch/PSDMadsWithPythonBB/param.txt diff --git a/examples/advanced/batch/PSDMadsWithPythonBB/X0.txt b/examples/advanced/batch/PSDMadsWithPythonBB/X0.txt new file mode 100644 index 00000000..82850ee3 --- /dev/null +++ b/examples/advanced/batch/PSDMadsWithPythonBB/X0.txt @@ -0,0 +1,2 @@ +0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 + diff --git a/examples/advanced/batch/PSDMadsWithPythonBB/bb.py b/examples/advanced/batch/PSDMadsWithPythonBB/bb.py new file mode 100755 index 00000000..b3771f93 --- /dev/null +++ b/examples/advanced/batch/PSDMadsWithPythonBB/bb.py @@ -0,0 +1,20 @@ +import sys +import os +import re +import numpy as np + + +input_file_name=sys.argv[1] +X=np.genfromtxt(input_file_name) + +#print(X) + +# Standard output is grabbed by Nomad evaluator +dim = len(X) +assert (dim%2==0), "Dimension must be an even number" + +f = 0 +for i in range(1,int(dim/2)): + f += pow( 10*X[2*i-1] - pow(X[2*i-2],2), 2) + pow(1-X[2*i-2],2) +print(f) +exit(0) diff --git a/examples/advanced/batch/PSDMadsWithPythonBB/param.txt b/examples/advanced/batch/PSDMadsWithPythonBB/param.txt new file mode 100755 index 00000000..a82b5096 --- /dev/null +++ b/examples/advanced/batch/PSDMadsWithPythonBB/param.txt @@ -0,0 +1,22 @@ +# NOTE: Nomad executable needs openMP support +# for this example to work + + +DIMENSION 50 + +BB_EXE '$python3 bb.py ' +BB_OUTPUT_TYPE OBJ + +X0 * 0.5 + +LOWER_BOUND * -10 +UPPER_BOUND * 10 + + +MAX_BB_EVAL 10000 + +PSD_MADS_OPTIMIZATION yes +NB_THREADS_OPENMP 4 + +DISPLAY_DEGREE 2 +DISPLAY_STATS BBE ( SOL ) OBJ From 1221ae08b0b00955533340645cff8433febf7249 Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Wed, 8 May 2024 15:46:54 -0400 Subject: [PATCH 05/51] Add explicit message to help user when bb outputs are not as expected --- src/Algos/Mads/MadsInitialization.cpp | 12 ++++++++---- src/Eval/Evaluator.cpp | 2 +- src/Util/defines.hpp | 3 +++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Algos/Mads/MadsInitialization.cpp b/src/Algos/Mads/MadsInitialization.cpp index b1d3bf51..c9471596 100644 --- a/src/Algos/Mads/MadsInitialization.cpp +++ b/src/Algos/Mads/MadsInitialization.cpp @@ -168,11 +168,11 @@ bool NOMAD::MadsInitialization::eval_x0s() } } + evalPointX0s.push_back(evalPointX0); if (x0Found && evalPointX0.isEvalOk(evalType)) { // evalOk is true if at least one evaluation is Ok evalOk = true; - evalPointX0s.push_back(evalPointX0); x0Failed = false; // At least one good X0. } @@ -187,10 +187,14 @@ bool NOMAD::MadsInitialization::eval_x0s() // If X0 fails, initialization is unsuccessful. _success = NOMAD::SuccessType::UNSUCCESSFUL; - for (const auto & x0 : _x0s) + for (const auto & ep: evalPointX0s) { - auto x0Full = x0.makeFullSpacePointFromFixed(NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); - AddOutputError("X0 evaluation failed for X0 = " + x0Full.display()); + const auto x0Full = ep.getX()->makeFullSpacePointFromFixed(NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); + AddOutputError("Evaluation failed for X0 = " + x0Full.display() + " -> Raw bb outputs obtained: \"" + ep.getBBO(evalType) + "\""); + if (ep.getEval(evalType)->getBBOutput().getBBOAsArrayOfDouble().size() != ep.getEval(evalType)->getBBOutputTypeList().size()) + { + AddOutputError("Evaluation of point do not return the registered number of outputs, " + std::to_string(ep.getEval(evalType)->getBBOutput().getBBOAsArrayOfDouble().size()) + " instead of " + std::to_string(ep.getEval(evalType)->getBBOutputTypeList().size()) + " expected. You may need to increase the buffer size in $NOMAD_HOME/src/Util/defines.hpp and rebuild Nomad." ); + } } } else diff --git a/src/Eval/Evaluator.cpp b/src/Eval/Evaluator.cpp index 8ef025d6..fe1ba6f7 100644 --- a/src/Eval/Evaluator.cpp +++ b/src/Eval/Evaluator.cpp @@ -388,7 +388,7 @@ std::vector NOMAD::Evaluator::evalXBBExe(NOMAD::Block &block, if (!_bbRedirection) { - char buffer[1024]; + char buffer[BUFFER_SIZE]; char *outputline = nullptr; outputline = fgets(buffer, sizeof(buffer), fresult); diff --git a/src/Util/defines.hpp b/src/Util/defines.hpp index 3a0137e9..fc2fb8b4 100644 --- a/src/Util/defines.hpp +++ b/src/Util/defines.hpp @@ -151,6 +151,9 @@ const int INT_DISPLAY_WIDTH = 3; // Width for integers // Maximal output value for points used for models. const double MODEL_MAX_OUTPUT = 1E20; +// Buffer size for reading BB outputs +const size_t BUFFER_SIZE = 1024; + // ------------------------- // Related to MADS algorithm From 555a240670b0d33217e87a19b553720260e40c82 Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Fri, 10 May 2024 08:48:35 -0400 Subject: [PATCH 06/51] Update Evaluator.cpp Buffer size uses a global variable everywhere --- src/Eval/Evaluator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Eval/Evaluator.cpp b/src/Eval/Evaluator.cpp index fe1ba6f7..03ac21cf 100644 --- a/src/Eval/Evaluator.cpp +++ b/src/Eval/Evaluator.cpp @@ -464,7 +464,7 @@ std::vector NOMAD::Evaluator::evalXBBExe(NOMAD::Block &block, { std::shared_ptr x = block[index]; - char buffer[1024]; + char buffer[BUFFER_SIZE]; char *outputLine = nullptr; size_t nbTries=0; From fe37be5679b6de177076b2b8a01ea693b2a7a0ea Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Thu, 16 May 2024 09:37:48 -0400 Subject: [PATCH 07/51] Update PollMethodBase.cpp An exception was reported for VARIABLE_GROUP with Ortho n+1 neg --- src/Algos/Mads/PollMethodBase.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Algos/Mads/PollMethodBase.cpp b/src/Algos/Mads/PollMethodBase.cpp index db206d8b..35508cf5 100644 --- a/src/Algos/Mads/PollMethodBase.cpp +++ b/src/Algos/Mads/PollMethodBase.cpp @@ -224,6 +224,8 @@ std::list NOMAD::PollMethodBase::generateFullSpaceScaledDirect { for (auto vg : _varGroups) { + directionsSubSpace.clear(); + size_t nVG = vg.size(); if (!isSecondPass) From 6ca90edf8f54d23aa254f91a92b269a42421850d Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Thu, 16 May 2024 10:31:32 -0400 Subject: [PATCH 08/51] Update EvaluatorControl.cpp Blackbox outputs most likely cause this exception. More info to help user fix the blackbox. --- src/Eval/EvaluatorControl.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Eval/EvaluatorControl.cpp b/src/Eval/EvaluatorControl.cpp index 80ca8fd9..d6db5f7f 100644 --- a/src/Eval/EvaluatorControl.cpp +++ b/src/Eval/EvaluatorControl.cpp @@ -2228,6 +2228,12 @@ std::vector NOMAD::EvaluatorControl::evalBlockOfPoints( { std::string err("EvaluatorControl: Eval Block of Points: eval_x returned an exception: "); err += e.what(); + err += " \n Blackbox evaluation maybe the cause of this exception. Raw bb outputs obtained: \""; + for ( const auto & ep : block) + { + err += ep->getBBO(evalType); + err += "\"\n"; + } throw NOMAD::Exception(__FILE__, __LINE__, err); } From e577a6a65fa156f14f932e29e028460c26871d3d Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Thu, 29 Aug 2024 11:33:01 -0400 Subject: [PATCH 09/51] Update readme.txt --- interfaces/PyNomad/readme.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interfaces/PyNomad/readme.txt b/interfaces/PyNomad/readme.txt index 9f373770..e54074b1 100644 --- a/interfaces/PyNomad/readme.txt +++ b/interfaces/PyNomad/readme.txt @@ -27,9 +27,9 @@ https://packaging.python.org/en/latest/tutorials/installing-packages/ To install the last version, from a shell command line perform: -pip install PyNomad +pip install PyNomadBBO -PyNomad from PyPI relies on Python3 version 3.8 and above. +PyNomadBBO from PyPI relies on Python3 version 3.8 and above. ********** HOW TO USE @@ -144,4 +144,4 @@ proposed in the $NOMAD_HOME/examples/advanced/library/PyNomad directory. python3 simpleExample_basic.py python3 simpleExample_BlockEval.py - Python3 simpleExample_PbWithConst.py \ No newline at end of file + Python3 simpleExample_PbWithConst.py From 67d34b43e9815688b65225602cb87e65d3f34ce0 Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Thu, 5 Sep 2024 09:41:17 -0400 Subject: [PATCH 10/51] Update pypi.yml --- .github/workflows/pypi.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index d450cdcf..b25fb607 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -53,7 +53,7 @@ jobs: cmake --version - name: Build binary wheels - uses: pypa/cibuildwheel@v2.12.0 + uses: pypa/cibuildwheel@v2.20.0 env: CIBW_ARCHS: >- ${{ matrix.target.archs }} @@ -76,7 +76,7 @@ jobs: package-dir: interfaces/PyNomad - name: Collect wheels for processing - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: wheelhouse/*.whl @@ -94,7 +94,7 @@ jobs: steps: - name: Collect wheels for publication - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: artifact path: dist From 7c27558af22bd1c284a6a33ff73b435e45348a96 Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Thu, 23 Jan 2025 11:44:02 -0500 Subject: [PATCH 11/51] Update README.txt --- README.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.txt b/README.txt index 32b9c306..852725b4 100644 --- a/README.txt +++ b/README.txt @@ -126,13 +126,11 @@ cmake -S . -B build/release addpath(strcat(getenv('NOMAD_HOME'),'/build/release/bin')) To enable *Python* interface (PyNomad) building: - cmake -DBUILD_INTERFACE_PYTHON=ON -DTEST_OPENMP=OFF -S . -B build/release + cmake -DBUILD_INTERFACE_PYTHON=ON -S . -B build/release ! Before proceeding, have a look into $NOMAD_HOME/interfaces/PyNomad/readme.txt - ! The Python interface will not be built if OpenMP is enabled. - ! More details are provided in $NOMAD_HOME/interfaces/PyNomad/readme.txt ! Building requires to have Cython. Cython can be obtained with @@ -151,8 +149,10 @@ cmake --build build/release (for *OSX* and *Linux*) Option --parallel xx can be added for faster build. - The option --config Release should be used on *Windows* to build only + The option --config Release should be used on *Windows* + multi-configuration build environment (VisualStudio) to build only Release configuration. The default configuration is Debug. + The same option should be used for *OSX* when using a *Xcode* project. cmake --install build/release --config Release (for *Windows*) or From 22ad3daf8ef27c0146524c1fdf272d8d7fe1d234 Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Thu, 23 Jan 2025 15:27:24 -0500 Subject: [PATCH 12/51] Update examples --- CMakeLists.txt | 45 +- doc/doxygen/Doxyfile | 2 +- examples/CMakeLists.txt | 13 +- .../batch/BBOutputRedirection/CMakeLists.txt | 12 +- .../{bb5.cpp => bb_redirect.cpp} | 50 +- .../batch/BBOutputRedirection/param.txt | 26 +- .../advanced/batch/CountEval/CMakeLists.txt | 15 + .../CountEval/bb_cnt_eval.cpp} | 140 ++-- examples/advanced/batch/CountEval/param.txt | 38 + .../advanced/batch/DiscoMads/CMakeLists.txt | 9 +- .../batch/DiscoMads/paramEscapeDiscont.txt | 1 - .../paramEscapeHiddenConstraints.txt | 85 ++ .../batch/FixedVariable/CMakeLists.txt | 18 +- .../advanced/batch/FixedVariable/param.txt | 9 + .../advanced/batch/FixedVariable/param10.txt | 9 + .../advanced/batch/FixedVariable/param2.txt | 8 + .../advanced/batch/FixedVariable/param3.txt | 8 + .../advanced/batch/FixedVariable/runFixed.sh | 1 + .../batch/FixedVariable/runFixedWin.sh | 10 +- examples/advanced/batch/IBEX/README.txt | 4 +- examples/advanced/batch/IBEX/bb.cpp | 49 +- examples/advanced/batch/LHonly/CMakeLists.txt | 11 +- .../batch/PSDMadsWithPythonBB/param.txt | 6 +- .../batch/SuggestAndObserve/CMakeLists.txt | 17 +- .../advanced/batch/SuggestAndObserve/bbr.cpp | 9 +- .../batch/SuggestAndObserve/utils.cpp | 11 +- .../batch/UseCacheFileForRerun/CMakeLists.txt | 8 +- .../advanced/library/COOPMads/CMakeLists.txt | 31 + .../library/COOPMads/rosenbrockCoop.cpp} | 144 +++- .../CustomCompForOrdering/CMakeLists.txt | 17 +- .../customCompForOrdering.cpp | 77 +- .../CustomOpportunistic/CMakeLists.txt | 17 +- .../CustomOpportunistic/customOpport.cpp | 35 +- .../library/CustomPollMethod/CMakeLists.txt | 20 + .../CustomPollMethod/customPollMethod.cpp | 293 +++++++ .../library/CustomSearchMethod/CMakeLists.txt | 20 + .../CustomSearchMethod/customSearchMethod.cpp | 233 ++++++ .../library/CustomStatSum/CMakeLists.txt | 17 +- .../library/CustomStatSum/customStatSum.cpp | 30 +- .../EscapeDiscontinuities/CMakeLists.txt | 16 +- .../DiscoMadsEscapeDiscont.cpp | 22 +- .../EscapeHiddenConstraints/CMakeLists.txt | 16 +- .../DiscoMadsEscapeHiddenConstraints.cpp | 13 +- .../advanced/library/FixedVariable/.gitignore | 1 + .../library/FixedVariable/CMakeLists.txt | 13 +- .../library/FixedVariable/fixedVariable.cpp | 21 +- .../HandlingHiddenConstraints/CMakeLists.txt | 17 +- .../handlingHiddenCons.cpp | 20 +- .../advanced/library/NMonly/CMakeLists.txt | 18 +- examples/advanced/library/NMonly/NMOpt.cpp | 11 +- .../library/NestedOptim/CMakeLists.txt | 30 + .../library/NestedOptim/nestedOptim.cpp | 224 +++++ .../advanced/library/PSDMads/CMakeLists.txt | 14 +- .../advanced/library/PSDMads/rosenbrock.cpp | 33 +- .../PyNomad/LoopSuggestAndObserve/.gitignore | 1 - .../PyNomad/LoopSuggestAndObserve/cache0.txt | 4 - .../runTestLoopSuggestAndObserve.py | 85 -- .../library/PyNomad/OnlyObserve/.gitignore | 3 - .../library/PyNomad/OnlyObserve/cache0.txt | 4 - .../PyNomad/OnlyObserve/runTestObserve.py | 23 - .../PyNomad/OnlySuggest/runTestSuggest.py | 23 - .../PyNomad/OptimizeWithMainStep/bb.py | 16 - .../PyNomad/OptimizeWithMainStep/param.txt | 12 - .../runTestOptimizeWithMainStep.py | 8 - .../PyNomad/OptimizeWithMainStep/x0.txt | 1 - .../simpleExample_BlockEvalParallel.py | 57 ++ .../PyNomad/simpleExample_NMOptimization.py | 21 + .../simpleExample_basic_parallelEval.py | 25 + .../advanced/library/Restart/CMakeLists.txt | 17 +- examples/advanced/library/Restart/restart.cpp | 26 +- .../library/Restart_VNS/CMakeLists.txt | 35 - .../Restart_VNS/problems/7_WILD3/bb.cpp | 791 ------------------ .../Restart_VNS/problems/7_WILD3/param.txt | 25 - .../problems/7_WILD3/param_VNSmartAlgo.txt | 16 - .../Restart_VNS/problems/7_WILD3/paramvns.txt | 25 - .../Restart_VNS/problems/7_WILD3/x0.txt | 2 - .../Restart_VNS/problems/COCO/Readme.txt | 7 - .../Restart_VNS/problems/COCO/param.txt | 33 - .../problems/COCO/param_VNSmartAlgo.txt | 24 - .../Restart_VNS/problems/COCO/paramvns.txt | 38 - .../library/Restart_VNS/problems/COCO/x0.txt | 1 - .../Restart_VNS/problems/RASTRIGIN/param.txt | 20 - .../problems/RASTRIGIN/param_VNSmartAlgo.txt | 19 - .../problems/RASTRIGIN/paramvns.txt | 20 - .../Restart_VNS/problems/RASTRIGIN/x0.txt | 1 - .../Restart_VNS/problems/RASTRIGIN/xe.txt | 3 - .../library/Restart_VNS/restart_vns.cpp | 481 ----------- .../library/StopIfBBFails/CMakeLists.txt | 17 +- .../library/StopIfBBFails/stopIfBBFails.cpp | 13 +- .../StopOnConsecutiveFails/CMakeLists.txt | 17 +- .../stopOnConsecutiveFails.cpp | 24 +- .../library/c_api/example1/CMakeLists.txt | 13 +- .../library/c_api/example1/example1_c_api.c | 86 +- .../library/c_api/example2/CMakeLists.txt | 19 +- .../library/c_api/example2/example2_c_api.c | 98 ++- .../library/c_api/example3/CMakeLists.txt | 45 + .../library/c_api/example3/example3_c_api.c | 212 +++++ .../loopSuggestAndObserve.cpp | 17 +- .../suggestAndObserve.cpp | 8 +- examples/basic/batch/MatlabBB/paramNomad.txt | 32 +- examples/basic/batch/PythonBB/param.txt | 2 +- examples/basic/batch/example1/CMakeLists.txt | 1 + examples/basic/batch/example1/param.txt | 6 - .../batch/example1/param_COOPMads.txt} | 34 +- examples/basic/batch/example1/param_LH.txt | 45 + .../basic/batch/example1/param_LH_ONLY.txt | 27 + .../batch/{example2 => example1}/param_NM.txt | 18 +- examples/basic/batch/example1/x0.txt | 1 + examples/basic/batch/example2/param.txt | 9 +- examples/basic/batch/multi_obj/param.txt | 4 +- examples/basic/batch/multi_obj/x.txt | 1 + .../basic/batch/multi_obj2/CMakeLists.txt | 8 +- examples/basic/batch/multi_obj2/param.txt | 1 - .../basic/batch/multi_obj2/param_testQMS.txt | 40 + examples/basic/batch/multi_obj2/x.txt | 1 + .../basic/batch/single_obj/CMakeLists.txt | 16 - examples/basic/batch/single_obj/param.txt | 40 - examples/basic/batch/single_obj/x.txt | 1 - .../batch/single_obj_MPIparallel/param.txt | 7 +- .../batch/single_obj_parallel/CMakeLists.txt | 8 +- .../basic/batch/single_obj_parallel/param.txt | 2 +- .../basic/batch/surrogate_sort/CMakeLists.txt | 8 +- examples/basic/batch/surrogate_sort/param.txt | 3 - .../surrogate_sort/param_surrogateOptim.txt | 3 +- .../CustomSurrogateOrdering/CMakeLists.txt | 17 +- .../customSurrogateOrdering.cpp | 36 +- .../library/StopOnFTarget/CMakeLists.txt | 17 +- .../library/StopOnFTarget/stopOnFTarget.cpp | 32 +- .../basic/library/example1/example1_lib.cpp | 28 +- .../basic/library/example2/example2_lib.cpp | 15 +- .../basic/library/example3/CMakeLists.txt | 32 - .../basic/library/example3/example3_lib.cpp | 197 ----- .../basic/library/example4/CMakeLists.txt | 32 - .../basic/library/example4/example4_lib.cpp | 204 ----- .../basic/library/multi_obj/CMakeLists.txt | 29 + .../basic/library/multi_obj/multi_obj_lib.cpp | 279 ++++++ .../library/single_obj_parallel/basic_lib.cpp | 87 +- 137 files changed, 2649 insertions(+), 3127 deletions(-) rename examples/advanced/batch/BBOutputRedirection/{bb5.cpp => bb_redirect.cpp} (59%) create mode 100644 examples/advanced/batch/CountEval/CMakeLists.txt rename examples/advanced/{library/Restart_VNS/problems/RASTRIGIN/bb.cpp => batch/CountEval/bb_cnt_eval.cpp} (64%) create mode 100644 examples/advanced/batch/CountEval/param.txt create mode 100644 examples/advanced/batch/DiscoMads/paramEscapeHiddenConstraints.txt create mode 100644 examples/advanced/library/COOPMads/CMakeLists.txt rename examples/{basic/batch/single_obj/bb.cpp => advanced/library/COOPMads/rosenbrockCoop.cpp} (54%) create mode 100644 examples/advanced/library/CustomPollMethod/CMakeLists.txt create mode 100644 examples/advanced/library/CustomPollMethod/customPollMethod.cpp create mode 100644 examples/advanced/library/CustomSearchMethod/CMakeLists.txt create mode 100644 examples/advanced/library/CustomSearchMethod/customSearchMethod.cpp create mode 100644 examples/advanced/library/NestedOptim/CMakeLists.txt create mode 100644 examples/advanced/library/NestedOptim/nestedOptim.cpp delete mode 100644 examples/advanced/library/PyNomad/LoopSuggestAndObserve/.gitignore delete mode 100644 examples/advanced/library/PyNomad/LoopSuggestAndObserve/cache0.txt delete mode 100644 examples/advanced/library/PyNomad/LoopSuggestAndObserve/runTestLoopSuggestAndObserve.py delete mode 100644 examples/advanced/library/PyNomad/OnlyObserve/.gitignore delete mode 100644 examples/advanced/library/PyNomad/OnlyObserve/cache0.txt delete mode 100644 examples/advanced/library/PyNomad/OnlyObserve/runTestObserve.py delete mode 100644 examples/advanced/library/PyNomad/OnlySuggest/runTestSuggest.py delete mode 100644 examples/advanced/library/PyNomad/OptimizeWithMainStep/bb.py delete mode 100644 examples/advanced/library/PyNomad/OptimizeWithMainStep/param.txt delete mode 100644 examples/advanced/library/PyNomad/OptimizeWithMainStep/runTestOptimizeWithMainStep.py delete mode 100644 examples/advanced/library/PyNomad/OptimizeWithMainStep/x0.txt create mode 100644 examples/advanced/library/PyNomad/simpleExample_BlockEvalParallel.py create mode 100644 examples/advanced/library/PyNomad/simpleExample_NMOptimization.py create mode 100644 examples/advanced/library/PyNomad/simpleExample_basic_parallelEval.py delete mode 100644 examples/advanced/library/Restart_VNS/CMakeLists.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/7_WILD3/bb.cpp delete mode 100644 examples/advanced/library/Restart_VNS/problems/7_WILD3/param.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/7_WILD3/param_VNSmartAlgo.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/7_WILD3/paramvns.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/7_WILD3/x0.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/COCO/Readme.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/COCO/param.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/COCO/param_VNSmartAlgo.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/COCO/paramvns.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/COCO/x0.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/RASTRIGIN/param.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/RASTRIGIN/param_VNSmartAlgo.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/RASTRIGIN/paramvns.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/RASTRIGIN/x0.txt delete mode 100644 examples/advanced/library/Restart_VNS/problems/RASTRIGIN/xe.txt delete mode 100644 examples/advanced/library/Restart_VNS/restart_vns.cpp create mode 100644 examples/advanced/library/c_api/example3/CMakeLists.txt create mode 100644 examples/advanced/library/c_api/example3/example3_c_api.c rename examples/{advanced/batch/UseCacheFileForRerun/paramNextStep.txt => basic/batch/example1/param_COOPMads.txt} (53%) create mode 100644 examples/basic/batch/example1/param_LH.txt create mode 100644 examples/basic/batch/example1/param_LH_ONLY.txt rename examples/basic/batch/{example2 => example1}/param_NM.txt (57%) create mode 100644 examples/basic/batch/example1/x0.txt create mode 100644 examples/basic/batch/multi_obj/x.txt create mode 100644 examples/basic/batch/multi_obj2/param_testQMS.txt create mode 100644 examples/basic/batch/multi_obj2/x.txt delete mode 100644 examples/basic/batch/single_obj/CMakeLists.txt delete mode 100644 examples/basic/batch/single_obj/param.txt delete mode 100644 examples/basic/batch/single_obj/x.txt delete mode 100644 examples/basic/library/example3/CMakeLists.txt delete mode 100644 examples/basic/library/example3/example3_lib.cpp delete mode 100644 examples/basic/library/example4/CMakeLists.txt delete mode 100644 examples/basic/library/example4/example4_lib.cpp create mode 100644 examples/basic/library/multi_obj/CMakeLists.txt create mode 100644 examples/basic/library/multi_obj/multi_obj_lib.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 005e7a34..c66c54ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,10 +7,10 @@ cmake_minimum_required(VERSION 3.15...3.15) # Warning. This must be consistent with src/nomad_version.hpp set(NOMAD_VERSION_MAJOR 4) -set(NOMAD_VERSION_MINOR 4) -set(NOMAD_VERSION_PATCH 0) -set(NOMAD_VERSION ${NOMAD_VERSION_MAJOR}.${NOMAD_VERSION_MINOR}.${NOMAD_VERSION_PATCH}) +set(NOMAD_VERSION_MINOR 5) +set(NOMAD_VERSION_PATCH beta1) # The beta version betaX is for develop branch of the public repo. +set(NOMAD_VERSION ${NOMAD_VERSION_MAJOR}.${NOMAD_VERSION_MINOR}.${NOMAD_VERSION_PATCH}) # name of the project # Need to update when version changes @@ -29,8 +29,8 @@ endif() # Need to update when version changes set(NOMAD_SRC_TEMPLATE NOMAD_${NOMAD_VERSION_MAJOR}_${NOMAD_VERSION_MINOR}) -# use standard compilers parameters for c++14 -SET(CMAKE_CXX_STANDARD 14 ) +# use standard compilers parameters for c++17 +SET(CMAKE_CXX_STANDARD 17 ) SET(CMAKE_CXX_STANDARD_REQUIRED ON ) # Disable in-source builds to prevent source tree corruption. @@ -42,7 +42,7 @@ endif() #check compiler version if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - # require at least gcc 4 + # require at least gcc 8 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8) message(FATAL_ERROR "GCC version < 8 has not been tested for Nomad") endif() @@ -53,7 +53,7 @@ elseif (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") message(FATAL_ERROR "Clang version has not been tested for Nomad") endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # require at least 15.0 (MSVC 2017) for C++14 support + # require at least 15.8 (MSVC 2017) for C++17 support if (MSVC_TOOLSET_VERSION VERSION_LESS 141) message(FATAL_ERROR "MSVC version ${CMAKE_CXX_COMPILER_VERSION} has not been tested for Nomad") endif() @@ -72,9 +72,25 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) # # Message for starting configuration # -message(CHECK_START " Configuring custom options") +message(CHECK_START "Configuring custom options") list(APPEND CMAKE_MESSAGE_INDENT " ") +# +# Modify the build type if not specified on the command +# +if (CMAKE_CONFIGURATION_TYPES) + message(STATUS " Multi-configuration generator detected. Use the --config option during build to specify the build type (Release, Debug, ...).") +else() + if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE PATH "..." FORCE) + message(STATUS " Build type not set explicitly. Default is set to Release. To force build type selection, use --DCMAKE_BUILD_TYPE=xxx, options are Debug Release RelWithDebInfo MinSizeRel.") + else() + message(STATUS " Build type is ${CMAKE_BUILD_TYPE}") + endif() +endif() + + + # # Modify the install prefix if not specified on the command # @@ -83,6 +99,7 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) endif() message(STATUS " Installation prefix set to ${CMAKE_INSTALL_PREFIX}") + # # Choose to build with time stats enabled # @@ -123,6 +140,7 @@ else() message(STATUS " Examples NOT built") endif() + # # Choose to build the C interface # @@ -140,15 +158,11 @@ endif() # option(BUILD_INTERFACE_PYTHON "Option to build Python interface to Nomad" OFF) if(BUILD_INTERFACE_PYTHON MATCHES ON) - if(OpenMP_FOUND) - message(STATUS " Warning: Cannot build Python interface with OpenMP enabled") - else() - set(Python3_FIND_VIRTUALENV "First") - find_package(Python 3.6 QUIET REQUIRED) + set(Python3_FIND_VIRTUALENV "First") # Using virtualenv to have cython and wheel is easy + find_package(Python 3.8 QUIET REQUIRED) message(CHECK_START " Configuring build for Python interface (Python ${Python_VERSION})") add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/PyNomad) message(CHECK_PASS " done") - endif() else() message(STATUS " Python interface to Nomad NOT built") endif() @@ -240,14 +254,13 @@ else() message(STATUS " Sgtelib library will NOT be used\n") endif() - - # # Custom options final message # list(REMOVE_ITEM CMAKE_MESSAGE_INDENT " ") message(CHECK_PASS " done") + # # Add nomad app directory for building # diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index a0d3b5d6..dd73ab7f 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "NOMAD Source" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "Version 4.2" +PROJECT_NUMBER = "Version 4.5" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5735faa9..2ad0c12d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,17 +1,18 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/library/example1) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/library/example2) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/library/example3) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/library/example4) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/library/multi_obj) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/library/single_obj_parallel) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/library/StopOnFTarget) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/library/CustomSurrogateOrdering) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/FixedVariable) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/NMonly) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/Restart) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/Restart_VNS) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/exampleSuggestAndObserve) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/CustomOpportunistic) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/CustomPollMethod) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/CustomSearchMethod) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/DiscoMads/EscapeDiscontinuities) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/DiscoMads/EscapeHiddenConstraints) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/HandlingHiddenConstraints) @@ -21,17 +22,18 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/CustomCompForOrder add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/CustomStatSum) if(OpenMP_CXX_FOUND) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/PSDMads) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/COOPMads) endif() if (BUILD_INTERFACE_C MATCHES ON) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/c_api/example1) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/c_api/example2) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/library/c_api/example3) endif() # For running the tests on the batch examples we need to build the blackbox # AND install add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/batch/example1) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/batch/single_obj) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/batch/multi_obj) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/batch/multi_obj2) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/batch/surrogate_sort) @@ -40,12 +42,13 @@ if(OpenMP_CXX_FOUND) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/batch/single_obj_parallel) endif() add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/basic/batch/single_obj_MPIparallel) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/batch/BBOutputRedirection) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/batch/LHonly) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/batch/CountEval) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/batch/FixedVariable) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/batch/SuggestAndObserve) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/batch/DiscoMads) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/batch/UseCacheFileForRerun) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/advanced/batch/BBOutputRedirection) # The script for running library examples is created in a temp directory FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/tmp/runExampleTest.sh diff --git a/examples/advanced/batch/BBOutputRedirection/CMakeLists.txt b/examples/advanced/batch/BBOutputRedirection/CMakeLists.txt index ef27350c..2dece6c1 100644 --- a/examples/advanced/batch/BBOutputRedirection/CMakeLists.txt +++ b/examples/advanced/batch/BBOutputRedirection/CMakeLists.txt @@ -1,15 +1,15 @@ set(CMAKE_EXECUTABLE_SUFFIX .exe) -add_executable(bb5.exe bb5.cpp ) -set_target_properties(bb5.exe PROPERTIES SUFFIX "") +add_executable(bb_redirect.exe bb_redirect.cpp ) +set_target_properties(bb_redirect.exe PROPERTIES SUFFIX "") # installing executables and libraries -install(TARGETS bb5.exe +install(TARGETS bb_redirect.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) # Add a test for this example -message(STATUS " Add example batch #5") +message(STATUS " Add example advanced batch BB redirection") -# Test run in working directory AFTER install of bb5.exe executable -add_test(NAME Example5BasicBatch +# Test run in working directory AFTER install of bb_redirect.exe executable +add_test(NAME ExampleAdvancedBatchRedirect COMMAND ${CMAKE_INSTALL_PREFIX}/bin/nomad param.txt WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/examples/advanced/batch/BBOutputRedirection/bb5.cpp b/examples/advanced/batch/BBOutputRedirection/bb_redirect.cpp similarity index 59% rename from examples/advanced/batch/BBOutputRedirection/bb5.cpp rename to examples/advanced/batch/BBOutputRedirection/bb_redirect.cpp index 84085e28..1e9b9fad 100644 --- a/examples/advanced/batch/BBOutputRedirection/bb5.cpp +++ b/examples/advanced/batch/BBOutputRedirection/bb_redirect.cpp @@ -44,10 +44,56 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ // // BB_5 // -// Created by CT +// Created by Christophe Tribes // #include #include @@ -60,7 +106,7 @@ using namespace std; // The name of the output MUST be inputfilename.output. // INPUT and OUTPUT files have a fixed name during optimization. // Some verbose can be displayed on the standard output or standard error and will not be considered by Nomad -// The verbose can be send to a log file (see param.txt file). +// The verbose is stored in a log file. int main(int argc, const char ** argv) { diff --git a/examples/advanced/batch/BBOutputRedirection/param.txt b/examples/advanced/batch/BBOutputRedirection/param.txt index ffece1c2..cb53b4e8 100644 --- a/examples/advanced/batch/BBOutputRedirection/param.txt +++ b/examples/advanced/batch/BBOutputRedirection/param.txt @@ -3,21 +3,21 @@ DIMENSION 2 # number of variables -BB_EXE bb5.exe # 'bb5.exe' is a program that - # takes in argument the name of - # a text file ('input filename') - # containing 2 - # values, and that write 1 - # values that correspond to the - # objective function value (OBJ) - # in a file inputfilename.output - # IN THAT CASE WE MUST HAVE THE OPTION - # BB_REDIRECTION no - # To have log file use BB_EXE "bb5.exe $>> $log.txt" +BB_EXE bb_redirect.exe # 'bb_redirect.exe' is a program that + # takes in argument the name of + # a text file ('input filename') + # containing 2 + # values, and that write 1 + # values that correspond to the + # objective function value (OBJ) + # in a file inputfilename.output + # IN THAT CASE WE MUST HAVE THE OPTION + # BB_REDIRECTION no + # To have log file use BB_EXE "bb_redirect.exe $>> $log.txt" BB_OUTPUT_TYPE OBJ -BB_REDIRECTION no # For a blackbox that manages the output file (default - # is redirection), NOMAD expect an output file with a name +BB_REDIRECTION no # For a blackbox that manages the output file + # NOMAD expect an output file with a name # of the input file + ".output' # INPUT and OUTPUT files have a fixed name # during optimization. diff --git a/examples/advanced/batch/CountEval/CMakeLists.txt b/examples/advanced/batch/CountEval/CMakeLists.txt new file mode 100644 index 00000000..51db91c5 --- /dev/null +++ b/examples/advanced/batch/CountEval/CMakeLists.txt @@ -0,0 +1,15 @@ +set(CMAKE_EXECUTABLE_SUFFIX .exe) +add_executable(bb_cnt_eval.exe bb_cnt_eval.cpp ) +set_target_properties(bb_cnt_eval.exe PROPERTIES SUFFIX "") + +# installing executables and libraries +install(TARGETS bb_cnt_eval.exe + RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) + +# Add a test for this example +message(STATUS " Add example advanced batch count eval") + +# Test run in working directory AFTER install of bb_cnt_eval.exe executable +add_test(NAME CountEvalAdvancedBatch + COMMAND ${CMAKE_INSTALL_PREFIX}/bin/nomad param.txt + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/bb.cpp b/examples/advanced/batch/CountEval/bb_cnt_eval.cpp similarity index 64% rename from examples/advanced/library/Restart_VNS/problems/RASTRIGIN/bb.cpp rename to examples/advanced/batch/CountEval/bb_cnt_eval.cpp index 8e9ad6be..563f8386 100644 --- a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/bb.cpp +++ b/examples/advanced/batch/CountEval/bb_cnt_eval.cpp @@ -44,74 +44,102 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#include +#include // For sqrt +#include // For ifstream #include -#include -#include -#include -using namespace std; - - - -int main ( int argc , char ** argv ) { - - double f = 1e20; - - int n = 12; - const double pi = 3.1415927; - f = 10.0*n; - - if ( argc >= 2 ) { - - double * x = new double[n]; - // read the point: - ifstream in ( argv[1] ); - for (int i = 0 ; i < n ; ++i ) +#include // For logic_error +#include + +const int n = 10; + +int main (int argc, char **argv) +{ + bool eval_ok = false; + + // Remotely based on G2. + double f = 1e+20, g1 = 1e+20, g2 = 1e+20, g3 = 1e+20; + double sum1 = 0.0, sum2 = 0.0, sum3 = 0.0, prod1 = 1.0, prod2 = 1.0; + double x[n]; + + bool x0read = false; + if (argc >= 2) + { + std::string x0file = argv[1]; + std::ifstream in (argv[1]); + for (int i = 0; i < n; i++) { + if (in.fail()) + { + std::cerr << "Error reading file " << x0file << " for x0." << std::endl; + x0read = false; + break; + } in >> x[i]; + x0read = true; } in.close(); - - if ( !in.fail() ) - for ( int j = 0 ; j < n ; j++) - { - f += x[j]*x[j] - 10.0*cos(2.0*pi*x[j]); - } } - - cout.setf(ios::fixed); - cout.precision(15); - cout << f << endl; - return 0; -} - - - - -/* -int main ( int argc , char ** argv ) { - - double f = 1e20; - if ( argc >= 2 ) { + if (x0read) + { + try + { + for (int i = 0; i < n ; i++) + { + sum1 += pow(cos(x[i]), 4); + sum2 += x[i]; + sum3 += (i+1)*x[i]*x[i]; + prod1 *= pow(cos(x[i]), 2); + if (prod2 != 0.0) + { + if (x[i] == 0.0) + { + prod2 = 0.0; + } + else + { + prod2 *= x[i]; + } + } + } - double x , y; - ifstream in ( argv[1] ); + g1 = -prod2 + 0.75; + + // Let's say g1 is a hidden constraint. We don't want to count when it is not verified + if (g1>0) + { + std::cout << 0 << " Inf" << std::endl; + return 1; + } + + g2 = sum2 -7.5 * n; - in >> x >> y; - - in.close(); + f = 10*g1 + 10*g2; + if (0.0 != sum3) + { + f -= (sum1 -2*prod1) / std::abs(sqrt(sum3)); + } + // Scale + if (!std::isnan(f)) + { + f *= 1e-5; + } - if ( !in.fail() ) - f = 20 + x*x + y*y - 10*cos(6.283185307*x) - 10*cos(6.283185307*y); + eval_ok = !std::isnan(f); - } + g3 = - (f + 2000); + } + catch (std::exception &e) + { + std::string err("Exception: "); + err += e.what(); + throw std::logic_error(err); + } + } - cout.setf(ios::fixed); - cout.precision(15); - cout << f << endl; + std::cout << 1 << " " << f << " " << g2 << " " << g3 << std::endl; - return 0; + // Return 0 if eval_ok. + return !eval_ok; } - */ diff --git a/examples/advanced/batch/CountEval/param.txt b/examples/advanced/batch/CountEval/param.txt new file mode 100644 index 00000000..6b8ccc60 --- /dev/null +++ b/examples/advanced/batch/CountEval/param.txt @@ -0,0 +1,38 @@ +# +# Example: count eval flag is provided by the blackbox +# If a hidden constraint is not verified, the remaining constraints are not computed, +# the objective is set to infinity and the evaluation is not counted. +# NOTE: For library mode, the countEval flag is an output argument of the eval_x function. + + +# PROBLEM PARAMETERS +#################### + +# Number of variables +DIMENSION 10 + +# Black box +BB_EXE bb_cnt_eval.exe +BB_OUTPUT_TYPE CNT_EVAL OBJ PB PB # CNT_EVAL is for the flag passed from the bb to Nomad + +# Starting point +X0 ( 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 ) + +# Bounds are useful to avoid extreme values +LOWER_BOUND * -20.0 +UPPER_BOUND * 20.0 + + +# ALGORITHM PARAMETERS +###################### + +# The algorithm terminates after that number black-box evaluations +MAX_BB_EVAL 100 + +# Formatted stats into a file +STATS_FILE stats.txt BBE SOL BBO + +DISPLAY_ALL_EVAL yes + + + diff --git a/examples/advanced/batch/DiscoMads/CMakeLists.txt b/examples/advanced/batch/DiscoMads/CMakeLists.txt index 41c65320..31c8f640 100644 --- a/examples/advanced/batch/DiscoMads/CMakeLists.txt +++ b/examples/advanced/batch/DiscoMads/CMakeLists.txt @@ -6,11 +6,4 @@ set_target_properties(bb_disco.exe PROPERTIES SUFFIX "") install(TARGETS bb_disco.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add a test for this example -if(BUILD_TESTS MATCHES ON) - message(STATUS " Add example batch DiscoMads") - # Test run in working directory AFTER install of bb executable - add_test(NAME ExampleAdvancedBatchDiscoMadsDiscont - COMMAND ${CMAKE_INSTALL_PREFIX}/bin/nomad paramEscapeDiscont.txt - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) -endif() +# No test for this example diff --git a/examples/advanced/batch/DiscoMads/paramEscapeDiscont.txt b/examples/advanced/batch/DiscoMads/paramEscapeDiscont.txt index 31e43889..f8e6bff2 100644 --- a/examples/advanced/batch/DiscoMads/paramEscapeDiscont.txt +++ b/examples/advanced/batch/DiscoMads/paramEscapeDiscont.txt @@ -66,7 +66,6 @@ DISCO_MADS_REVEALING_POLL_NB_POINTS 2 # defaut= problem dimension # RECOMMENDED PARAMETERS FOR DISCOMADS ###################### -NB_THREADS_OPENMP 1 # DiscoMads works with OpenMP but has not been extensively tested # Quadratic model: desactivated as they may be slow with DiscoMads QUAD_MODEL_SEARCH false diff --git a/examples/advanced/batch/DiscoMads/paramEscapeHiddenConstraints.txt b/examples/advanced/batch/DiscoMads/paramEscapeHiddenConstraints.txt new file mode 100644 index 00000000..b81502a9 --- /dev/null +++ b/examples/advanced/batch/DiscoMads/paramEscapeHiddenConstraints.txt @@ -0,0 +1,85 @@ +## Run DiscoMads to reveal and escape hidden constraints regions + + +# The problem is described sec. 5.3 "5.3. Design of a styrene production process." of [1] and more detailled +# in section 2.5.4, p.61 of [2]. + +# IMPORTANT : The blackbox used is Styrene, run in hybrid library/batch mode. +# The styrene standalone executable is registered with "BB_EXE truth.exe" +# To run this optimization, this file must be executed in a path where styrene truth.exe executable is available. +# Styrene sources are available at https://github.com/bbopt/styrene and must be compiled prior to run this optimization. + +# [1] Escaping Unknown Discontinuous Regions in Blackbox Optimization +# Charles Audet, Alain Batailly, and Solène Kojtych, SIAM Journal on Optimization, 2022 +# doi/10.1137/21M1420915 +# [2] Contributions à l'optimisation de systèmes mécaniques non réguliers : reconception +# d'aubes de compresseur +# Solène Kojtych, Ph.D. thesis 2022 +# doi/10.1137/21M1420915 +#################### + + +# PROBLEM PARAMETERS +#################### + +# Number of variables +DIMENSION 8 + +# Black box +BB_EXE truth.exe + +# BB output (-R indicates a revealing output) +BB_OUTPUT_TYPE EB EB EB EB PB PB PB PB PB PB PB OBJ-R +# Only revealing output are considered to reveal hidden constraints with DiscoMads + +# Starting point +X0 ( 100 87.82280202 95.36797348 0 0 49.04338841 42.41599794 41.01732603 ) + +LOWER_BOUND * 0 +UPPER_BOUND * 100 + +# GENERAL ALGORITHM PARAMETERS +###################### + +# The algorithm terminates after that number black-box evaluations +# or when min mesh size is reached +MAX_BB_EVAL 1000 +MIN_MESH_SIZE * 1E-7 + +# Parameters for display degree +DISPLAY_DEGREE 2 +DISPLAY_ALL_EVAL true +DISPLAY_STATS BBE OBJ + + +# DISCOMADS PARAMETERS +###################### +DISCO_MADS_OPTIMIZATION true +DISCO_MADS_HID_CONST true # escape hidden constraints instead of discontinuities + +# Remoteness to hidden constraints wished +DISCO_MADS_EXCLUSION_RADIUS 15 + +# Revealing poll +DISCO_MADS_REVEALING_POLL_RADIUS 20 +DISCO_MADS_REVEALING_POLL_NB_POINTS 8 # default= problem dimension + + +# RECOMMENDED PARAMETERS FOR DISCOMADS +###################### + +# Quadratic model: desactivated as they may be slow with DiscoMads +QUAD_MODEL_SEARCH false +EVAL_QUEUE_SORT DIR_LAST_SUCCESS +DIRECTION_TYPE ORTHO 2N + +#INITIAL_FRAME_SIZE * 5.05 + +# SPECIFIC THESIS PARAMETERS USED IN [2] +###################### +## Uncomment the following parameters to reproduce the thesis parameters +#DIRECTION_TYPE ORTHO N+1 NEG # comment previous "DIRECTION_TYPE" command +#SEED 3698370 +#ANISOTROPIC_MESH false +#NM_SEARCH false +#SPECULATIVE_SEARCH true \ No newline at end of file diff --git a/examples/advanced/batch/FixedVariable/CMakeLists.txt b/examples/advanced/batch/FixedVariable/CMakeLists.txt index cbc42840..5c1d7145 100644 --- a/examples/advanced/batch/FixedVariable/CMakeLists.txt +++ b/examples/advanced/batch/FixedVariable/CMakeLists.txt @@ -6,20 +6,4 @@ set_target_properties(uu.exe PROPERTIES SUFFIX "") install(TARGETS uu.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add a test for this example -if(BUILD_TESTS MATCHES ON) - - message(STATUS " Add example batch fixed variables") - # Test run in working directory AFTER install of bb executable - - if (WIN32) - add_test(NAME ExampleAdvancedBatchFixedVariables - COMMAND bash.exe runFixedWin.sh ${CMAKE_INSTALL_PREFIX} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - # Temp comment - #else() - # add_test(NAME ExampleAdvancedBatchFixedVariables - # COMMAND ./runFixed.sh ${CMAKE_INSTALL_PREFIX} - # WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - endif() -endif() +# No test for this example \ No newline at end of file diff --git a/examples/advanced/batch/FixedVariable/param.txt b/examples/advanced/batch/FixedVariable/param.txt index a755b5b7..d073d45a 100644 --- a/examples/advanced/batch/FixedVariable/param.txt +++ b/examples/advanced/batch/FixedVariable/param.txt @@ -21,6 +21,7 @@ UPPER_BOUND * 31.0 MAX_BB_EVAL 1000 # Parameters for display degree +#DISPLAY_HEADER 0 DISPLAY_DEGREE 2 DISPLAY_ALL_EVAL true DISPLAY_INFEASIBLE true @@ -35,6 +36,14 @@ DISPLAY_STATS BBE ( SOL ) OBJ BB_OUTPUT_TYPE PB OBJ ADD_SEED_TO_FILE_NAMES false +EVAL_OPPORTUNISTIC true +H_MAX_0 200000 FIXED_VARIABLE 0-2 +#NB_THREADS_OPENMP 8 + +HOT_RESTART_ON_USER_INTERRUPT false +HOT_RESTART_READ_FILES false +HOT_RESTART_WRITE_FILES false CACHE_FILE cache.txt +REJECT_UNKNOWN_PARAMETERS false diff --git a/examples/advanced/batch/FixedVariable/param10.txt b/examples/advanced/batch/FixedVariable/param10.txt index a9b5cada..a921e5a0 100644 --- a/examples/advanced/batch/FixedVariable/param10.txt +++ b/examples/advanced/batch/FixedVariable/param10.txt @@ -36,4 +36,13 @@ DISPLAY_STATS BBE ( MESH_SIZE ) ( POLL_SIZE ) ( SOL ) OBJ CONS_H BB_OUTPUT_TYPE PB OBJ ADD_SEED_TO_FILE_NAMES false +EVAL_OPPORTUNISTIC true +H_MAX_0 200000 + +#NB_THREADS_OPENMP 8 + +HOT_RESTART_ON_USER_INTERRUPT false +HOT_RESTART_READ_FILES false +HOT_RESTART_WRITE_FILES false CACHE_FILE cache.txt +REJECT_UNKNOWN_PARAMETERS false diff --git a/examples/advanced/batch/FixedVariable/param2.txt b/examples/advanced/batch/FixedVariable/param2.txt index 782df556..60d75a48 100644 --- a/examples/advanced/batch/FixedVariable/param2.txt +++ b/examples/advanced/batch/FixedVariable/param2.txt @@ -36,6 +36,14 @@ DISPLAY_STATS BBE ( MESH_SIZE ) ( POLL_SIZE ) ( SOL ) OBJ BB_OUTPUT_TYPE PB OBJ ADD_SEED_TO_FILE_NAMES false +EVAL_OPPORTUNISTIC true +H_MAX_0 200000 FIXED_VARIABLE 2-3 +#NB_THREADS_OPENMP 8 + +HOT_RESTART_ON_USER_INTERRUPT false +HOT_RESTART_READ_FILES false +HOT_RESTART_WRITE_FILES false CACHE_FILE cache.txt +REJECT_UNKNOWN_PARAMETERS false diff --git a/examples/advanced/batch/FixedVariable/param3.txt b/examples/advanced/batch/FixedVariable/param3.txt index 83f066f0..8c68c2ba 100644 --- a/examples/advanced/batch/FixedVariable/param3.txt +++ b/examples/advanced/batch/FixedVariable/param3.txt @@ -36,6 +36,14 @@ DISPLAY_STATS BBE ( MESH_SIZE ) ( POLL_SIZE ) ( SOL ) OBJ BB_OUTPUT_TYPE PB OBJ ADD_SEED_TO_FILE_NAMES false +EVAL_OPPORTUNISTIC true +H_MAX_0 200000 FIXED_VARIABLE 3-4 +#NB_THREADS_OPENMP 8 + +HOT_RESTART_ON_USER_INTERRUPT false +HOT_RESTART_READ_FILES false +HOT_RESTART_WRITE_FILES false CACHE_FILE cache.txt +REJECT_UNKNOWN_PARAMETERS false diff --git a/examples/advanced/batch/FixedVariable/runFixed.sh b/examples/advanced/batch/FixedVariable/runFixed.sh index 8aa88a81..039ff3cf 100755 --- a/examples/advanced/batch/FixedVariable/runFixed.sh +++ b/examples/advanced/batch/FixedVariable/runFixed.sh @@ -1,3 +1,4 @@ +#!/bin/bash #Batch executable to run a problem using a series of fixed values. # Argument #1: path to Nomad install dir diff --git a/examples/advanced/batch/FixedVariable/runFixedWin.sh b/examples/advanced/batch/FixedVariable/runFixedWin.sh index 5abd30b5..ac27a4e2 100644 --- a/examples/advanced/batch/FixedVariable/runFixedWin.sh +++ b/examples/advanced/batch/FixedVariable/runFixedWin.sh @@ -1,21 +1,21 @@ #Batch executable to run a problem using a series of fixed values. -# Argument #1: path to Nomad install dir +nomad_exe=$1 rm -f cache.txt # Fix 0-2 echo "Fix 0-2" -%1\bin\nomad.exe param1.txt +$nomad_exe param1.txt echo "Cache size: "; wc -l cache.txt # Fix 2-3 echo "Fix 2-3" -%1\bin\nomad.exe param2.txt +$nomad_exe param2.txt echo "Cache size: "; wc -l cache.txt # Fix 3-4 echo "Fix 3-4" -%1\bin\nomad.exe param3.txt +$nomad_exe param3.txt echo "Cache size: "; wc -l cache.txt # Fix nothing echo "Fix nothing" -%1\bin\nomad.exe param10.txt +$nomad_exe param10.txt echo "Cache size: "; wc -l cache.txt diff --git a/examples/advanced/batch/IBEX/README.txt b/examples/advanced/batch/IBEX/README.txt index 8a691f4d..03602a47 100644 --- a/examples/advanced/batch/IBEX/README.txt +++ b/examples/advanced/batch/IBEX/README.txt @@ -6,6 +6,4 @@ Then, you have to use the files "create_set" or "create_set_with_volume" to crea However, if you don't want to create the Set, you can only provide the system file name thanks to the attribute SYSTEM_FILE_NAME and the Set will be created automatically in NOMAD. The argument SET_FILE (bool) defines if you already created the Set or if you only want to pass the system file. -Two different use of NOMAD with IBEX are available. You can either call the Set in the BB file and project directly in the this file (see bb.cpp) or you can project the point in NOMAD, and in this case you give the informations needed thanks to the param.txt file, such as explained above. - -IMPORTANT: Modify the path to IBEX in bb.cpp before building the example +Two differents use of NOMAD with IBEX are available. You can either call the Set in the BB file and project directly in the this file (see bb.cpp) or you can project the point in NOMAD, and in this case you give the informations needed thanks to the param.txt file, such as explained above. diff --git a/examples/advanced/batch/IBEX/bb.cpp b/examples/advanced/batch/IBEX/bb.cpp index ae39bc4f..f2a66e75 100644 --- a/examples/advanced/batch/IBEX/bb.cpp +++ b/examples/advanced/batch/IBEX/bb.cpp @@ -44,13 +44,58 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ - +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ #include #include #include #include #include -#include "/home/User/MyName/ibex-2.8.9/__build__/ibex.h" // IMPORTANT: Modify the path before building +#include "/home/expert/Bureau/ibex-2.8.9/__build__/ibex.h" using namespace std; using namespace ibex; diff --git a/examples/advanced/batch/LHonly/CMakeLists.txt b/examples/advanced/batch/LHonly/CMakeLists.txt index 0fee1089..252f96f0 100644 --- a/examples/advanced/batch/LHonly/CMakeLists.txt +++ b/examples/advanced/batch/LHonly/CMakeLists.txt @@ -6,13 +6,4 @@ set_target_properties(u.exe PROPERTIES SUFFIX "") install(TARGETS u.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add a test for this example -if(BUILD_TESTS MATCHES ON) - message(STATUS " Add example batch LHOnly") - - # Test run in working directory AFTER install of bb executable - add_test(NAME ExampleAdvancedBatchLHOnly - COMMAND ${CMAKE_INSTALL_PREFIX}/bin/nomad param.txt - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) -endif() +# No test for this example diff --git a/examples/advanced/batch/PSDMadsWithPythonBB/param.txt b/examples/advanced/batch/PSDMadsWithPythonBB/param.txt index a82b5096..c455ea51 100755 --- a/examples/advanced/batch/PSDMadsWithPythonBB/param.txt +++ b/examples/advanced/batch/PSDMadsWithPythonBB/param.txt @@ -1,7 +1,3 @@ -# NOTE: Nomad executable needs openMP support -# for this example to work - - DIMENSION 50 BB_EXE '$python3 bb.py ' @@ -16,7 +12,7 @@ UPPER_BOUND * 10 MAX_BB_EVAL 10000 PSD_MADS_OPTIMIZATION yes -NB_THREADS_OPENMP 4 +NB_THREADS_PARALLEL_EVAL 4 DISPLAY_DEGREE 2 DISPLAY_STATS BBE ( SOL ) OBJ diff --git a/examples/advanced/batch/SuggestAndObserve/CMakeLists.txt b/examples/advanced/batch/SuggestAndObserve/CMakeLists.txt index 063df455..016caae5 100644 --- a/examples/advanced/batch/SuggestAndObserve/CMakeLists.txt +++ b/examples/advanced/batch/SuggestAndObserve/CMakeLists.txt @@ -23,19 +23,4 @@ endif() install(TARGETS suggest.exe observe.exe bbr.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add a test for this example -if(BUILD_TESTS MATCHES ON) - - message(STATUS " Add example batch suggest and observe") - # Test run in working directory AFTER install of bb executable - - if (WIN32) - add_test(NAME ExampleAdvancedBatchSuggestAndObserve - COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./loopSuggestAndObserve.sh - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - else() - add_test(NAME ExampleAdvancedBatchSuggestAndObserve - COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./loopSuggestAndObserve.sh - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - endif() -endif() +# No test for this example diff --git a/examples/advanced/batch/SuggestAndObserve/bbr.cpp b/examples/advanced/batch/SuggestAndObserve/bbr.cpp index b759a51f..8d991b28 100644 --- a/examples/advanced/batch/SuggestAndObserve/bbr.cpp +++ b/examples/advanced/batch/SuggestAndObserve/bbr.cpp @@ -54,7 +54,7 @@ #define DIMENSION 2 -bool eval_xs(const std::vector> &xs, std::vector& fxs) +bool eval_xs(const std::vector > &xs, std::vector& fxs) { bool eval_ok = false; @@ -90,13 +90,13 @@ bool eval_xs(const std::vector> &xs, std::vector& fx } -std::vector> readXFile(const std::string& xFileName) +std::vector > readXFile(const std::string& xFileName) { - std::vector> xs; + std::vector > xs; std::ifstream in(xFileName); // Get the input points - while (!in.eof()) + while (!in.eof() && in.good()) { std::vector x(DIMENSION); for (size_t i = 0; i < DIMENSION; i++) @@ -106,6 +106,7 @@ std::vector> readXFile(const std::string& xFileName) xs.push_back(x); } in.close(); + xs.pop_back(); return xs; diff --git a/examples/advanced/batch/SuggestAndObserve/utils.cpp b/examples/advanced/batch/SuggestAndObserve/utils.cpp index a22bfd2c..49d6530f 100644 --- a/examples/advanced/batch/SuggestAndObserve/utils.cpp +++ b/examples/advanced/batch/SuggestAndObserve/utils.cpp @@ -77,9 +77,9 @@ void readXFile(const std::string& xFileName, NOMAD::ArrayOfPoint &aop) readXFile(xFileName, xs); aop.clear(); - for (auto x : xs) + for (const auto& x : xs) { - aop.push_back(NOMAD::Point(x)); + aop.emplace_back(x); } } @@ -94,19 +94,18 @@ void initParams(std::shared_ptr& params, params->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(DIMENSION, 10.0)); NOMAD::BBOutputTypeList bbot; // Definition of output types - bbot.push_back(NOMAD::BBOutputType::OBJ); + bbot.emplace_back(NOMAD::BBOutputType::OBJ); params->setAttributeValue("BB_OUTPUT_TYPE", bbot); - params->setAttributeValue("CACHE_FILE", cacheFileName); - for (auto paramAsString : additionalParams) + for (const auto& paramAsString : additionalParams) { params->readParamLine(paramAsString); } // Display parameters - params->setAttributeValue("DISPLAY_DEGREE", 0); + //params->setAttributeValue("DISPLAY_DEGREE", 4); // parameters validation params->getPbParams()->doNotShowWarnings(); diff --git a/examples/advanced/batch/UseCacheFileForRerun/CMakeLists.txt b/examples/advanced/batch/UseCacheFileForRerun/CMakeLists.txt index b8ec4a2e..3bc4fc3a 100644 --- a/examples/advanced/batch/UseCacheFileForRerun/CMakeLists.txt +++ b/examples/advanced/batch/UseCacheFileForRerun/CMakeLists.txt @@ -6,10 +6,4 @@ set_target_properties(bb_cache.exe PROPERTIES SUFFIX "") install(TARGETS bb_cache.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add a test for this example -# message(STATUS " Add example batch for using cache file for rerun") - -# Test run in working directory AFTER install of bb_cache.exe executable -# add_test(NAME ExampleAdvancedBatchCacheFileForRerun -# COMMAND ${CMAKE_INSTALL_PREFIX}/bin/nomad param.txt -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) +# No test for this example diff --git a/examples/advanced/library/COOPMads/CMakeLists.txt b/examples/advanced/library/COOPMads/CMakeLists.txt new file mode 100644 index 00000000..2fcc98c7 --- /dev/null +++ b/examples/advanced/library/COOPMads/CMakeLists.txt @@ -0,0 +1,31 @@ +# Example only for OPENMP build + +add_executable(rosenbrockCoop.exe rosenbrockCoop.cpp ) + +target_include_directories(rosenbrockCoop.exe PRIVATE + ${CMAKE_SOURCE_DIR}/src) + +set_target_properties(rosenbrockCoop.exe PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" SUFFIX "") + +target_link_libraries(rosenbrockCoop.exe PUBLIC nomadAlgos nomadUtils nomadEval OpenMP::OpenMP_CXX) + +# installing executables and libraries +install(TARGETS rosenbrockCoop.exe + RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) + + +# Add a test for this example +message(STATUS " Add example test for COOPMads") + +if (WIN32) + add_test(NAME ExampleAdvancedCOOPMads + COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./rosenbrockCoop.exe + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +else() + add_test(NAME ExampleAdvancedCOOPMads + COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./rosenbrockCoop.exe + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +endif() + diff --git a/examples/basic/batch/single_obj/bb.cpp b/examples/advanced/library/COOPMads/rosenbrockCoop.cpp similarity index 54% rename from examples/basic/batch/single_obj/bb.cpp rename to examples/advanced/library/COOPMads/rosenbrockCoop.cpp index 1f2ece8b..0b50c00b 100644 --- a/examples/basic/batch/single_obj/bb.cpp +++ b/examples/advanced/library/COOPMads/rosenbrockCoop.cpp @@ -44,35 +44,121 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#include -#include -#include -#include -#include -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 ); +/*--------------------------------------------*/ +/* Rosenbrock with dimension greater than 2 */ +/*--------------------------------------------*/ +#include "Nomad/nomad.hpp" +#include "Type/DirectionType.hpp" +#include "Type/EvalSortType.hpp" + +const size_t N = 20; + +/*----------------------------------------*/ +/* The problem */ +/*----------------------------------------*/ +class My_Evaluator : public NOMAD::Evaluator +{ +private: + +public: + explicit My_Evaluator(const std::shared_ptr& evalParams) + : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) + {} + + ~My_Evaluator() override = default; + + bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; +}; + + +/*----------------------------------------*/ +/* user-defined eval_x */ +/*----------------------------------------*/ +bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, + const NOMAD::Double &hMax, + bool &countEval) const +{ + + if (N%2 != 0) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Dimension N should be an even number"); + } + + double f=0; + for ( size_t i = 1 ; i <= N/2 ; ++i ) { + f += pow ( 10 * (x[2*i-1].todouble() - pow(x[2*i-2].todouble(),2) ) , 2 ); + f += pow ( 1 - x[2*i-2].todouble() , 2 ); + } + x.setBBO(std::to_string(f)); + + countEval = true; // count a black-box evaluation + + return true; // the evaluation succeeded +} + + +void initAllParams(std::shared_ptr allParams) +{ + // Parameters creation + allParams->setAttributeValue("DIMENSION", N); + // 100 black-box evaluations + allParams->setAttributeValue("MAX_BB_EVAL", 400*N); + + + // Starting point + allParams->setAttributeValue("X0", NOMAD::Point(N, 0.5) ); + + // Bounds + allParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(N, -10.0 )); + allParams->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(N, 10.0 )); + + allParams->setAttributeValue("COOP_MADS_OPTIMIZATION",true); + allParams->setAttributeValue("COOP_MADS_NB_PROBLEM", 5); + allParams->setAttributeValue("COOP_MADS_OPTIMIZATION_CACHE_SEARCH",true); + + allParams->setAttributeValue("DIRECTION_TYPE",NOMAD::DirectionType::ORTHO_2N); + + // Constraints and objective + NOMAD::BBOutputTypeList bbOutputTypes = {NOMAD::BBOutputType::OBJ}; + allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); + + allParams->setAttributeValue("DISPLAY_DEGREE", 2); + + NOMAD::ArrayOfString ds("BBE ( SOL ) OBJ"); + allParams->setAttributeValue("DISPLAY_STATS", ds); + + // Parameters validation + allParams->checkAndComply(); + +} + + +/*------------------------------------------*/ +/* NOMAD main function */ +/*------------------------------------------*/ +int main() +{ + NOMAD::MainStep TheMainStep; + + auto params = std::make_shared(); + initAllParams(params); + TheMainStep.setAllParameters(params); + + // Custom Evaluator + auto ev = std::make_unique(params->getEvalParams()); + TheMainStep.addEvaluator(std::move(ev)); + + try + { + TheMainStep.start(); + TheMainStep.run(); + TheMainStep.end(); } - f = x[4]; - if ( in.fail() ) - f = c1 = c2 = 1e20; - else { - c1 = c1 - 25; - c2 = 25 - c2; + + catch(std::exception &e) + { + std::cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; } - in.close(); - } - cout << f << " " << c1 << " " << c2 << endl; - return 0; + + return 0; } diff --git a/examples/advanced/library/CustomCompForOrdering/CMakeLists.txt b/examples/advanced/library/CustomCompForOrdering/CMakeLists.txt index 908d4935..004724aa 100644 --- a/examples/advanced/library/CustomCompForOrdering/CMakeLists.txt +++ b/examples/advanced/library/CustomCompForOrdering/CMakeLists.txt @@ -17,19 +17,4 @@ install(TARGETS customCompForOrdering.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add test for this example -#if(BUILD_TESTS MATCHES ON) -# message(STATUS " Add example test for custom ordering of points before evaluation") -# # Can run this test after install -# if (WIN32) -# add_test(NAME ExampleAdvancedcustomCompForOrdering -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./customCompForOrdering.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# else() -# add_test(NAME ExampleAdvancedcustomCompForOrdering -# COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./customCompForOrdering.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# endif() -#endif() +# No test for this example \ No newline at end of file diff --git a/examples/advanced/library/CustomCompForOrdering/customCompForOrdering.cpp b/examples/advanced/library/CustomCompForOrdering/customCompForOrdering.cpp index 898602e7..35effc23 100644 --- a/examples/advanced/library/CustomCompForOrdering/customCompForOrdering.cpp +++ b/examples/advanced/library/CustomCompForOrdering/customCompForOrdering.cpp @@ -46,7 +46,9 @@ /*---------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ /* Example of a program that uses a custom comparison (2 elements) for */ -/* ordering trial points before evaluation */ +/* ordering trial points before evaluation. */ +/* The rank of points is established in the completeTrialPointsInformation */ +/* and comp functions. */ /*--------------------------------------------------------------------------*/ #include "Nomad/nomad.hpp" #include "Algos/EvcInterface.hpp" @@ -63,11 +65,11 @@ class My_Evaluator : public NOMAD::Evaluator private: public: - My_Evaluator(const std::shared_ptr& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; }; @@ -99,11 +101,11 @@ bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, return true; // the evaluation succeeded } -void initAllParams(std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { // Parameters creation allParams->setAttributeValue("DIMENSION", n); - + // Starting point allParams->setAttributeValue("X0", NOMAD::Point(n, 0.0) ); @@ -117,15 +119,19 @@ void initAllParams(std::shared_ptr allParams) // Constraints and objective NOMAD::BBOutputTypeList bbOutputTypes; - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::OBJ); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::PB); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::OBJ); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::PB); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::PB); allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); + allParams->setAttributeValue("MAX_BB_EVAL", 200); + + allParams->setAttributeValue("QUAD_MODEL_SEARCH", false); + allParams->setAttributeValue("DISPLAY_DEGREE", 2); allParams->setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("bbe ( sol ) obj")); allParams->setAttributeValue("DISPLAY_ALL_EVAL", true); - + // Parameters validation requested to have access to their value. allParams->checkAndComply(); @@ -136,52 +142,73 @@ void initAllParams(std::shared_ptr allParams) // The closer to 0, the lower the priority. class CustomOrder : public NOMAD::ComparePriorityMethod { + // The evaluation point tags are unique. Let's use + // them as map key. The value for ordering is the + // second element of the map, the distance to P0. + std::map _valByTags; public: bool comp(NOMAD::EvalQueuePointPtr& p1, NOMAD::EvalQueuePointPtr& p2) const override { bool lowerPriority = false; + auto itP1 = _valByTags.find(p1->getTag()); + auto itP2 = _valByTags.find(p2->getTag()); + if (itP1 != _valByTags.end() && itP2 != _valByTags.end()) + { + lowerPriority = (itP1->second < itP2->second); + } + + return lowerPriority; + + } + + + void completeTrialPointsInformation(const NOMAD::Step *step, NOMAD::EvalPointSet & trialPoints) override + { NOMAD::Point P0(n, 0); - NOMAD::Double d1 = NOMAD::Point::dist(P0, *(p1.get())); - NOMAD::Double d2 = NOMAD::Point::dist(P0, *(p2.get())); - if (d1 < d2) + _valByTags.clear(); + + // We could std::copy_if but it is not worth it. Clarity is better. + for ( const auto & evalQueuePoint : trialPoints) { - lowerPriority = true; + // Let use a reference point to compute a distance. + // The distance is used in comp function to order the points. + auto tag = evalQueuePoint.getTag(); + NOMAD::Double d1 = NOMAD::Point::dist(P0, evalQueuePoint); + _valByTags.insert(std::pair(tag,d1)); } - return lowerPriority; } }; - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) +int main() { - - NOMAD::MainStep TheMainStep; - + // Set parameters auto params = std::make_shared(); initAllParams(params); TheMainStep.setAllParameters(params); - + // Custom Evaluator creation auto ev = std::make_unique(params->getEvalParams()); TheMainStep.addEvaluator(std::move(ev)); - + + // The run + TheMainStep.start(); + // Define new sort function and sort according to that function + // Must be done after main step start. auto customOrder = std::make_shared(); NOMAD::EvcInterface::getEvaluatorControl()->setUserCompMethod(customOrder); - // The run - TheMainStep.start(); TheMainStep.run(); TheMainStep.end(); - - return 1; + + return 0; } diff --git a/examples/advanced/library/CustomOpportunistic/CMakeLists.txt b/examples/advanced/library/CustomOpportunistic/CMakeLists.txt index e2dd2eba..904e719d 100644 --- a/examples/advanced/library/CustomOpportunistic/CMakeLists.txt +++ b/examples/advanced/library/CustomOpportunistic/CMakeLists.txt @@ -17,19 +17,4 @@ install(TARGETS customOpport.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add test for this example -#if(BUILD_TESTS MATCHES ON) -# message(STATUS " Add example test for custom opportunism") -# # Can run this test after install -# if (WIN32) -# add_test(NAME ExampleAdvancedCustomOpport -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./customOpport.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# else() -# add_test(NAME ExampleAdvancedCustomOpport -# COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./customOpport.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# endif() -#endif() +# No test for this example \ No newline at end of file diff --git a/examples/advanced/library/CustomOpportunistic/customOpport.cpp b/examples/advanced/library/CustomOpportunistic/customOpport.cpp index 4160dedf..03d9409e 100644 --- a/examples/advanced/library/CustomOpportunistic/customOpport.cpp +++ b/examples/advanced/library/CustomOpportunistic/customOpport.cpp @@ -45,7 +45,6 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ - /*--------------------------------------------------------------------------*/ /* Example of a program that makes NOMAD do a local opportunistic stop */ /* of queued evaluations from a Poll step when a user criterion is met */ @@ -64,6 +63,9 @@ // for custom opportunistic stop of step NOMAD::Double currentBestFeasF; +// Default F and H compute type used for custom oppportunistic stop +NOMAD::FHComputeType computeType = NOMAD::defaultFHComputeType; + /*----------------------------------------*/ /* The problem */ /*----------------------------------------*/ @@ -74,11 +76,11 @@ class My_Evaluator : public NOMAD::Evaluator private: public: - My_Evaluator(const std::shared_ptr& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; }; @@ -91,7 +93,6 @@ bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const { - if (N%2 != 0) { throw NOMAD::Exception(__FILE__,__LINE__,"Dimension N should be an even number"); @@ -102,16 +103,16 @@ bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, f += pow ( 10 * (x[2*i-1].todouble() - pow(x[2*i-2].todouble(),2) ) , 2 ); f += pow ( 1 - x[2*i-2].todouble() , 2 ); } - x.setBBO(std::to_string(f)); + NOMAD::Double F(f); + x.setBBO(F.tostring()); countEval = true; return true; // the evaluation succeeded } -void initAllParams( std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { - // Parameters creation allParams->setAttributeValue("DIMENSION", N); // 100 black-box evaluations @@ -125,14 +126,14 @@ void initAllParams( std::shared_ptr allParams) // Constraints and objective NOMAD::BBOutputTypeList bbOutputTypes; - bbOutputTypes.push_back(NOMAD::BBOutputType::OBJ); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::OBJ); allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); allParams->setAttributeValue("DISPLAY_DEGREE", 3); allParams->setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("bbe ( sol ) obj")); allParams->setAttributeValue("DISPLAY_ALL_EVAL", true); - // Opportunistic eval must be activated (rem: activated by default!). Let us sort with a poor sorting strategy (quadratic model is much better). Default criterion for opportunism is disabled and replaced by a custom opportunistic criterion provided by a user callback (see below). + // Opportunistic eval must be activated (rem: activated by default!). Let us sort with a poor sorting strategy (quadratic model is much better than lexicographical). Default criterion for opportunism is disabled and replaced by a custom opportunistic criterion provided by a user callback (see below). allParams->setAttributeValue("EVAL_OPPORTUNISTIC", true); allParams->setAttributeValue("EVAL_QUEUE_SORT",NOMAD::EvalSortType::LEXICOGRAPHICAL); @@ -144,7 +145,6 @@ void initAllParams( std::shared_ptr allParams) // Parameters validation allParams->checkAndComply(); - } @@ -158,39 +158,38 @@ void customEvalCB(NOMAD::EvalQueuePointPtr & evalQueuePoint, bool &opportunistic if (NOMAD::EvalType::BB == evalQueuePoint->getEvalType() ) { // Consider only feasible points - if (evalQueuePoint->isFeasible(NOMAD::EvalType::BB)) + if (evalQueuePoint->isFeasible(computeType)) { // Update my current best feasible point if (!currentBestFeasF.isDefined()) { - currentBestFeasF = evalQueuePoint->getF(NOMAD::EvalType::BB); + currentBestFeasF = evalQueuePoint->getF(computeType); return; } auto mystep = evalQueuePoint->getGenStep(); // Opportunism only if enough reduction is obtained (optim f is 0) - auto FMinOpport = currentBestFeasF - 0.01*currentBestFeasF.abs(); + auto FMinOpport = currentBestFeasF - 0.1*currentBestFeasF.abs(); if (NOMAD::stepTypeToString(mystep).find("Poll") != string::npos && - evalQueuePoint->getF(NOMAD::EvalType::BB) < FMinOpport) + evalQueuePoint->getF(computeType) < FMinOpport) { opportunisticEvalStop=true; std::cout<<"*****************************************************"<< std::endl; std::cout<<"Opportunistic stop in Poll on f sufficient decrease. "<< std::endl; std::cout<<"*****************************************************"<< std::endl; - currentBestFeasF = evalQueuePoint->getF(NOMAD::EvalType::BB); + currentBestFeasF = evalQueuePoint->getF(computeType); } } } } - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) +int main() { NOMAD::MainStep TheMainStep; @@ -213,5 +212,5 @@ int main ( int argc , char ** argv ) TheMainStep.run(); TheMainStep.end(); - return 1; + return 0; } diff --git a/examples/advanced/library/CustomPollMethod/CMakeLists.txt b/examples/advanced/library/CustomPollMethod/CMakeLists.txt new file mode 100644 index 00000000..aa9373e0 --- /dev/null +++ b/examples/advanced/library/CustomPollMethod/CMakeLists.txt @@ -0,0 +1,20 @@ +add_executable(customPollMethod.exe customPollMethod.cpp ) + +target_include_directories(customPollMethod.exe PRIVATE + ${CMAKE_SOURCE_DIR}/src) + +set_target_properties(customPollMethod.exe PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" SUFFIX "") + + +if(OpenMP_CXX_FOUND) + target_link_libraries(customPollMethod.exe PUBLIC nomadAlgos nomadUtils nomadEval OpenMP::OpenMP_CXX) +else() + target_link_libraries(customPollMethod.exe PUBLIC nomadAlgos nomadUtils nomadEval) +endif() + +# installing executables and libraries +install(TARGETS customPollMethod.exe + RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) + + +# No test for this example diff --git a/examples/advanced/library/CustomPollMethod/customPollMethod.cpp b/examples/advanced/library/CustomPollMethod/customPollMethod.cpp new file mode 100644 index 00000000..fbdaf3c1 --- /dev/null +++ b/examples/advanced/library/CustomPollMethod/customPollMethod.cpp @@ -0,0 +1,293 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------*/ +/* Example of a program that makes NOMAD do a Mads custom/user poll in */ +/* addition to the Ortho 2n poll method. */ +/*--------------------------------------------------------------------------*/ +#include "Nomad/nomad.hpp" +#include "Algos/EvcInterface.hpp" +#include "Algos/Mads/Mads.hpp" +#include "Algos/Mads/MadsMegaIteration.hpp" +#include "Algos/Mads/SearchMethodAlgo.hpp" +#include "Algos/SubproblemManager.hpp" +#include "Cache/CacheBase.hpp" +#include "Type/EvalSortType.hpp" +#include "Algos/AlgoStopReasons.hpp" +#include "Util/AllStopReasons.hpp" +#include "Math/MatrixUtils.hpp" + +/*----------------------------------------*/ +/* The problem */ +/*----------------------------------------*/ +const int N=6; + +class My_Evaluator : public NOMAD::Evaluator +{ +private: + +public: + explicit My_Evaluator(const std::shared_ptr& evalParams) + : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) + {} + + ~My_Evaluator() override = default; + + bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; +}; + + +/*----------------------------------------*/ +/* user-defined eval_x */ +/*----------------------------------------*/ +bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, + const NOMAD::Double &hMax, + bool &countEval) const +{ + if (N%2 != 0) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Dimension N should be an even number"); + } + double f=0; + for ( size_t i = 1 ; i <= N/2 ; ++i ) { + f += pow ( 10 * (x[2*i-1].todouble() - pow(x[2*i-2].todouble(),2) ) , 2 ); + f += pow ( 1 - x[2*i-2].todouble() , 2 ); + } + NOMAD::Double F(f); + x.setBBO(F.tostring()); + countEval = true; + + return true; // the evaluation succeeded +} + + +void initAllParams(const std::shared_ptr& allParams) +{ + // Parameters creation + allParams->setAttributeValue("DIMENSION", N); + + // black-box evaluations + allParams->setAttributeValue("MAX_BB_EVAL", 400*N); + + // Starting point + allParams->setAttributeValue("X0", NOMAD::Point(N, 0.0) ); + + // Bounds + allParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(N, -10.0)); + allParams->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(N, 10.0)); + + // Constraints and objective + NOMAD::BBOutputTypeList bbOutputTypes; + bbOutputTypes.emplace_back(NOMAD::BBOutputType::OBJ); + allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes); + + // NOTE: USER_POLL directions can be combined with other direction type or not. + NOMAD::DirectionTypeList dtList = {NOMAD::DirectionType::USER_POLL, NOMAD::DirectionType::ORTHO_2N}; + + allParams->setAttributeValue("DIRECTION_TYPE",dtList); + + allParams->setAttributeValue("QUAD_MODEL_SEARCH", false); // Disable QMS and NM for clarity of the display + allParams->setAttributeValue("NM_SEARCH", false); + + // Display + allParams->setAttributeValue("DISPLAY_DEGREE", 3); + allParams->setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("bbe ( sol ) obj")); + + // Parameters validation + allParams->checkAndComply(); + +} + +// The function to generate QRMads user poll directions. This is registered as a callback below. +bool userQRPollMethodCallback(const NOMAD::Step& step, std::list & dirs, const size_t n) +{ + // Important: by default USER_CALLS are disabled when doing quad model optimization + // -> NO call to this function when doing quad model search. + + auto mads = dynamic_cast(step.getRootAlgorithm()); + if (nullptr == mads) + { + throw NOMAD::Exception(__FILE__,__LINE__,"No Mads available."); + } + // Access to the current poll method frame center + auto callingPoll = dynamic_cast(&step); + if (nullptr == callingPoll) + { + throw NOMAD::Exception(__FILE__,__LINE__,"No poll method available."); + } + auto frameCenter = callingPoll->getFrameCenter(); + + // Let's work on the Mads pb. Remark: Mads does not see the fixed variables. + auto pbParams = mads->getPbParams(); + + // Pb parameters + auto nPb = pbParams->getAttributeValue("DIMENSION"); + if (nPb != n) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Dimension pb."); + } + + // Mesh delta frame size is used to scale the proposed search direction + auto mesh = step.getIterationMesh(); + if (nullptr == mesh) + { + throw NOMAD::Exception(__FILE__,__LINE__,"No mesh available."); + } + // Box size has the dimension of the Mads problem. + NOMAD::ArrayOfDouble boxSize = mesh->getDeltaFrameSize(); + + dirs.clear(); + NOMAD::Direction dirUnit(n, 0.0); + NOMAD::Direction::computeDirOnUnitSphere(dirUnit); + + while (dirUnit[0] == 0) + { + NOMAD::Direction::computeDirOnUnitSphere(dirUnit); + } + + // Matrix M + auto ** M = new double*[n]; + for (size_t i = 0; i < n; ++i) + { + M[i] = new double [n]; + M[i][0] = dirUnit[i].todouble(); + for (size_t j = 1; j < n; ++j) + { + M[i][j] = (i == j)? 1.0:0.0; + } + } + + // std::cout << "M matrix for QR:" <(n),static_cast(n)); + + if ( !success || !error_msg.empty()) + { + std::cerr << "QR decomposition for QR 2N poll method has failed" << std::endl; + return false; + } + + // std::cout << "Direction after QR decomposition: " << std::endl; + // Ordering D_k alternates Qk and -Qk instead of [Q_k -Q_k] + NOMAD::Direction dir(n); + for (size_t i = 0; i < n; ++i) + { + for (size_t j = 0; j < n; ++j) + { + dir[j] = Q[j][i]; + } + + dirs.push_back(dir); + dirs.push_back(-dir); + } + + // Delete M, Q and R: + for ( size_t i = 0 ; i < n ; ++i ) + { + delete [] M[i]; + delete [] Q[i]; + delete [] R[i]; + } + delete [] Q; + delete [] R; + delete [] M; + + return true; +} + +/*------------------------------------------*/ +/* NOMAD main function */ +/*------------------------------------------*/ +int main() +{ + NOMAD::MainStep TheMainStep; + + // Set parameters + auto params = std::make_shared(); + initAllParams(params); + TheMainStep.setAllParameters(params); + + // Custom Evaluator + std::unique_ptr ev(new My_Evaluator(params->getEvalParams())); + TheMainStep.setEvaluator(std::move(ev)); + + // Main step start initializes Mads (default algorithm) + TheMainStep.start(); + + // Registering the callback function to generate Mads user poll trial points via poll directions. + // The user poll also requires to set DIRECTION_TYPE USER_POLL (see above) + auto mads = std::dynamic_pointer_cast(TheMainStep.getAlgo(NOMAD::StepType::ALGORITHM_MADS)); + if (nullptr == mads) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot access to Mads algorithm"); + } + mads->addCallback(NOMAD::CallbackType::USER_METHOD_POLL, userQRPollMethodCallback); + + TheMainStep.run(); + TheMainStep.end(); + + return 0; +} diff --git a/examples/advanced/library/CustomSearchMethod/CMakeLists.txt b/examples/advanced/library/CustomSearchMethod/CMakeLists.txt new file mode 100644 index 00000000..e20ed203 --- /dev/null +++ b/examples/advanced/library/CustomSearchMethod/CMakeLists.txt @@ -0,0 +1,20 @@ +add_executable(customSearchMethod.exe customSearchMethod.cpp ) + +target_include_directories(customSearchMethod.exe PRIVATE + ${CMAKE_SOURCE_DIR}/src) + +set_target_properties(customSearchMethod.exe PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" SUFFIX "") + + +if(OpenMP_CXX_FOUND) + target_link_libraries(customSearchMethod.exe PUBLIC nomadAlgos nomadUtils nomadEval OpenMP::OpenMP_CXX) +else() + target_link_libraries(customSearchMethod.exe PUBLIC nomadAlgos nomadUtils nomadEval) +endif() + +# installing executables and libraries +install(TARGETS customSearchMethod.exe + RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) + + +# No test for this example diff --git a/examples/advanced/library/CustomSearchMethod/customSearchMethod.cpp b/examples/advanced/library/CustomSearchMethod/customSearchMethod.cpp new file mode 100644 index 00000000..e2b6b693 --- /dev/null +++ b/examples/advanced/library/CustomSearchMethod/customSearchMethod.cpp @@ -0,0 +1,233 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------*/ +/* Example of a program that makes NOMAD do a Mads custom user search in */ +/* addition to the default search. */ +/*--------------------------------------------------------------------------*/ +#include "Nomad/nomad.hpp" +#include "Algos/EvcInterface.hpp" +#include "Algos/Mads/Mads.hpp" +#include "Algos/Mads/MadsMegaIteration.hpp" +#include "Algos/Mads/SearchMethodAlgo.hpp" +#include "Algos/SubproblemManager.hpp" +#include "Cache/CacheBase.hpp" +#include "Type/EvalSortType.hpp" +#include "Algos/AlgoStopReasons.hpp" +#include "Util/AllStopReasons.hpp" + +/*----------------------------------------*/ +/* The problem */ +/*----------------------------------------*/ +const int N=6; + +class My_Evaluator : public NOMAD::Evaluator +{ +private: + +public: + explicit My_Evaluator(const std::shared_ptr& evalParams) + : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) + {} + + ~My_Evaluator() override = default; + + bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; +}; + + +/*----------------------------------------*/ +/* user-defined eval_x */ +/*----------------------------------------*/ +bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, + const NOMAD::Double &hMax, + bool &countEval) const +{ + + if (N%2 != 0) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Dimension N should be an even number"); + } + + double f=0; + for ( size_t i = 1 ; i <= N/2 ; ++i ) { + f += pow ( 10 * (x[2*i-1].todouble() - pow(x[2*i-2].todouble(),2) ) , 2 ); + f += pow ( 1 - x[2*i-2].todouble() , 2 ); + } + NOMAD::Double F(f); + x.setBBO(F.tostring()); + countEval = true; + + return true; // the evaluation succeeded +} + + +void initAllParams(const std::shared_ptr& allParams) +{ + // Parameters creation + allParams->setAttributeValue("DIMENSION", N); + // 100 black-box evaluations + allParams->setAttributeValue("MAX_BB_EVAL", 50*N); + // Starting point + allParams->setAttributeValue("X0", NOMAD::Point(N, 0.0) ); + + // Bounds + allParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(N, -10.0)); + allParams->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(N, 10.0)); + + // Constraints and objective + NOMAD::BBOutputTypeList bbOutputTypes; + bbOutputTypes.emplace_back(NOMAD::BBOutputType::OBJ); + allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); + + // Algo + allParams->setAttributeValue("DIRECTION_TYPE",NOMAD::DirectionType::ORTHO_2N); + allParams->setAttributeValue("QUAD_MODEL_SEARCH", false); + allParams->setAttributeValue("NM_SEARCH", false); + + // Enable the user search method. See below for registering the callback function + // to generate the search directions. Both are required. + allParams->setAttributeValue("USER_SEARCH", true); + + // Display + allParams->setAttributeValue("DISPLAY_DEGREE", 3); + allParams->setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("bbe ( sol ) obj")); + allParams->setAttributeValue("DISPLAY_ALL_EVAL", true); + + // Parameters validation + allParams->checkAndComply(); +} + +// The function to generate user search directions. This is registered as a callback below. +bool userSearchMethodCallback(const NOMAD::Step& step, NOMAD::EvalPointSet & trialPoints) +{ + // Important: by default USER_CALLS are disabled when doing quad model optimization + // -> NO call to this function when doing quad model search. + + auto mads = dynamic_cast(step.getRootAlgorithm()); + if (nullptr == mads) + { + throw NOMAD::Exception(__FILE__,__LINE__,"No Mads available."); + } + auto barrier = mads->getMegaIterationBarrier(); + if (nullptr == barrier) + { + throw NOMAD::Exception(__FILE__,__LINE__,"No barrier available."); + } + auto frameCenter = barrier->getFirstPoint(); + + // Let's work on the Mads pb. + auto pbParams = mads->getPbParams(); + + // Pb parameters + auto n = pbParams->getAttributeValue("DIMENSION"); + + // Mesh delta frame size is used to scale the proposed search direction + auto mesh = step.getIterationMesh(); + if (nullptr == mesh) + { + throw NOMAD::Exception(__FILE__,__LINE__,"No mesh available."); + } + // Frame size of the mesh + NOMAD::ArrayOfDouble frameSize = mesh->getDeltaFrameSize(); + + // Let's try a random direction larger than the mesh frame size. + NOMAD::Direction dir(n,0.0); + + // Compute unit sphere direction + NOMAD::Direction::computeDirOnUnitSphere(dir); + + for (size_t i = 0 ; i < n ; i++) + { + // Let's explore beyond the frame size + dir[i] *= frameSize[i]*2.0; // Note: resulting pt is projected on the bounds and on the mesh if required. + } + + trialPoints.clear(); + + // insert the trial point in the trial point set + NOMAD::EvalPoint ep(*frameCenter->getX() + dir); + ep.setPointFrom(frameCenter, NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(&step)); + trialPoints.insert(ep); + + return true; +} + + +/*------------------------------------------*/ +/* NOMAD main function */ +/*------------------------------------------*/ +int main() +{ + NOMAD::MainStep TheMainStep; + + // Set parameters + auto params = std::make_shared(); + initAllParams(params); + TheMainStep.setAllParameters(params); + + // Custom Evaluator + std::unique_ptr ev(new My_Evaluator(params->getEvalParams())); + TheMainStep.setEvaluator(std::move(ev)); + + // Main step start initializes Mads (default algorithm) + TheMainStep.start(); + + // Registering the callback function to generate Mads user search trial points + // Setting USER_SEARCH yes is also required (see above) + auto mads = std::dynamic_pointer_cast(TheMainStep.getAlgo(NOMAD::StepType::ALGORITHM_MADS)); + if (nullptr == mads) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot access to Mads algorithm"); + } + mads->addCallback(NOMAD::CallbackType::USER_METHOD_SEARCH, userSearchMethodCallback); + + TheMainStep.run(); + TheMainStep.end(); + + return 0; +} diff --git a/examples/advanced/library/CustomStatSum/CMakeLists.txt b/examples/advanced/library/CustomStatSum/CMakeLists.txt index 135af970..7d9bebbc 100644 --- a/examples/advanced/library/CustomStatSum/CMakeLists.txt +++ b/examples/advanced/library/CustomStatSum/CMakeLists.txt @@ -17,19 +17,4 @@ install(TARGETS customStatSum.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add test for this example -#if(BUILD_TESTS MATCHES ON) -# message(STATUS " Add example test for stop on stat sum criterion") -# # Can run this test after install -# if (WIN32) -# add_test(NAME ExampleAdvancedcustomStatSum -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./customStatSum.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# else() -# add_test(NAME ExampleAdvancedcustomStatSum -# COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./customStatSum.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# endif() -#endif() +# No test for this example \ No newline at end of file diff --git a/examples/advanced/library/CustomStatSum/customStatSum.cpp b/examples/advanced/library/CustomStatSum/customStatSum.cpp index 4aada090..880c5a95 100644 --- a/examples/advanced/library/CustomStatSum/customStatSum.cpp +++ b/examples/advanced/library/CustomStatSum/customStatSum.cpp @@ -59,7 +59,7 @@ #include "Util/AllStopReasons.hpp" -// User stats used for stoping optimization +// User stats used for stopping optimization /* This feature is implemented in Nomad 3 as STAT_SUM and STAT_SUM_TARGET Nomad 4 has more flexibility by using user evaluation callbacks */ @@ -76,11 +76,11 @@ class My_Evaluator : public NOMAD::Evaluator private: public: - My_Evaluator(const std::shared_ptr& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; }; @@ -120,9 +120,8 @@ bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, return true; // the evaluation succeeded } -void initAllParams(std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { - const size_t n = 5; // Parameters creation @@ -140,11 +139,11 @@ void initAllParams(std::shared_ptr allParams) allParams->setAttributeValue("UPPER_BOUND", ub); // Constraints and objective - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::OBJ); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::EB); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::EB); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::BBO_UNDEFINED); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::BBO_UNDEFINED); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::OBJ); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::EB); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::EB); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::BBO_UNDEFINED); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::BBO_UNDEFINED); allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); allParams->setAttributeValue("DISPLAY_DEGREE", 2); @@ -155,7 +154,6 @@ void initAllParams(std::shared_ptr allParams) // Parameters validation requested to have access to their value. allParams->checkAndComply(); - } @@ -163,7 +161,7 @@ void initAllParams(std::shared_ptr allParams) /* After each evaluation compute user stats on extra outputs and check on */ /* user stat stopping criterion */ /*------------------------------------------------------------------------*/ -void customEvalStopCB( NOMAD::EvalQueuePointPtr & evalQueuePoint, bool & globalStop) +void customEvalStopCB(NOMAD::EvalQueuePointPtr& evalQueuePoint, bool& globalStop) { globalStop = false; if (nullptr != evalQueuePoint) @@ -187,14 +185,11 @@ void customEvalStopCB( NOMAD::EvalQueuePointPtr & evalQueuePoint, bool & globalS } - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) +int main() { - - NOMAD::MainStep TheMainStep; // Set parameters @@ -212,11 +207,10 @@ int main ( int argc , char ** argv ) // Add callback function for eval check and stop management. NOMAD::EvcInterface::getEvaluatorControl()->addEvalCallback(cbFailCheck); - // The run TheMainStep.start(); TheMainStep.run(); TheMainStep.end(); - return 1; + return 0; } diff --git a/examples/advanced/library/DiscoMads/EscapeDiscontinuities/CMakeLists.txt b/examples/advanced/library/DiscoMads/EscapeDiscontinuities/CMakeLists.txt index ec33b151..b5a9adcd 100644 --- a/examples/advanced/library/DiscoMads/EscapeDiscontinuities/CMakeLists.txt +++ b/examples/advanced/library/DiscoMads/EscapeDiscontinuities/CMakeLists.txt @@ -16,18 +16,4 @@ endif() install(TARGETS DiscoMadsEscapeDiscont.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add a test for this example -if(BUILD_TESTS MATCHES ON) - message(STATUS " Add example DiscoMadsEscapeDiscont library #1") - -# Can run this test after install - if (WIN32) - add_test(NAME ExampleDiscoMadsEscapeDiscontLib - COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./DiscoMadsEscapeDiscont.exe - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - else() - add_test(NAME ExampleDiscoMadsEscapeDiscontLib - COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./DiscoMadsEscapeDiscont.exe - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - endif() -endif() +# No test for this example diff --git a/examples/advanced/library/DiscoMads/EscapeDiscontinuities/DiscoMadsEscapeDiscont.cpp b/examples/advanced/library/DiscoMads/EscapeDiscontinuities/DiscoMadsEscapeDiscont.cpp index a2c20cb2..5c05f10b 100644 --- a/examples/advanced/library/DiscoMads/EscapeDiscontinuities/DiscoMadsEscapeDiscont.cpp +++ b/examples/advanced/library/DiscoMads/EscapeDiscontinuities/DiscoMadsEscapeDiscont.cpp @@ -54,7 +54,7 @@ /*----------------------------------------*/ /* The problem */ /*----------------------------------------*/ -// The problem is described sec. 5.1 "Results of a typical run" of [1] and more detailled +// The problem is described sec. 5.1 "Results of a typical run" of [1] and more detailed // following eq. 2.52, p.53 in [2]. // [1] Escaping Unknown Discontinuous Regions in Blackbox Optimization @@ -65,21 +65,19 @@ // Solène Kojtych, Ph.D. thesis 2022 // doi/10.1137/21M1420915 - class My_Evaluator : public NOMAD::Evaluator { public: - My_Evaluator(const std::shared_ptr& evalParams, NOMAD::EvalType evalType) + explicit My_Evaluator(const std::shared_ptr& evalParams, NOMAD::EvalType evalType) : NOMAD::Evaluator(evalParams, evalType) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double& hMax, bool &countEval) const override { - bool eval_ok = false; - NOMAD::Double f = 1e+20, c1 = 1e+20; - size_t n = x.size(); + bool eval_ok = false; + NOMAD::Double f = 1e+20, c1 = 1e+20; try { @@ -124,8 +122,6 @@ class My_Evaluator : public NOMAD::Evaluator }; - - void initParams(NOMAD::AllParameters &p) { // parameters creation @@ -166,15 +162,12 @@ void initParams(NOMAD::AllParameters &p) p.setAttributeValue("DISCO_MADS_REVEALING_POLL_NB_POINTS", n); // ------- Recommended parameters for DiscoMads - // no parallelism - p.setAttributeValue("NB_THREADS_OPENMP",1); // DiscoMads works with OpenMP but has not been extensively tested - // quad models are desactivated as they may be slow with DiscoMads + // quad models are deactivated as they may be slow with DiscoMads p.getRunParams()->setAttributeValue("QUAD_MODEL_SEARCH", false); p.getRunParams()->setAttributeValue("DIRECTION_TYPE", NOMAD::DirectionType::ORTHO_2N); p.getEvaluatorControlParams()->setAttributeValue("EVAL_QUEUE_SORT",NOMAD::EvalSortType::DIR_LAST_SUCCESS); - // ------- Specific thesis parameters // Uncomment the following parameters to reproduce the thesis parameters //p.set_SEED(3698370); @@ -183,7 +176,6 @@ void initParams(NOMAD::AllParameters &p) //p.getRunParams()->setAttributeValue("NM_SEARCH", false); //p.setAttributeValue("SPECULATIVE_SEARCH", true); - // parameters validation p.checkAndComply(); } @@ -191,7 +183,7 @@ void initParams(NOMAD::AllParameters &p) /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main (int argc, char **argv) +int main() { auto TheMainStep = std::make_unique(); diff --git a/examples/advanced/library/DiscoMads/EscapeHiddenConstraints/CMakeLists.txt b/examples/advanced/library/DiscoMads/EscapeHiddenConstraints/CMakeLists.txt index 4154a909..ca3d2303 100644 --- a/examples/advanced/library/DiscoMads/EscapeHiddenConstraints/CMakeLists.txt +++ b/examples/advanced/library/DiscoMads/EscapeHiddenConstraints/CMakeLists.txt @@ -16,18 +16,4 @@ endif() install(TARGETS DiscoMadsEscapeHiddenConstraints.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# # Add a test for this example -# if(BUILD_TESTS MATCHES ON) -# message(STATUS " Add example DiscoMads library #1") - -# # Can run this test after install -# if (WIN32) -# add_test(NAME ExampleDiscoMadsLib -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./DiscoMadsEscapeHiddenConstraints.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) -# else() -# add_test(NAME ExampleDiscoMadsLib -# COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./DiscoMadsEscapeHiddenConstraints.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) -# endif() -# endif() +# No test for this example \ No newline at end of file diff --git a/examples/advanced/library/DiscoMads/EscapeHiddenConstraints/DiscoMadsEscapeHiddenConstraints.cpp b/examples/advanced/library/DiscoMads/EscapeHiddenConstraints/DiscoMadsEscapeHiddenConstraints.cpp index 356e3078..af48a7cd 100644 --- a/examples/advanced/library/DiscoMads/EscapeHiddenConstraints/DiscoMadsEscapeHiddenConstraints.cpp +++ b/examples/advanced/library/DiscoMads/EscapeHiddenConstraints/DiscoMadsEscapeHiddenConstraints.cpp @@ -58,7 +58,7 @@ #include "Util/AllStopReasons.hpp" // # The problem is described sec. 5.3 "5.3. Design of a styrene production process." -// of [1] and more detailled in section 2.5.4, p.61 of [2]. +// of [1] and more detailed in section 2.5.4, p.61 of [2]. // // IMPORTANT // @@ -76,7 +76,7 @@ // Solène Kojtych, Ph.D. thesis 2022 // doi/10.1137/21M1420915 -void initAllParams( std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { const int n = 8; @@ -120,8 +120,6 @@ void initAllParams( std::shared_ptr allParams) allParams->setAttributeValue("DISCO_MADS_REVEALING_POLL_NB_POINTS", n); // ------- Recommended parameters for DiscoMads - // no parallelism - allParams->setAttributeValue("NB_THREADS_OPENMP",1); // DiscoMads works with OpenMP but has not been extensively tested // quad models are desactivated as they may be slow with DiscoMads allParams->getRunParams()->setAttributeValue("QUAD_MODEL_SEARCH", false); @@ -143,14 +141,11 @@ void initAllParams( std::shared_ptr allParams) } - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) +int main() { - - NOMAD::MainStep TheMainStep; // Set parameters @@ -171,5 +166,5 @@ int main ( int argc , char ** argv ) std::cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; } - return 1; + return 0; } diff --git a/examples/advanced/library/FixedVariable/.gitignore b/examples/advanced/library/FixedVariable/.gitignore index b9bdc5aa..ef60df2b 100644 --- a/examples/advanced/library/FixedVariable/.gitignore +++ b/examples/advanced/library/FixedVariable/.gitignore @@ -1,3 +1,4 @@ +nomadtmp.* *.o *.exe cache.txt diff --git a/examples/advanced/library/FixedVariable/CMakeLists.txt b/examples/advanced/library/FixedVariable/CMakeLists.txt index 1b1cadc7..afb29e1b 100644 --- a/examples/advanced/library/FixedVariable/CMakeLists.txt +++ b/examples/advanced/library/FixedVariable/CMakeLists.txt @@ -19,19 +19,16 @@ install(TARGETS fixedVariable.exe ufl.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) # Add a test for this example -if(BUILD_TESTS MATCHES ON) - message(STATUS " Add example test for fixed variables") - # Can run this test after install +message(STATUS " Add example for fixed variables") - if (WIN32) - add_test(NAME ExampleAdvancedFixedVariables +if (WIN32) + add_test(NAME ExampleAdvancedFixedVariables COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./fixedVariable.exe WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - else() - add_test(NAME ExampleAdvancedFixedVariables +else() + add_test(NAME ExampleAdvancedFixedVariables COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./fixedVariable.exe WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - endif() endif() diff --git a/examples/advanced/library/FixedVariable/fixedVariable.cpp b/examples/advanced/library/FixedVariable/fixedVariable.cpp index ea9073fe..63213930 100644 --- a/examples/advanced/library/FixedVariable/fixedVariable.cpp +++ b/examples/advanced/library/FixedVariable/fixedVariable.cpp @@ -51,8 +51,6 @@ #include "Eval/Evaluator.hpp" #include "Param/AllParameters.hpp" - - void initParams1(NOMAD::AllParameters &p) { // parameters creation @@ -165,7 +163,7 @@ void initParamsFinal(NOMAD::AllParameters &p, const NOMAD::Point& x0) /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main (int argc, char **argv) +int main() { auto TheMainStep = std::make_unique(); @@ -174,6 +172,11 @@ int main (int argc, char **argv) auto params = std::make_shared(); initParams1(*params); TheMainStep->setAllParameters(params); + + auto computeTypeS = NOMAD::ComputeType::STANDARD; + auto hNormType = params->getAttributeValue("H_NORM"); + auto evalType = NOMAD::EvalType::BB; + NOMAD::FHComputeType computeType = {evalType, {computeTypeS, hNormType}}; try { @@ -195,8 +198,9 @@ int main (int argc, char **argv) NOMAD::CacheBase::getInstance()->resetNbCacheHits(); NOMAD::EvcInterface::getEvaluatorControl()->setNbEval(0); std::vector bestFeasList; - NOMAD::CacheBase::getInstance()->findBestFeas(bestFeasList, NOMAD::Point(), - NOMAD::EvalType::BB, NOMAD::ComputeType::STANDARD); + + + NOMAD::CacheBase::getInstance()->findBestFeas(bestFeasList, NOMAD::Point(), computeType); // NB. Assuming the list is non-empty. NOMAD::Point x02 = *(bestFeasList[0].getX()); initParams2(*params, x02); @@ -214,8 +218,7 @@ int main (int argc, char **argv) // Part 3: FIXED_VARIABLE 3-4 NOMAD::CacheBase::getInstance()->resetNbCacheHits(); NOMAD::EvcInterface::getEvaluatorControl()->setNbEval(0); - NOMAD::CacheBase::getInstance()->findBestFeas(bestFeasList, NOMAD::Point(), - NOMAD::EvalType::BB, NOMAD::ComputeType::STANDARD); + NOMAD::CacheBase::getInstance()->findBestFeas(bestFeasList, NOMAD::Point(), computeType); NOMAD::Point x03 = *(bestFeasList[0].getX()); initParams3(*params , x03); try @@ -230,8 +233,7 @@ int main (int argc, char **argv) } // Final part: No fixed variable - NOMAD::CacheBase::getInstance()->findBestFeas(bestFeasList, NOMAD::Point(), - NOMAD::EvalType::BB, NOMAD::ComputeType::STANDARD); + NOMAD::CacheBase::getInstance()->findBestFeas(bestFeasList, NOMAD::Point(), computeType); NOMAD::Point x0final = *(bestFeasList[0].getX()); initParamsFinal(*params,x0final); try @@ -245,6 +247,5 @@ int main (int argc, char **argv) std::cerr << "\nFinal run has been interrupted (" << e.what() << ")\n\n"; } - return 0; } diff --git a/examples/advanced/library/HandlingHiddenConstraints/CMakeLists.txt b/examples/advanced/library/HandlingHiddenConstraints/CMakeLists.txt index 05d30486..72886fbe 100644 --- a/examples/advanced/library/HandlingHiddenConstraints/CMakeLists.txt +++ b/examples/advanced/library/HandlingHiddenConstraints/CMakeLists.txt @@ -17,19 +17,4 @@ install(TARGETS handlingHiddenCons.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add test for this example -#if(BUILD_TESTS MATCHES ON) -# message(STATUS " Add example test for handling hidden constraints") -# # Can run this test after install -# if (WIN32) -# add_test(NAME ExampleAdvancedhandlingHiddenCons -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./handlingHiddenCons.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# else() -# add_test(NAME ExampleAdvancedhandlingHiddenCons -# COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./handlingHiddenCons.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# endif() -#endif() +# No test for this example \ No newline at end of file diff --git a/examples/advanced/library/HandlingHiddenConstraints/handlingHiddenCons.cpp b/examples/advanced/library/HandlingHiddenConstraints/handlingHiddenCons.cpp index 83c16540..19bde71d 100644 --- a/examples/advanced/library/HandlingHiddenConstraints/handlingHiddenCons.cpp +++ b/examples/advanced/library/HandlingHiddenConstraints/handlingHiddenCons.cpp @@ -45,8 +45,8 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ -/* example of a program that makes NOMAD do a local step stop (search) */ -/* after a user criterion */ +/* example of a program that makes NOMAD call a user call back function to */ +/* manage failed evaluations. */ /*--------------------------------------------------------------------------*/ #include "Nomad/nomad.hpp" #include "Algos/EvcInterface.hpp" @@ -65,8 +65,7 @@ // setAttributeValue("BB_EXE",xxxx) // To run this optimization, the program must be executed in a path where styrene truth executable is available. // Styrene sources are available at https://github.com/bbopt/styrene and must be compiled prior to run this optimization. - -void initAllParams( std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { const int n = 8; @@ -78,7 +77,6 @@ void initAllParams( std::shared_ptr allParams) std::vector x0 = { 54, 66, 86, 8, 29, 51, 32, 15}; allParams->setAttributeValue("X0", NOMAD::Point(x0) ); allParams->setAttributeValue("BB_EXE", std::string("./truth.exe")); - // Bounds allParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(n, 0.0 )); @@ -91,11 +89,8 @@ void initAllParams( std::shared_ptr allParams) allParams->setAttributeValue("DISPLAY_DEGREE", 2); allParams->setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("bbe ( sol ) obj")); - // Parameters validation allParams->checkAndComply(); - - } @@ -112,21 +107,18 @@ void customFailEvalCB( NOMAD::EvalQueuePointPtr & evalQueuePoint) if (! eval->isBBOutputComplete()) { eval->setBBO(std::string("1 1 1 1 1 1 1 1 1 1 1 1"), eval->getBBOutputTypeList(), true); - std::cout<<"BBoutput was incomplete. BBO is reset to be complete."<& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override { bool eval_ok = false; // Based on G2. NOMAD::Double f, c1 = 0, c2 = 0; - size_t n = x.size(); try { @@ -125,13 +124,13 @@ void initParams1(NOMAD::AllParameters &p) p.getDispParams()->setAttributeValue("DISPLAY_UNSUCCESSFUL", false); p.getDispParams()->setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("BBE ( SOL ) OBJ")); - p.getEvalParams()->setAttributeValue("BB_OUTPUT_TYPE", NOMAD::stringToBBOutputTypeList("OBJ PB PB")); p.getEvaluatorControlParams()->setAttributeValue("EVAL_OPPORTUNISTIC", false); + + // Activating NM optimization deactivates the default Mads optimization (default) p.getRunParams()->setAttributeValue("NM_OPTIMIZATION",true); - // parameters validation p.checkAndComply(); } @@ -140,7 +139,7 @@ void initParams1(NOMAD::AllParameters &p) /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main (int argc, char **argv) +int main() { auto TheMainStep = std::make_unique(); diff --git a/examples/advanced/library/NestedOptim/CMakeLists.txt b/examples/advanced/library/NestedOptim/CMakeLists.txt new file mode 100644 index 00000000..88fb7598 --- /dev/null +++ b/examples/advanced/library/NestedOptim/CMakeLists.txt @@ -0,0 +1,30 @@ + +add_executable(nestedOptim.exe nestedOptim.cpp) + +target_include_directories(nestedOptim.exe PRIVATE + ${CMAKE_SOURCE_DIR}/src) + +set_target_properties(nestedOptim.exe PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" SUFFIX "") + +target_link_libraries(nestedOptim.exe PUBLIC nomadAlgos nomadUtils nomadEval) + +# installing executables and libraries +install(TARGETS nestedOptim.exe + RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) + + +# Add a test for this example +message(STATUS " Add example for nested optimization") + +if (WIN32) + add_test(NAME ExampleAdvancedNestedMads + COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./nestedOptim.exe + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +else() + add_test(NAME ExampleAdvancedNestedMads + COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./nestedOptim.exe + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +endif() +endif() diff --git a/examples/advanced/library/NestedOptim/nestedOptim.cpp b/examples/advanced/library/NestedOptim/nestedOptim.cpp new file mode 100644 index 00000000..364dbfea --- /dev/null +++ b/examples/advanced/library/NestedOptim/nestedOptim.cpp @@ -0,0 +1,224 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +/*--------------------------------------------*/ +/* Rosenbrock with dimension greater than 2 */ +/* Inner problem has dimension 2 */ +/* Inner problem is solved with SimpleMads */ +/* Outer problem is solved with regular Mads*/ +/*--------------------------------------------*/ +#include "Nomad/nomad.hpp" +#include "Algos/SimpleMads/SimpleMads.hpp" +#include "Type/DirectionType.hpp" +#include "Type/EvalSortType.hpp" + +const size_t Nout = 10; // 10 variables outer problem, 2 additional (hidden) variables are used in the problem + +/*----------------------------------------*/ +/* The problem */ +/*----------------------------------------*/ +class My_EvaluatorOut : public NOMAD::Evaluator +{ +private: + const NOMAD::Step * _genStep; + +public: + explicit My_EvaluatorOut(const std::shared_ptr& evalParams, const NOMAD::Step * genStep ) + : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB), + _genStep(genStep) + {} + + ~My_EvaluatorOut() override = default; + + bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; +}; + + +/*----------------------------------------*/ +/* user-defined eval_x */ +/*----------------------------------------*/ +bool My_EvaluatorOut::eval_x(NOMAD::EvalPoint &x, + const NOMAD::Double &hMax, + bool &countEval) const +{ + if (Nout%2 != 0) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Dimension N should be an even number"); + } + + // + // Suboptimization on 2 variables. x (dim=10) is passed as a fixed variables to inner evaluation function + // + + // The function to evaluate an eval point. + // Outer variables ->x + std::function&)> eval_x = [&x](std::vector& allXIn) -> bool + { + for (auto & xIn: allXIn) + { + double f=0; + // outer variables (dim 10) contribution to f + for ( size_t i = 1 ; i <= Nout/2 ; ++i ) { + f += pow ( 10 * (x[2*i-1].todouble() - pow(x[2*i-2].todouble(),2) ) , 2 ); + f += pow ( 1 - x[2*i-2].todouble() , 2 ); + } + // inner variables (dim 2) contribution to f + f += pow ( 10 * (xIn[1].todouble() - pow(xIn[0].todouble(),2) ) , 2 ); + f += pow ( 1 - xIn[0].todouble() , 2 ); + + xIn.setF(f); + xIn.setH(0); + } + return true; + }; + + // Inner Sub-Pb parameters + auto pbParams = std::make_shared(); + pbParams->setAttributeValue("DIMENSION",2); + pbParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(2,-5)); // lb = (-5,-5) + pbParams->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(2,5)); // ub = (5,5) + NOMAD::ArrayOfPoint x0s{NOMAD::ArrayOfDouble(2,0)}; // A single X0 = (0,0) + pbParams->setAttributeValue("X0", x0s); + pbParams->checkAndComply(); + + // Run parameters (use default) + auto runParams = std::make_shared(); + runParams->setAttributeValue("ANISOTROPIC_MESH",false); + auto evcParams = NOMAD::EvcInterface::getEvaluatorControl()->getEvaluatorControlGlobalParams(); + runParams->checkAndComply(evcParams, pbParams); + + NOMAD::BBOutputTypeList bbot = {NOMAD::BBOutputType::Type::OBJ}; + + auto madsStopReasons = std::make_shared>(); + + // Create a simple mads to solve the inner problem on 2 dimension. + // Outer variables -> x are available as fixed parameters in the evaluation. + // Simple Mads is not opportunistic. All poll points are passed at once into eval_x. + NOMAD::SimpleMads mads(_genStep, madsStopReasons, runParams, pbParams, bbot, eval_x /* eval_x for a block of points */, 1600 /* maxEval */); + + // No need to display something at the end of the sub-optimization + mads.setEndDisplay(false); + + mads.start(); + bool runOk = mads.run(); + mads.end(); + + double f = 0; + if (!runOk) + { + std::cout << "Pb with inner mads. Let's continue. f=0." << std::endl; + } + else + { + // Get the best feas solution + f = mads.getBestSimpleSolution(true).getF().todouble(); + } + + x.setBBO(std::to_string(f)); + + countEval = true; // count a black-box evaluation + + return true; // the evaluation succeeded +} + + +void initAllParams(const std::shared_ptr& allParams) +{ + // Parameters creation + allParams->setAttributeValue("DIMENSION", Nout); + // 100 black-box evaluations + allParams->setAttributeValue("MAX_BB_EVAL", 400*Nout); + + // Starting point + allParams->setAttributeValue("X0", NOMAD::Point(Nout, 0.5) ); + + // Bounds + allParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(Nout, -10.0 )); + allParams->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(Nout, 10.0 )); + + // Constraints and objective + NOMAD::BBOutputTypeList bbOutputTypes = {NOMAD::BBOutputType::OBJ}; + allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); + + allParams->setAttributeValue("DISPLAY_DEGREE", 2); + + NOMAD::ArrayOfString ds("BBE ( SOL ) OBJ"); + allParams->setAttributeValue("DISPLAY_STATS", ds); + + // Parameters validation + allParams->checkAndComply(); +} + + +/*------------------------------------------*/ +/* NOMAD main function */ +/*------------------------------------------*/ +int main() +{ + NOMAD::MainStep TheMainStep; + + auto params = std::make_shared(); + initAllParams(params); + TheMainStep.setAllParameters(params); + + // Custom Evaluator + auto ev = std::make_unique(params->getEvalParams(), &TheMainStep); + TheMainStep.addEvaluator(std::move(ev)); + + try + { + TheMainStep.start(); + TheMainStep.run(); + TheMainStep.end(); + } + + catch(std::exception &e) + { + std::cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; + } + + return 0; +} diff --git a/examples/advanced/library/PSDMads/CMakeLists.txt b/examples/advanced/library/PSDMads/CMakeLists.txt index 60b326ab..37e90b5a 100644 --- a/examples/advanced/library/PSDMads/CMakeLists.txt +++ b/examples/advanced/library/PSDMads/CMakeLists.txt @@ -15,19 +15,17 @@ install(TARGETS rosenbrock.exe # Add a test for this example -if(BUILD_TESTS MATCHES ON) - message(STATUS " Add example test for PSDMads") - # Can run this test after install +message(STATUS " Add example test for PSDMads") - if (WIN32) - add_test(NAME ExampleAdvancedPSDMads +if (WIN32) + add_test(NAME ExampleAdvancedPSDMads COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./rosenbrock.exe WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - else() - add_test(NAME ExampleAdvancedPSDMads +else() + add_test(NAME ExampleAdvancedPSDMads COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./rosenbrock.exe WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - endif() endif() + diff --git a/examples/advanced/library/PSDMads/rosenbrock.cpp b/examples/advanced/library/PSDMads/rosenbrock.cpp index 470b9e95..1a35a68f 100644 --- a/examples/advanced/library/PSDMads/rosenbrock.cpp +++ b/examples/advanced/library/PSDMads/rosenbrock.cpp @@ -61,11 +61,11 @@ class My_Evaluator : public NOMAD::Evaluator private: public: - My_Evaluator(const std::shared_ptr& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; }; @@ -78,12 +78,11 @@ bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const { - if (N%2 != 0) { throw NOMAD::Exception(__FILE__,__LINE__,"Dimension N should be an even number"); } - + double f=0; for ( size_t i = 1 ; i <= N/2 ; ++i ) { f += pow ( 10 * (x[2*i-1].todouble() - pow(x[2*i-2].todouble(),2) ) , 2 ); @@ -97,47 +96,55 @@ bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, } -void initAllParams(std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { // Parameters creation allParams->setAttributeValue("DIMENSION", N); // 100 black-box evaluations allParams->setAttributeValue("MAX_BB_EVAL", 100*N); - - + // Starting point allParams->setAttributeValue("X0", NOMAD::Point(N, 0.5) ); // Bounds allParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(N, -10.0 )); allParams->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(N, 10.0 )); - + allParams->setAttributeValue("PSD_MADS_OPTIMIZATION",true); allParams->setAttributeValue("PSD_MADS_NB_VAR_IN_SUBPROBLEM",2); allParams->setAttributeValue("PSD_MADS_SUBPROBLEM_PERCENT_COVERAGE",NOMAD::Double(0.0)); allParams->setAttributeValue("PSD_MADS_SUBPROBLEM_MAX_BB_EVAL",10); - allParams->setAttributeValue("NB_THREADS_OPENMP",4); + + allParams->setAttributeValue("PSD_MADS_NB_SUBPROBLEM",4); + + // ChT Temp for debugging + allParams->setAttributeValue("NM_SEARCH",false); + allParams->setAttributeValue("QUAD_MODEL_SEARCH",false); + allParams->setAttributeValue("DIRECTION_TYPE",NOMAD::DirectionType::ORTHO_2N); + allParams->setAttributeValue("EVAL_QUEUE_SORT",NOMAD::EvalSortType::DIR_LAST_SUCCESS); // Constraints and objective NOMAD::BBOutputTypeList bbOutputTypes = {NOMAD::BBOutputType::OBJ}; allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); allParams->setAttributeValue("DISPLAY_DEGREE", 2); - allParams->setAttributeValue("DISPLAY_UNSUCCESSFUL",false); + + NOMAD::ArrayOfString ds("BBE ( SOL ) OBJ"); + allParams->setAttributeValue("DISPLAY_STATS", ds); + // allParams->setAttributeValue("DISPLAY_ALL_EVAL", true); + // allParams->setAttributeValue("DISPLAY_UNSUCCESSFUL",false); // allParams->setAttributeValue("STATS_FILE", NOMAD::ArrayOfString("stats.txt bbe obj")); // Parameters validation allParams->checkAndComply(); - } /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) +int main() { - NOMAD::MainStep TheMainStep; auto params = std::make_shared(); diff --git a/examples/advanced/library/PyNomad/LoopSuggestAndObserve/.gitignore b/examples/advanced/library/PyNomad/LoopSuggestAndObserve/.gitignore deleted file mode 100644 index 6575205d..00000000 --- a/examples/advanced/library/PyNomad/LoopSuggestAndObserve/.gitignore +++ /dev/null @@ -1 +0,0 @@ -cache.txt diff --git a/examples/advanced/library/PyNomad/LoopSuggestAndObserve/cache0.txt b/examples/advanced/library/PyNomad/LoopSuggestAndObserve/cache0.txt deleted file mode 100644 index 91cfb6b4..00000000 --- a/examples/advanced/library/PyNomad/LoopSuggestAndObserve/cache0.txt +++ /dev/null @@ -1,4 +0,0 @@ -BB_OUTPUT_TYPE OBJ -( -0.5 -1 1 ) EVAL_OK ( -0.5 ) -( -0.5 1 0.5 ) EVAL_OK ( 1 ) -( 0 0 1 ) EVAL_OK ( 3 ) diff --git a/examples/advanced/library/PyNomad/LoopSuggestAndObserve/runTestLoopSuggestAndObserve.py b/examples/advanced/library/PyNomad/LoopSuggestAndObserve/runTestLoopSuggestAndObserve.py deleted file mode 100644 index f0e88780..00000000 --- a/examples/advanced/library/PyNomad/LoopSuggestAndObserve/runTestLoopSuggestAndObserve.py +++ /dev/null @@ -1,85 +0,0 @@ -import PyNomad -import shutil - -def bb(x): - out =[] - for i in range(len(x)): - f =[] - f.append(sum( [ x[i][j] for j in range(len(x[i])) ] )) - # print(f) - out.append(f) - return out - - -# copy cache file -shutil.copyfile("cache0.txt","cache.txt") - -params = ["DISPLAY_DEGREE 2", "DIMENSION 3", "LOWER_BOUND ( -1 -1 -1 )", "UPPER_BOUND * 1", "BB_OUTPUT_TYPE OBJ", "CACHE_FILE cache.txt","INITIAL_FRAME_SIZE ( 1.0 1.0 1.0 )","MEGA_SEARCH_POLL yes" ] - -# Stopping criterions on bb eval and on frame size -MAX_BB_EVAL= 100 -MIN_FRAME_SIZE= 1E-4 -MAX_ITERATIONS= 10 - -nbEval= 0 -frameSize=100000 - -iteration= 0 - -for iteration in range(MAX_ITERATIONS): - - # Increment iteration counter - iteration = iteration + 1 - - if nbEval > MAX_BB_EVAL : - print("Reached max bb eval") - break - - if frameSize update parameters and cache - updatedParams = PyNomad.observe(params,candidates,evals,"cache.txt") - - # Decode bytes into string - for i in range(len(updatedParams)): - updatedParams[i] = updatedParams[i].decode('utf-8') - for i in range(len(params)): - if type(params[i]) is bytes: - params[i] = params[i].decode('utf-8') - - print("Updated parameters by observe:\n",updatedParams) - print("---------------------") - - # Replace updated params in params OR add if not present - for i in range(len(updatedParams)): - split1 = updatedParams[i].split() - found = False - for j in range(len(params)): - split2 = params[j].split() - if ( split2[0].upper() == split1[0].upper() ): - params[j] = updatedParams[i] - found = True - break; - if not found: - params.append(updatedParams[i]) - - print("Parameters for next iteration:\n",params) - print("\n") diff --git a/examples/advanced/library/PyNomad/OnlyObserve/.gitignore b/examples/advanced/library/PyNomad/OnlyObserve/.gitignore deleted file mode 100644 index 837b3093..00000000 --- a/examples/advanced/library/PyNomad/OnlyObserve/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -cache.txt -cache*.txt -!cache0.txt diff --git a/examples/advanced/library/PyNomad/OnlyObserve/cache0.txt b/examples/advanced/library/PyNomad/OnlyObserve/cache0.txt deleted file mode 100644 index 91cfb6b4..00000000 --- a/examples/advanced/library/PyNomad/OnlyObserve/cache0.txt +++ /dev/null @@ -1,4 +0,0 @@ -BB_OUTPUT_TYPE OBJ -( -0.5 -1 1 ) EVAL_OK ( -0.5 ) -( -0.5 1 0.5 ) EVAL_OK ( 1 ) -( 0 0 1 ) EVAL_OK ( 3 ) diff --git a/examples/advanced/library/PyNomad/OnlyObserve/runTestObserve.py b/examples/advanced/library/PyNomad/OnlyObserve/runTestObserve.py deleted file mode 100644 index 3a3d08cc..00000000 --- a/examples/advanced/library/PyNomad/OnlyObserve/runTestObserve.py +++ /dev/null @@ -1,23 +0,0 @@ -import PyNomad - -import shutil - -# Copy cache file -shutil.copyfile("cache0.txt","cache.txt") - -params = ["DISPLAY_DEGREE 2", "DIMENSION 3", "LOWER_BOUND ( -1 -1 -1 )", "UPPER_BOUND * 1", "MAX_BB_EVAL 100", "BB_OUTPUT_TYPE OBJ", "CACHE_FILE cache.txt","MEGA_SEARCH_POLL yes" ] - - -points=[[0.5,0,0.5]] -evals=[[-1]] - -print("Initial parameters:\n",params) - -# Observe evaluated points and update cache and parameters -updatedParams = PyNomad.observe(params,points,evals,"cache1.txt") - -# Decode bytes into string -for i in range(len(updatedParams)): - updatedParams[i] = updatedParams[i].decode('utf-8') - -print("Modified parameters:\n",updatedParams) diff --git a/examples/advanced/library/PyNomad/OnlySuggest/runTestSuggest.py b/examples/advanced/library/PyNomad/OnlySuggest/runTestSuggest.py deleted file mode 100644 index 59a1f0a9..00000000 --- a/examples/advanced/library/PyNomad/OnlySuggest/runTestSuggest.py +++ /dev/null @@ -1,23 +0,0 @@ -# import PyNomad -from PyNomad import PyNomadMainStep - -#params = ["DISPLAY_DEGREE 2", "DIMENSION 3", "LOWER_BOUND ( -1 -1 -1 )", "UPPER_BOUND * 1", "BB_OUTPUT_TYPE OBJ", "CACHE_FILE cache.txt", "MEGA_SEARCH_POLL yes" , "SEED 0"] -params = ["DISPLAY_DEGREE 2", "DIMENSION 3", "LOWER_BOUND ( -1 -1 -1 )", "UPPER_BOUND * 1", "BB_OUTPUT_TYPE OBJ", "CACHE_FILE cache.txt", "LH_EVAL 5" , "SEED 0"] - -#candidates = PyNomad.suggest(params) -mainstep = PyNomadMainStep(params) - -candidates = mainstep.suggest() - -print(candidates) - -# To obtain the same candidates the Random Number Generator (static) must be reset -# Otherwise, each suggest call will most likely propose different candidates -# PyNomad.resetRandomNumberGenerator() - -#candidates2 = PyNomad.suggest(params) -candidates2 = mainstep.suggest() - -print(candidates2) - -#print(PyNomad.getRNGState()) diff --git a/examples/advanced/library/PyNomad/OptimizeWithMainStep/bb.py b/examples/advanced/library/PyNomad/OptimizeWithMainStep/bb.py deleted file mode 100644 index 358c667c..00000000 --- a/examples/advanced/library/PyNomad/OptimizeWithMainStep/bb.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/python -import sys - -def bb(): - filename = sys.argv[1] - file = open(filename, 'r') - x = file.read().split() - file.close() - - dim = len(x) - x = [float(x[i]) for i in range(dim)] - - f = sum([x[i]**2 for i in range(dim)]) - print(f) - -bb() diff --git a/examples/advanced/library/PyNomad/OptimizeWithMainStep/param.txt b/examples/advanced/library/PyNomad/OptimizeWithMainStep/param.txt deleted file mode 100644 index 5e605fb7..00000000 --- a/examples/advanced/library/PyNomad/OptimizeWithMainStep/param.txt +++ /dev/null @@ -1,12 +0,0 @@ - -DISPLAY_DEGREE 2 - -DIMENSION 3 -X0 (0.71 0.51 0.51) -LOWER_BOUND ( -1 -1 -1 ) -UPPER_BOUND * 1 -MAX_BB_EVAL 100 - - -BB_EXE "$python bb.py" -BB_OUTPUT_TYPE OBJ diff --git a/examples/advanced/library/PyNomad/OptimizeWithMainStep/runTestOptimizeWithMainStep.py b/examples/advanced/library/PyNomad/OptimizeWithMainStep/runTestOptimizeWithMainStep.py deleted file mode 100644 index 2a3297d9..00000000 --- a/examples/advanced/library/PyNomad/OptimizeWithMainStep/runTestOptimizeWithMainStep.py +++ /dev/null @@ -1,8 +0,0 @@ -import PyNomad - - -params = ["DISPLAY_DEGREE 2", "DIMENSION 3", "X0 (0.71 0.51 0.51)", "LOWER_BOUND ( -1 -1 -1 )", "UPPER_BOUND * 1", "MAX_BB_EVAL 100", "BB_EXE \"$python bb.py\"" , "BB_OUTPUT_TYPE OBJ"] -# params = ["DISPLAY_DEGREE 2"] - - -PyNomad.optimizeWithMainStep(params) diff --git a/examples/advanced/library/PyNomad/OptimizeWithMainStep/x0.txt b/examples/advanced/library/PyNomad/OptimizeWithMainStep/x0.txt deleted file mode 100644 index bedc6e16..00000000 --- a/examples/advanced/library/PyNomad/OptimizeWithMainStep/x0.txt +++ /dev/null @@ -1 +0,0 @@ -0.71 0.51 0.51 diff --git a/examples/advanced/library/PyNomad/simpleExample_BlockEvalParallel.py b/examples/advanced/library/PyNomad/simpleExample_BlockEvalParallel.py new file mode 100644 index 00000000..400058bd --- /dev/null +++ b/examples/advanced/library/PyNomad/simpleExample_BlockEvalParallel.py @@ -0,0 +1,57 @@ +import PyNomad +import sys + +from asyncio import gather, run + + +# This example is for a block, i.e., a vector of EvalPoints, evaluated asynchronously. + +# Evaluation of a single point. +async def bb_single(x): + try: + dim = x.size() + f = sum([x.get_coord(i)**2 for i in range(dim)]) + except Exception as e: + print("Unexpected error in bb_single()", str(e)) + return "Inf" + return str(f) + +# The blackbox output must be put in each EvalPoint passed as argument (x.setBBO()). +async def async_bb_block(block): + nbPoints = block.size() + evals = [] + evalOk = [] + for i in range(nbPoints): + evalOk.append(False) + xs = block.get_x(i) + evals.append(bb_single(xs)) + + try: + results = await gather(*evals) + for k in range(nbPoints): + x = block.get_x(k) + x.setBBO(results[k].encode("UTF-8")) + evalOk[k] = True + except Exception as e: + print("Unexpected error in async_bb_block()", str(e)) + return 0 + return evalOk # list where 1 is success, 0 is a failed evaluation + +def sync_bb_block(block): + result = run(async_bb_block(block)) + return result + + +x0 = [0.71, 0.51, 0.51] +lb = [-1, -1, -1] +ub=[] + +params = ["BB_OUTPUT_TYPE OBJ", "MAX_BB_EVAL 100", "UPPER_BOUND * 1", "DIRECTION_TYPE ORTHO N+1 NEG"] +params += ["DISPLAY_DEGREE 2", "DISPLAY_STATS BBE BLK_SIZE OBJ", "DISPLAY_ALL_EVAL true"] +params += ["MEGA_SEARCH_POLL yes", "BB_MAX_BLOCK_SIZE 4"] + +result = PyNomad.optimize(sync_bb_block, x0, lb, ub, params) + +fmt = ["{} = {}".format(n,v) for (n,v) in result.items()] +output = "\n".join(fmt) +print("\nNOMAD results \n" + output + " \n") diff --git a/examples/advanced/library/PyNomad/simpleExample_NMOptimization.py b/examples/advanced/library/PyNomad/simpleExample_NMOptimization.py new file mode 100644 index 00000000..5a85d528 --- /dev/null +++ b/examples/advanced/library/PyNomad/simpleExample_NMOptimization.py @@ -0,0 +1,21 @@ +import PyNomad + +# This example of blackbox function is for a single process +# The blackbox output must be put in the EvalPoint passed as argument +def bb(x): + dim = x.size() + f = sum([x.get_coord(i)**2 for i in range(dim)]) + x.setBBO(str(f).encode("UTF-8")) + return 1 # 1: success 0: failed evaluation + +x0 = [0.71, 0.51, 0.51] +lb = [-1, -1, -1] +ub=[] + +params = ["BB_OUTPUT_TYPE OBJ", "MAX_BB_EVAL 100","NM_OPTIMIZATION yes", "UPPER_BOUND * 1", "DISPLAY_DEGREE 2", "DISPLAY_ALL_EVAL false", "DISPLAY_STATS BBE OBJ"] + +result = PyNomad.optimize(bb, x0, lb, ub, params) + +fmt = ["{} = {}".format(n,v) for (n,v) in result.items()] +output = "\n".join(fmt) +print("\nNOMAD results \n" + output + " \n") diff --git a/examples/advanced/library/PyNomad/simpleExample_basic_parallelEval.py b/examples/advanced/library/PyNomad/simpleExample_basic_parallelEval.py new file mode 100644 index 00000000..bd57bced --- /dev/null +++ b/examples/advanced/library/PyNomad/simpleExample_basic_parallelEval.py @@ -0,0 +1,25 @@ +import PyNomad + +# This example of blackbox function is for a single process +# The blackbox output must be put in the EvalPoint passed as argument + +# Nomad parallel bb evaluations + +def bb(x): + dim = x.size() + f = sum([x.get_coord(i)**2 for i in range(dim)]) + x.setBBO(str(f).encode("UTF-8")) + + return 1 # 1: success 0: failed evaluation + +x0 = [0.71, 0.51, 0.51] +lb = [-1, -1, -1] +ub=[] + +params = ["BB_OUTPUT_TYPE OBJ", "MAX_BB_EVAL 100", "UPPER_BOUND * 1","DIRECTION_TYPE ORTHO 2n", "DISPLAY_DEGREE 2", "DISPLAY_ALL_EVAL true", "DISPLAY_STATS THREAD_NUM BBE OBJ","NB_THREADS_PARALLEL_EVAL 4"] + +result = PyNomad.optimize(bb, x0, lb, ub, params) + +fmt = ["{} = {}".format(n,v) for (n,v) in result.items()] +output = "\n".join(fmt) +print("\nNOMAD results \n" + output + " \n") diff --git a/examples/advanced/library/Restart/CMakeLists.txt b/examples/advanced/library/Restart/CMakeLists.txt index f1781e8f..9da03f29 100644 --- a/examples/advanced/library/Restart/CMakeLists.txt +++ b/examples/advanced/library/Restart/CMakeLists.txt @@ -17,19 +17,4 @@ install(TARGETS restart.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add a test for this example -if(BUILD_TESTS MATCHES ON) - message(STATUS " Add example test for restart") - # Can run this test after install - if (WIN32) - add_test(NAME ExampleAdvancedRestart - COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./restart.exe - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - else() - add_test(NAME ExampleAdvancedRestart - COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./restart.exe - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - endif() -endif() +# No test for this example diff --git a/examples/advanced/library/Restart/restart.cpp b/examples/advanced/library/Restart/restart.cpp index 551891fb..2adba033 100644 --- a/examples/advanced/library/Restart/restart.cpp +++ b/examples/advanced/library/Restart/restart.cpp @@ -45,7 +45,7 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ -/* example of a program that makes NOMAD restarts after failed iterations */ +/* example of a program that makes NOMAD restart after failed iterations */ /*--------------------------------------------------------------------------*/ #include "Nomad/nomad.hpp" #include "Algos/EvcInterface.hpp" @@ -64,11 +64,11 @@ class My_Evaluator : public NOMAD::Evaluator private: public: - My_Evaluator(const std::shared_ptr& evalParams, NOMAD::EvalType evalType) + explicit My_Evaluator(const std::shared_ptr& evalParams, NOMAD::EvalType evalType) : NOMAD::Evaluator(evalParams, evalType) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; }; @@ -102,7 +102,7 @@ bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, } -void initAllParams(std::shared_ptr allParams, const size_t n) +void initAllParams(const std::shared_ptr& allParams, const size_t n) { // Parameters creation allParams->setAttributeValue("DIMENSION", n); @@ -121,9 +121,9 @@ void initAllParams(std::shared_ptr allParams, const size_t // Constraints and objective NOMAD::BBOutputTypeList bbOutputTypes; - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::OBJ); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::EB); // Note: pb solves easier with PB constraint. This choice is made to illustrate the custom stop and restart. - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::EB); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::OBJ); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::EB); // Note: pb solves easier with PB constraint. This choice is made to illustrate the custom stop and restart. + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::EB); allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); allParams->setAttributeValue("DISPLAY_DEGREE", 2); @@ -166,7 +166,7 @@ void userMegaIterationEnd(const NOMAD::Step& step, /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) +int main() { // Dimension (Number of variables) size_t n = 5; @@ -186,7 +186,7 @@ int main ( int argc , char ** argv ) std::vector bf; std::vector bi; - + // Main run try { @@ -203,11 +203,11 @@ int main ( int argc , char ** argv ) // New starting points NOMAD::ArrayOfPoint x0s; - if (bf.size() > 0) + if (!bf.empty()) { x0s.push_back(bf[0]); } - if (bi.size() > 0) + if (!bi.empty()) { x0s.push_back(bi[0]); } @@ -231,8 +231,8 @@ int main ( int argc , char ** argv ) bf.clear(); bi.clear(); - NOMAD::CacheBase::getInstance()->findBestFeas(bf, NOMAD::Point(n), NOMAD::EvalType::BB,NOMAD::ComputeType::STANDARD); - NOMAD::CacheBase::getInstance()->findBestInf(bi, NOMAD::INF, NOMAD::Point(n), NOMAD::EvalType::BB, NOMAD::ComputeType::STANDARD); + NOMAD::CacheBase::getInstance()->findBestFeas(bf); + NOMAD::CacheBase::getInstance()->findBestInf(bi); } } diff --git a/examples/advanced/library/Restart_VNS/CMakeLists.txt b/examples/advanced/library/Restart_VNS/CMakeLists.txt deleted file mode 100644 index e9a2a86b..00000000 --- a/examples/advanced/library/Restart_VNS/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -add_executable(restart_vns.exe restart_vns.cpp ) - -target_include_directories(restart_vns.exe PRIVATE - ${CMAKE_SOURCE_DIR}/src) - -set_target_properties(restart_vns.exe PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" SUFFIX "") - - -if(OpenMP_CXX_FOUND) - target_link_libraries(restart_vns.exe PUBLIC nomadAlgos nomadUtils nomadEval OpenMP::OpenMP_CXX) -else() - target_link_libraries(restart_vns.exe PUBLIC nomadAlgos nomadUtils nomadEval) -endif() - -# installing executables and libraries -install(TARGETS restart_vns.exe - RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) - - -# Add a test for this example -#if(BUILD_TESTS MATCHES ON) -# message(STATUS " Add example test for restart VNS") -# # Can run this test after install -# if (WIN32) -# add_test(NAME ExampleAdvancedRestart -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./restart_vns.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# else() -# add_test(NAME ExampleAdvancedRestart -# COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./restart_vns.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# endif() -#endif() diff --git a/examples/advanced/library/Restart_VNS/problems/7_WILD3/bb.cpp b/examples/advanced/library/Restart_VNS/problems/7_WILD3/bb.cpp deleted file mode 100644 index b8c538ee..00000000 --- a/examples/advanced/library/Restart_VNS/problems/7_WILD3/bb.cpp +++ /dev/null @@ -1,791 +0,0 @@ -/*---------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ -/* */ -/* NOMAD - Version 4 has been created and developed by */ -/* Viviane Rochon Montplaisir - Polytechnique Montreal */ -/* Christophe Tribes - Polytechnique Montreal */ -/* */ -/* The copyright of NOMAD - version 4 is owned by */ -/* Charles Audet - Polytechnique Montreal */ -/* Sebastien Le Digabel - Polytechnique Montreal */ -/* Viviane Rochon Montplaisir - Polytechnique Montreal */ -/* Christophe Tribes - Polytechnique Montreal */ -/* */ -/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ -/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ -/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ -/* for Data Valorization) */ -/* */ -/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ -/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ -/* and Exxon Mobil. */ -/* */ -/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ -/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ -/* Exxon Mobil. */ -/* */ -/* Contact information: */ -/* Polytechnique Montreal - GERAD */ -/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ -/* e-mail: nomad@gerad.ca */ -/* */ -/* 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 . */ -/* */ -/* You can find information on the NOMAD software at www.gerad.ca/nomad */ -/*---------------------------------------------------------------------------------*/ -#include -#include -#include -#include -#include -using namespace std; - -/*-------------*/ -/* constants */ -/*-------------*/ -const double PI = 3.141592653589793; -const double SQRT5 = sqrt(5.0); -const double SQRT10 = sqrt(10.0); -const double C13 = 13.0; -const double C14 = 14.0; -const double C29 = 29.0; -const double C45 = 45.0; -const double DINT_MAX = INT_MAX; - -const double Y1[] = { 0.14 , 0.18 , 0.22 , 0.25 , 0.29 , - 0.32 , 0.35 , 0.39 , 0.37 , 0.58 , - 0.73 , 0.96 , 1.34 , 2.10 , 4.39 }; - -const double Y2[] = { 0.1957 , 0.1947 , 0.1735 , 0.1600 , - 0.0844 , 0.0627 , 0.0456 , 0.0342 , - 0.0323 , 0.0235 , 0.0246 }; - -const double Y3[] = { 34780 , 28610 , 23650 , 19630 , - 16370 , 13720 , 11540 , 9744 , - 8261 , 7030 , 6005 , 5147 , - 4427 , 3820 , 3307 , 2872 }; - -const double Y4[] = { 0.844 , 0.908 , 0.932 , 0.936 , 0.925 , - 0.908 , 0.881 , 0.850 , 0.818 , 0.784 , - 0.751 , 0.718 , 0.685 , 0.658 , 0.628 , - 0.603 , 0.580 , 0.558 , 0.538 , 0.522 , - 0.506 , 0.490 , 0.478 , 0.467 , 0.457 , - 0.448 , 0.438 , 0.431 , 0.424 , 0.420 , - 0.414 , 0.411 , 0.406 }; - -const double Y5[] = { 1.366 , 1.191 , 1.112 , 1.013 , 0.991 , - 0.885 , 0.831 , 0.847 , 0.786 , 0.725 , - 0.746 , 0.679 , 0.608 , 0.655 , 0.616 , - 0.606 , 0.602 , 0.626 , 0.651 , 0.724 , - 0.649 , 0.649 , 0.694 , 0.644 , 0.624 , - 0.661 , 0.612 , 0.558 , 0.533 , 0.495 , - 0.500 , 0.423 , 0.395 , 0.375 , 0.372 , - 0.391 , 0.396 , 0.405 , 0.428 , 0.429 , - 0.523 , 0.562 , 0.607 , 0.653 , 0.672 , - 0.708 , 0.633 , 0.668 , 0.645 , 0.632 , - 0.591 , 0.559 , 0.597 , 0.625 , 0.739 , - 0.710 , 0.729 , 0.720 , 0.636 , 0.581 , - 0.428 , 0.292 , 0.162 , 0.098 , 0.054 }; - -const double V[] = { 4 , 2 , 1 , 0.5 , 0.25 , 0.167 , 0.125 , - 0.1 , 0.0833 , 0.0714 , 0.0625 }; - -/*-----------------------------------------*/ -/* enumeration type for the problem type */ -/*-----------------------------------------*/ -enum problem_type { - SMOOTH , // smooth - NONDIFF, // nonsmooth - WILD3 , // deterministic noise - NOISY3 // random noise -}; - -problem_type get_pb_type ( int pb_type ) { - switch ( pb_type ) { - case 1: return SMOOTH; - case 2: return NONDIFF; - case 3: return WILD3; - case 4: return NOISY3; - } - return SMOOTH; -} - -void display_pb_type ( problem_type pb_type , ostream & out ) { - switch ( pb_type ) { - case SMOOTH : out << "SMOOTH" ; break; - case NONDIFF: out << "NONDIFF"; break; - case WILD3 : out << "WILD3" ; break; - case NOISY3 : out << "NOISY3" ; break; - } -} - -/*----------------------*/ -/* get problem name */ -/*----------------------*/ -string get_problem_name ( int nprob ) { - switch ( nprob ) { - case 1: return "LINEAR_FULL"; - case 2: return "LINEAR_R1"; - case 3: return "LINEAR_R1Z"; - case 4: return "ROSENBROCK"; - case 5: return "HELICAL"; - case 6: return "POWELLSG"; - case 7: return "FREUDENSTEIN_ROTH"; - case 8: return "BARD"; - case 9: return "KOWALIK_OSBORNE"; - case 10: return "MEYER"; - case 11: return "WATSON"; - case 12: return "BOX3"; - case 13: return "JENNRICH_SAMPSON"; - case 14: return "BROWN_DENNIS"; - case 15: return "CHEBYQUAD"; - case 16: return "BROWN"; - case 17: return "OSBORNE1"; - case 18: return "OSBORNE2"; - case 19: return "BDQRTIC"; - case 20: return "CUBE"; - case 21: return "MANCINO"; - case 22: return "HEART8"; - } - return ""; -} - -/*-----------------------*/ -/* get instance data */ -/*-----------------------*/ -void get_instance_data ( int ninstance , // IN: in {1,2,...,53} - problem_type pbtype , // IN - int & nprob , // OUT - int & n , // OUT - int & m , // OUT - bool & ns ) { // OUT - switch ( ninstance ) { - case 1: nprob = 1; n = 9; m = 45; ns = 0; break; // LINEAR_FULL - case 2: nprob = 1; n = 9; m = 45; ns = 1; break; // LINEAR_FULL - case 3: nprob = 2; n = 7; m = 35; ns = 0; break; // LINEAR_R1 - case 4: nprob = 2; n = 7; m = 35; ns = 1; break; // LINEAR_R1 - case 5: nprob = 3; n = 7; m = 35; ns = 0; break; // LINEAR_R1Z - case 6: nprob = 3; n = 7; m = 35; ns = 1; break; // LINEAR_R1Z - case 7: nprob = 4; n = 2; m = 2; ns = 0; break; // ROSENBROCK - case 8: nprob = 4; n = 2; m = 2; ns = 1; break; // ROSENBROCK - case 9: nprob = 5; n = 3; m = 3; ns = 0; break; // HELICAL - case 10: nprob = 5; n = 3; m = 3; ns = 1; break; // HELICAL - case 11: nprob = 6; n = 4; m = 4; ns = 0; break; // POWELLSG - case 12: nprob = 6; n = 4; m = 4; ns = 1; break; // POWELLSG - case 13: nprob = 7; n = 2; m = 2; ns = 0; break; // FREUDENSTEIN_ROTH - case 14: nprob = 7; n = 2; m = 2; ns = 1; break; // FREUDENSTEIN_ROTH - case 15: nprob = 8; n = 3; m = 15; ns = 0; break; // BARD - case 16: nprob = 8; n = 3; m = 15; ns = 1; break; // BARD - case 17: nprob = 9; n = 4; m = 11; ns = 0; break; // KOWALIK_OSBORNE - case 18: nprob = 10; n = 3; m = 16; ns = 0; break; // MEYER - case 19: nprob = 11; n = 6; m = 31; ns = 0; break; // WATSON - case 20: nprob = 11; n = 6; m = 31; ns = 1; break; // WATSON - case 21: nprob = 11; n = 9; m = 31; ns = 0; break; // WATSON - case 22: nprob = 11; n = 9; m = 31; ns = 1; break; // WATSON - case 23: nprob = 11; n = 12; m = 31; ns = 0; break; // WATSON - case 24: nprob = 11; n = 12; m = 31; ns = 1; break; // WATSON - case 25: nprob = 12; n = 3; m = 10; ns = 0; break; // BOX3 - case 26: nprob = 13; n = 2; m = 10; ns = 0; break; // JENNRICH_SAMPSON - case 27: nprob = 14; n = 4; m = 20; ns = 0; break; // BROWN_DENNIS - case 28: nprob = 14; n = 4; m = 20; ns = 1; break; // BROWN_DENNIS - case 29: nprob = 15; n = 6; m = 6; ns = 0; break; // CHEBYQUAD - case 30: nprob = 15; n = 7; m = 7; ns = 0; break; // CHEBYQUAD - case 31: nprob = 15; n = 8; m = 8; ns = 0; break; // CHEBYQUAD - case 32: nprob = 15; n = 9; m = 9; ns = 0; break; // CHEBYQUAD - case 33: nprob = 15; n = 10; m = 10; ns = 0; break; // CHEBYQUAD - case 34: nprob = 15; n = 11; m = 11; ns = 0; break; // CHEBYQUAD - case 35: nprob = 16; n = 10; m = 10; ns = 0; break; // BROWN - case 36: nprob = 17; n = 5; m = 33; ns = 0; break; // OSBORNE1 - case 37: nprob = 18; n = 11; m = 65; ns = 0; break; // OSBORNE2 - case 38: nprob = 18; n = 11; m = 65; ns = 1; break; // OSBORNE2 - case 39: nprob = 19; n = 8; m = 8; ns = 0; break; // BDQRTIC - case 40: nprob = 19; n = 10; m = 12; ns = 0; break; // BDQRTIC - case 41: nprob = 19; n = 11; m = 14; ns = 0; break; // BDQRTIC - case 42: nprob = 19; n = 12; m = 16; ns = 0; break; // BDQRTIC - case 43: nprob = 20; n = 5; m = 5; ns = 0; break; // CUBE - case 44: nprob = 20; n = 6; m = 6; ns = 0; break; // CUBE - case 45: nprob = 20; n = 8; m = 8; ns = 0; break; // CUBE - case 46: nprob = 21; n = 5; m = 5; ns = 0; break; // MANCINO - case 47: nprob = 21; n = 5; m = 5; ns = 1; break; // MANCINO - case 48: nprob = 21; n = 8; m = 8; ns = 0; break; // MANCINO - case 49: nprob = 21; n = 10; m = 10; ns = 0; break; // MANCINO - case 50: nprob = 21; n = 12; m = 12; ns = 0; break; // MANCINO - case 51: nprob = 21; n = 12; m = 12; ns = 1; break; // MANCINO - case 52: nprob = 22; n = 8; m = 8; ns = 0; break; // HEART8 - case 53: nprob = 22; n = 8; m = 8; ns = 1; break; // HEART8 - } -} - -/*--------------------------------------------------*/ -/* dfoxs function */ -/*--------------------------------------------------*/ -/* transcripted in C++ from the matlab version */ -/* dfoxs.m of S. Wild */ -/* http://www.mcs.anl.gov/~more/dfo/matlab/dfoxs.m */ -/*--------------------------------------------------*/ -void dfoxs ( int n , // IN : dimension of problem - int nprob , // IN : problem index in {1,2,...,22} - double factor , // IN : std pt is multiplied by factor - double * x ) { // OUT: array of size n - - int i , j; - double sum , tmp; - - switch ( nprob ) { - case 1: // Linear function - full rank or rank 1 - case 2: // Linear function - full rank or rank 1 - case 3: // Linear function - full rank or rank 1 - case 8: // Bard function - case 19: // Bdqrtic - for ( i = 0 ; i < n ; ++i ) - x[i] = 1.0; - break; - case 4: // Rosenbrock function - x[0] = -1.2; - x[1] = 1.0; - break; - case 5: // Helical valley function - x[0] = -1; - for ( i = 1 ; i < n ; ++i ) - x[i] = 0.0; - break; - case 6: // Powell singular function - x[0] = 3; - x[1] = -1; - x[2] = 0; - x[3] = 1; - break; - case 7: // Freudenstein and Roth function - x[0] = 0.5; - x[1] = -2.0; - break; - case 9: // Kowalik and Osborne function - x[0] = 0.250; - x[1] = 0.390; - x[2] = 0.415; - x[3] = 0.390; - break; - case 10: // Meyer function - x[0] = .02; - x[1] = 4000; - x[2] = 250; - break; - case 11: // Watson function - case 16: // Brown almost-linear function - case 20: // Cube - for ( i = 0 ; i < n ; ++i ) - x[i] = 0.5; - break; - case 12: // Box 3-dimensional function - x[0] = 0; - x[1] = 10; - x[2] = 20; - break; - case 13: // Jennrich and Sampson function - x[0] = 0.3; - x[1] = 0.4; - break; - case 14: // Brown and Dennis function - x[0] = 25; - x[1] = 5; - x[2] = -5; - x[3] = -1; - break; - case 15: // Chebyquad function - for ( i = 1 ; i <= n ; ++i ) - x[i-1] = i/(n+1.0); - break; - case 17: // Osborne 1 function - x[0] = 0.5; - x[1] = 1.5; - x[2] = 1.0; - x[3] = 0.01; - x[4] = 0.02; - break; - case 18: // Osborne 2 function - x[ 0] = 1.3; - x[ 1] = 0.65; - x[ 2] = 0.65; - x[ 3] = 0.7; - x[ 4] = 0.6; - x[ 5] = 3.0; - x[ 6] = 5.0; - x[ 7] = 7.0; - x[ 8] = 2.0; - x[ 9] = 4.5; - x[10] = 5.5; - break; - case 21: // Mancino - for ( i = 1 ; i <= n ; ++i ) { - sum = 0; - for ( j = 1 ; j <= n ; ++j ) { - tmp = i; - tmp = sqrt(tmp/j); - sum += (tmp*( pow(sin(log(tmp)),5.0)+ pow(cos(log(tmp)),5.0))); - } - x[i-1] = -0.0008710996 * (pow(i-50,3.0) + sum); - } - break; - case 22: // Heart8 - x[0] = -0.300; - x[1] = -0.390; - x[2] = 0.300; - x[3] = -0.344; - x[4] = -1.200; - x[5] = 2.690; - x[6] = 1.590; - x[7] = -1.500; - break; - } - - for ( i = 0 ; i < n ; ++i ) - x[i] *= factor; -} - -/*---------------------------------------------------*/ -/* dfovec function */ -/*---------------------------------------------------*/ -/* transcripted in C++ from the matlab version */ -/* dfovec.m of S. Wild */ -/* http://www.mcs.anl.gov/~more/dfo/matlab/dfovec.m */ -/*---------------------------------------------------*/ -bool dfovec ( int m , // IN : number of outputs - int n , // IN : dimension of problem - const double * x , // IN : array of size n - int nprob , // IN : problem index in {1,2,...,22} - double * fvec ) { // OUT: array of size m - - int i , j; - double tmp , tmp1 , tmp2 , tmp3 , tmp4 , den , sum = 0; - - // 1. Linear function - full rank: - if ( nprob == 1 ) { - for ( j = 0 ; j < n ; ++j ) - sum += x[j]; - tmp = 2*sum/m + 1; - for ( i = 0 ; i < m ; ++i ) { - fvec[i] = -tmp; - if ( i < n ) - fvec[i] += x[i]; - } - } - - // 2. Linear function - rank 1: - else if ( nprob == 2 ) { - for ( j = 1 ; j <= n ; ++j ) - sum += j*x[j-1]; - for ( i = 1 ; i <= m ; ++i ) - fvec[i-1] = i*sum - 1; - } - - // 3. Linear function - rank 1 with zero columns and rows: - else if ( nprob == 3 ) { - for ( j = 2 ; j < n ; ++j ) - sum += j*x[j-1]; - for ( i = 0 ; i < m-1 ; ++i ) - fvec[i] = i*sum - 1; - fvec[m-1] = -1; - } - - // 4. Rosenbrock function: - else if ( nprob == 4 ) { - fvec[0] = 10*(x[1] - x[0]*x[0]); - fvec[1] = 1 - x[0]; - } - - // 5. Helical valley function: - else if ( nprob == 5 ) { - if ( x[0] > 0 ) - tmp = atan ( x[1]/x[0] ) / (2*PI); - else if ( x[0] < 0 ) - tmp = atan ( x[1]/x[0] ) / (2*PI) + .5; - else - tmp = .25; - fvec[0] = 10*(x[2] - 10*tmp); - fvec[1] = 10*(sqrt(x[0]*x[0]+x[1]*x[1])-1); - fvec[2] = x[2]; - } - - // 6. Powell singular function: - else if ( nprob == 6 ) { - fvec[0] = x[0] + 10*x[1]; - fvec[1] = SQRT5*(x[2] - x[3]); - fvec[2] = pow(x[1] - 2*x[2],2.0); - fvec[3] = SQRT10*pow(x[0] - x[3],2.0); - } - - // 7. Freudenstein and Roth function: - else if ( nprob == 7 ) { - fvec[0] = -C13 + x[0] + ((5 - x[1])*x[1] - 2)*x[1]; - fvec[1] = -C29 + x[0] + ((1 + x[1])*x[1] - C14)*x[1]; - } - - // 8. Bard function: - else if ( nprob == 8 ) { - for ( i = 1 ; i <= 15 ; ++i ) { - tmp1 = i; - tmp2 = 16-i; - tmp3 = tmp1; - if ( i > 8 ) - tmp3 = tmp2; - - den = x[1]*tmp2 + x[2]*tmp3; - - if ( den == 0 ) - return false; - - fvec[i-1] = Y1[i-1] - (x[0] + tmp1/den); - } - } - - // 9. Kowalik and Osborne function: - else if ( nprob == 9 ) { - for ( i = 0 ; i < 11 ; ++i ) { - tmp1 = V[i]*(V[i] + x[1]); - tmp2 = V[i]*(V[i] + x[2]) + x[3]; - if ( tmp2 == 0.0 ) - return false; - fvec[i] = Y2[i] - x[0]*tmp1/tmp2; - } - } - - // 10. Meyer function: - else if ( nprob == 10 ) { - for ( i = 0 ; i < 16 ; ++i ) { - den = 5*(i+1) + C45 + x[2]; - if ( den == 0 ) - return false; - fvec[i] = x[0]*exp(x[1]/den) - Y3[i]; - } - } - - // 11. Watson function: - else if ( nprob == 11 ) { - for ( i = 1 ; i <= 29 ; ++i ) { - tmp = i/C29; - tmp1 = 0; - tmp3 = 1; - for ( j = 2 ; j <= n ; ++j ) { - tmp1 += (j-1)*tmp3*x[j-1]; - tmp3 *= tmp; - } - tmp2 = 0; - tmp3 = 1; - for ( j = 1 ; j <= n ; ++j ) { - tmp2 += tmp3*x[j-1]; - tmp3 *= tmp; - } - fvec[i-1] = tmp1 - tmp2*tmp2 - 1; - } - fvec[29] = x[0]; - fvec[30] = x[1] - x[0]*x[0] - 1; - } - - // 12. Box 3-dimensional function: - else if ( nprob == 12 ) { - for ( i = 1 ; i <= m ; ++i ) { - tmp = i; - tmp1 = tmp/10.0; - fvec[i-1] = exp(-tmp1*x[0]) - exp(-tmp1*x[1]) + - (exp(-tmp) - exp(-tmp1))*x[2]; - } - } - - // 13. Jennrich and Sampson function: - else if ( nprob == 13 ) { - for ( i = 1 ; i <= m ; ++i ) - fvec[i-1] = 2 + 2*i - exp(i*x[0]) - exp(i*x[1]); - } - - // 14. Brown and Dennis function: - else if ( nprob == 14 ) { - for ( i = 1 ; i <= m ; ++i ) { - tmp = i/5.0; - tmp1 = x[0] + tmp*x[1] - exp(tmp); - tmp2 = x[2] + sin(tmp)*x[3] - cos(tmp); - fvec[i-1] = tmp1*tmp1 + tmp2*tmp2; - } - } - - // 15. Chebyquad function: - else if ( nprob == 15 ) { - for ( i = 0 ; i < m ; ++i ) - fvec[i] = 0.0; - for ( j = 0 ; j < n ; ++j ) { - tmp1 = 1; - tmp2 = 2*x[j] - 1; - tmp3 = 2*tmp2; - for ( i = 0 ; i < m ; ++i ) { - fvec[i] += tmp2; - tmp = tmp3*tmp2 - tmp1; - tmp1 = tmp2; - tmp2 = tmp; - } - } - tmp = -1; - for ( i = 1 ; i <= m ; ++i ) { - fvec[i-1] /= n; - if ( tmp > 0 ) - fvec[i-1] += 1.0 / (i*i - 1); - tmp = -tmp; - } - } - - // 16. Brown almost-linear function: - else if ( nprob == 16 ) { - sum = -n-1; - tmp = 1; - for ( j = 0 ; j < n ; ++j ) { - sum += x[j]; - tmp *= x[j]; - } - for ( i = 0 ; i < n-1 ; ++i ) - fvec[i] = x[i] + sum; - fvec[n-1] = tmp - 1; - } - - // 17. Osborne 1 function: - else if ( nprob == 17 ) { - for ( i = 1 ; i <= 33 ; ++i ) { - tmp = 10*(i-1); - tmp1 = exp(-x[3]*tmp); - tmp2 = exp(-x[4]*tmp); - fvec[i-1] = Y4[i-1] - (x[0] + x[1]*tmp1 + x[2]*tmp2); - } - } - - // 18. Osborne 2 function: - else if ( nprob == 18 ) { - for ( i = 0 ; i < 65 ; ++i ) { - tmp = i/10.0; - tmp1 = exp(-x[4]*tmp); - tmp2 = exp(-x[5]*pow(tmp-x[8],2.0)); - tmp3 = exp(-x[6]*pow(tmp-x[9],2.0)); - tmp4 = exp(-x[7]*pow(tmp-x[10],2.0)); - fvec[i] = Y5[i] - (x[0]*tmp1 + x[1]*tmp2 + - x[2]*tmp3 + x[3]*tmp4); - } - } - - // 19. Bdqrtic: - else if ( nprob == 19 ) { - for ( i = 1 ; i <= n-4 ; ++i ) { - fvec[i-1 ] = (-4*x[i-1]+3.0); - fvec[n-5+i] = (x[i-1]*x[i-1]+2*x[i]*x[i]+3*x[i+1]*x[i+1] - +4*x[i+2]*x[i+2]+5*x[n-1]*x[n-1]); - } - } - - // 20. Cube: - else if ( nprob == 20 ) { - fvec[0] = (x[0]-1.0); - for ( i = 1 ; i < n ; ++i ) - fvec[i] = 10*(x[i]-pow(x[i-1],3.0)); - } - - // 21. Mancino: - else if ( nprob == 21 ) { - for ( i = 1 ; i <= n ; ++i ) { - tmp1 = 0; - for ( j = 1 ; j <= n ; ++j ) { - tmp3 = i; - tmp2 = sqrt ( x[i-1]*x[i-1] + tmp3/j) ; - tmp1 += tmp2*( pow(sin(log(tmp2)),5.0) + pow(cos(log(tmp2)),5.0) ); - } - fvec[i-1]=1400*x[i-1] + pow(i-50,3.0) + tmp1; - } - } - - // 22. Heart8: - else if ( nprob == 22 ) { - fvec[0] = x[0] + x[1] + 0.69; - fvec[1] = x[2] + x[3] + 0.044; - fvec[2] = x[4]*x[0] + x[5]*x[1] - x[6]*x[2] - x[7]*x[3] + 1.57; - fvec[3] = x[6]*x[0] + x[7]*x[1] + x[4]*x[2] + x[5]*x[3] + 1.31; - fvec[4] = x[0]*(x[4]*x[4]-x[6]*x[6]) - 2.0*x[2]*x[4]*x[6] + - x[1]*(x[5]*x[5]-x[7]*x[7]) - 2.0*x[3]*x[5]*x[7] + 2.65; - fvec[5] = x[2]*(x[4]*x[4]-x[6]*x[6]) + 2.0*x[0]*x[4]*x[6] + - x[3]*(x[5]*x[5]-x[7]*x[7]) + 2.0*x[1]*x[5]*x[7] - 2.0; - fvec[6] = x[0]*x[4]*(x[4]*x[4]-3.0*x[6]*x[6]) + - x[2]*x[6]*(x[6]*x[6]-3.0*x[4]*x[4]) + - x[1]*x[5]*(x[5]*x[5]-3.0*x[7]*x[7]) + - x[3]*x[7]*(x[7]*x[7]-3.0*x[5]*x[5]) + 12.6; - fvec[7] = x[2]*x[4]*(x[4]*x[4]-3.0*x[6]*x[6]) - - x[0]*x[6]*(x[6]*x[6]-3.0*x[4]*x[4]) + - x[3]*x[5]*(x[5]*x[5]-3.0*x[7]*x[7]) - - x[1]*x[7]*(x[7]*x[7]-3.0*x[5]*x[5]) - 9.48; - } - - return true; -} - -/*---------------------------------------------------*/ -/* calfun function */ -/*---------------------------------------------------*/ -/* transcripted in C++ from the matlab version */ -/* calfun.m of S. Wild */ -/* http://www.mcs.anl.gov/~more/dfo/matlab/calfun.m */ -/*---------------------------------------------------*/ -double calfun ( int m , // IN : number of outputs. - int n , // IN : dimension of problem - int nprob , // IN : problem index in {1,...,22} - problem_type probtype , // IN : problem type - const double * x , // IN : array of size n - bool & error ) { // OUT: error flag - - error = false; - - int i; - double tmp , f = 0.0 , n1 = 0.0 , n2 = 0.0 , ninf = 0.0 , - * fvec = new double[m] , * xc = new double[n]; - - // restrict domain for some nondiff problems: - if ( probtype == NONDIFF && - ( nprob == 8 || - nprob == 9 || - nprob == 13 || - nprob == 16 || - nprob == 17 || - nprob == 18 ) ) - for ( i = 0 ; i < n ; ++i ) - xc[i] = ( x[i] < 0.0 ) ? 0.0 : x[i]; - else if ( probtype == WILD3 ) { - for ( i = 0 ; i < n ; ++i ) { - xc[i] = x[i]; - tmp = fabs ( x[i] ); - n1 += tmp; - n2 += x[i]*x[i]; - if ( tmp > ninf ) - ninf = tmp; - } - n2 = sqrt(n2); - } - else - for ( i = 0 ; i < n ; ++i ) - xc[i] = x[i]; - - // generate the vector: - if ( !dfovec ( m , n , xc , nprob , fvec ) ) { - error = true; - delete [] xc; - delete [] fvec; - return 1e100; - } - - delete [] xc; - - // calculate the function value: - switch ( probtype ) { - - case SMOOTH: // smooth - for ( i = 0 ; i < m ; ++i ) - f += fvec[i]*fvec[i]; - break; - - case NONDIFF: // nonsmooth - for ( i = 0 ; i < m ; ++i ) - f += fabs ( fvec[i] ); - break; - - case WILD3: // deterministic noise - tmp = 0.9*sin(100*n1)*cos(100*ninf) + 0.1*cos(n2); - tmp *= 4.0*tmp*tmp - 3.0; - for ( i = 0 ; i < m ; ++i ) - f += fvec[i]*fvec[i]; - f *= 1.0 + 0.001*tmp; - break; - - case NOISY3: // random noise - for ( i = 0 ; i < m ; ++i ) { - tmp = rand() / DINT_MAX; - tmp = 1.0 + 0.001 * ( tmp * 2.0 - 1.0 ); - tmp *= fvec[i]; - f += tmp*tmp; - } - break; - } - - delete [] fvec; - - return f; -} - -/*--------------------------------------*/ -/* main function */ -/*--------------------------------------*/ -int main ( int argc , char ** argv ) { - - if ( argc != 2 ) { - cout << "error (no input file)" << endl; - return 1; - } - - // problem 7777777_WILD3: - const int ninstance = 7; - const problem_type pbtype = WILD3; - - int nprob; - int n ; - int m ; - bool ns; - get_instance_data ( ninstance , pbtype , nprob , n , m , ns ); - - // bool ns; - // get_instance_data ( ninstance , pbtype , nprob , n , m , ns ); - // { - // cout << endl << "MORE_WILD_" << ninstance - // << "_" << get_problem_name ( nprob ) << "_"; - // display_pb_type ( pbtype , cout ); - // cout << " (nprob=" << nprob << ",n=" - // << n << ",m=" << m << ",ns=" << ns << ")" - // << endl; - // } - - int i; - double * x = new double[n]; - - // read the point: - ifstream in ( argv[1] ); - - for ( i = 0 ; i < n ; ++i ) - in >> x[i]; - - in.close(); - - if ( in.fail() ) { - cerr << endl << "could not read input file " << argv[1] - << endl << endl; - delete [] x; - return 1; - } - -// cout << "x = ( "; -// for ( i = 0 ; i < n ; ++i ) -// cout << x[i] << " "; -// cout << ")" << endl; - - bool error; - double f = calfun ( m , n , nprob , pbtype , x , error ); - - if ( error ) - cout << "error"; - else - cout << f; - - cout << endl; - - delete [] x; - - return 0; -} diff --git a/examples/advanced/library/Restart_VNS/problems/7_WILD3/param.txt b/examples/advanced/library/Restart_VNS/problems/7_WILD3/param.txt deleted file mode 100644 index 5997ac55..00000000 --- a/examples/advanced/library/Restart_VNS/problems/7_WILD3/param.txt +++ /dev/null @@ -1,25 +0,0 @@ -DIMENSION 12 -BB_EXE bb.exe -BB_OUTPUT_TYPE OBJ -TMP_DIR /tmp -x0 * 0.0 #x0.txt - -HOT_RESTART_READ_FILES false -HOT_RESTART_WRITE_FILES false - -#VNS_MADS_SEARCH true - - -DISPLAY_STATS bbe ( sol ) obj -DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL true -STATS_FILE ./STATS/stats.txt bbe ( sol ) obj -EVAL_STATS_FILE ./STATS/detailedStats.txt - -# MAX_BB_EVAL 420 #100 - -# initial_mesh_size * 5.0 - - -# model_search no -# model_eval_sort no diff --git a/examples/advanced/library/Restart_VNS/problems/7_WILD3/param_VNSmartAlgo.txt b/examples/advanced/library/Restart_VNS/problems/7_WILD3/param_VNSmartAlgo.txt deleted file mode 100644 index 42242f23..00000000 --- a/examples/advanced/library/Restart_VNS/problems/7_WILD3/param_VNSmartAlgo.txt +++ /dev/null @@ -1,16 +0,0 @@ -DIMENSION 12 -BB_EXE bb.exe -TMP_DIR /tmp -BB_OUTPUT_TYPE OBJ -x0 * 0.0 #x0.txt - -# MAX_BB_EVAL 100 - -VNSMART_SEARCH yes - -DISPLAY_STATS bbe ( sol ) obj -DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL true -STATS_FILE ./VNSmartAlgoSearch/stats_vnsmart.txt bbe ( sol ) obj -EVAL_STATS_FILE ./VNSmartAlgoSearch/detailedStats_vnsmart.txt -HISTORY_FILE ./VNSmartAlgoSearch/historyFile_vnsmart.txt diff --git a/examples/advanced/library/Restart_VNS/problems/7_WILD3/paramvns.txt b/examples/advanced/library/Restart_VNS/problems/7_WILD3/paramvns.txt deleted file mode 100644 index 99e4906e..00000000 --- a/examples/advanced/library/Restart_VNS/problems/7_WILD3/paramvns.txt +++ /dev/null @@ -1,25 +0,0 @@ -DIMENSION 12 -BB_EXE bb.exe -BB_OUTPUT_TYPE OBJ -TMP_DIR /tmp -x0 * 0.0 #x0.txt - -HOT_RESTART_READ_FILES false -HOT_RESTART_WRITE_FILES false - -VNS_MADS_SEARCH true - - -DISPLAY_STATS bbe ( sol ) obj -DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL true -STATS_FILE ./STATS/stats_vns.txt bbe ( sol ) obj -EVAL_STATS_FILE ./STATS/detailedStats_vns.txt - -# MAX_BB_EVAL 420 #100 - -# initial_mesh_size * 5.0 - - -# model_search no -# model_eval_sort no diff --git a/examples/advanced/library/Restart_VNS/problems/7_WILD3/x0.txt b/examples/advanced/library/Restart_VNS/problems/7_WILD3/x0.txt deleted file mode 100644 index c680d593..00000000 --- a/examples/advanced/library/Restart_VNS/problems/7_WILD3/x0.txt +++ /dev/null @@ -1,2 +0,0 @@ -5 -20 - diff --git a/examples/advanced/library/Restart_VNS/problems/COCO/Readme.txt b/examples/advanced/library/Restart_VNS/problems/COCO/Readme.txt deleted file mode 100644 index e7e0e524..00000000 --- a/examples/advanced/library/Restart_VNS/problems/COCO/Readme.txt +++ /dev/null @@ -1,7 +0,0 @@ -Follow the Getting started instructions from the Readme of https://github.com/numbbo/coco -For the step 4, copy coco.h and coco.c into this subdirectory. -Once available run the cmake configuration, build and install steps. -An executable single_bbob-constrained.exe must be available in this subdirectory. - -Three (3) hardocoded attributes can be changed in the source code. Instances to be run, dimensions to include and functions considered. -The parameter file must be modified accordingly. X0 and the number of constraints are different for each function and instance. Lower and upper bounds are the same. diff --git a/examples/advanced/library/Restart_VNS/problems/COCO/param.txt b/examples/advanced/library/Restart_VNS/problems/COCO/param.txt deleted file mode 100644 index dd16bb96..00000000 --- a/examples/advanced/library/Restart_VNS/problems/COCO/param.txt +++ /dev/null @@ -1,33 +0,0 @@ - -# PROBLEM PARAMETERS -#################### - -# Number of variables -DIMENSION 10 - -# Black box -BB_EXE single_bbob-constrained.exe -BB_OUTPUT_TYPE OBJ PB PB PB PB PB PB PB PB PB - -# Starting point -X0 ( -4.426533 4.238298 1.037814 -3.581491 -4.835488 1.023338 2.797704 -2.753894 -2.859614 -4.790012 ) # Given by coco for instance 1, dim 10, f51 - -# Bounds are useful to avoid extreme values -LOWER_BOUND * -5.0 -UPPER_BOUND * 5.0 - - -# ALGORITHM PARAMETERS -###################### - -# The algorithm terminates after that number black-box evaluations -# MAX_BB_EVAL 600 - -# Parameters for display -DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL 1 -DISPLAY_STATS BBE ( SOL ) OBJ CONS_H -STATS_FILE ./STATS/stats.txt bbe ( sol ) obj -EVAL_STATS_FILE ./STATS/detailedStats.txt -HISTORY_FILE ./STATS/historyFile.txt - diff --git a/examples/advanced/library/Restart_VNS/problems/COCO/param_VNSmartAlgo.txt b/examples/advanced/library/Restart_VNS/problems/COCO/param_VNSmartAlgo.txt deleted file mode 100644 index 6029e107..00000000 --- a/examples/advanced/library/Restart_VNS/problems/COCO/param_VNSmartAlgo.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Number of variables -DIMENSION 10 - -# Black box -BB_EXE single_bbob-constrained.exe -BB_OUTPUT_TYPE OBJ PB PB PB PB PB PB PB PB PB - -# Starting point -X0 ( -4.426533 4.238298 1.037814 -3.581491 -4.835488 1.023338 2.797704 -2.753894 -2.859614 -4.790012 ) # Given by coco for instance 1, dim 10, f51 - -# Bounds are useful to avoid extreme values -LOWER_BOUND * -5.0 -UPPER_BOUND * 5.0 - -MAX_BB_EVAL 2000 - -VNSMART_ALGO_SEARCH yes - -DISPLAY_STATS BBE ( SOL ) OBJ CONS_H -DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL true -STATS_FILE ./VNSmartAlgoSearch/stats_vnsmart.txt bbe ( sol ) obj -EVAL_STATS_FILE ./VNSmartAlgoSearch/detailedStats_vnsmart.txt -HISTORY_FILE ./VNSmartAlgoSearch/historyFile_vnsmart.txt diff --git a/examples/advanced/library/Restart_VNS/problems/COCO/paramvns.txt b/examples/advanced/library/Restart_VNS/problems/COCO/paramvns.txt deleted file mode 100644 index cebdae4e..00000000 --- a/examples/advanced/library/Restart_VNS/problems/COCO/paramvns.txt +++ /dev/null @@ -1,38 +0,0 @@ - -# PROBLEM PARAMETERS -#################### - -# Number of variables -DIMENSION 10 - -# Black box -BB_EXE single_bbob-constrained.exe -BB_OUTPUT_TYPE OBJ PB PB PB PB PB PB PB PB PB - -# Starting point -X0 ( -4.426533 4.238298 1.037814 -3.581491 -4.835488 1.023338 2.797704 -2.753894 -2.859614 -4.790012 ) # Given by coco for instance 1, dim 10, f51 - -# Bounds are useful to avoid extreme values -LOWER_BOUND * -5.0 -UPPER_BOUND * 5.0 - - -# ALGORITHM PARAMETERS -###################### - -# The algorithm terminates after that number black-box evaluations -# MAX_BB_EVAL 600 - -# VNS search -VNS_MADS_SEARCH true -VNS_MADS_SEARCH_TRIGGER 0.75 - - -# Parameters for display -DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL 1 -DISPLAY_STATS BBE ( SOL ) OBJ CONS_H -STATS_FILE ./STATS/stats_vns.txt bbe ( sol ) obj -EVAL_STATS_FILE ./STATS/detailedStats_vns.txt -HISTORY_FILE ./STATS/historyFile_vns.txt - diff --git a/examples/advanced/library/Restart_VNS/problems/COCO/x0.txt b/examples/advanced/library/Restart_VNS/problems/COCO/x0.txt deleted file mode 100644 index 5e4a6a73..00000000 --- a/examples/advanced/library/Restart_VNS/problems/COCO/x0.txt +++ /dev/null @@ -1 +0,0 @@ --4.426533 4.238298 1.037814 -3.581491 -4.835488 1.023338 2.797704 -2.753894 -2.859614 -4.790012 diff --git a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/param.txt b/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/param.txt deleted file mode 100644 index dfeb3b69..00000000 --- a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/param.txt +++ /dev/null @@ -1,20 +0,0 @@ -DIMENSION 12 -BB_EXE bb.exe -TMP_DIR /tmp -BB_OUTPUT_TYPE OBJ -X0 * -5.12 - -# LOWER_BOUND * -5.12 -# UPPER_BOUND * 5.12 - -# MAX_BB_EVAL 500 - -#VNS_MADS_SEARCH true -#VNS_MADS_SEARCH_TRIGGER 0.75 - -DISPLAY_STATS bbe ( sol ) obj -DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL true -STATS_FILE ./STATS/stats.txt bbe ( sol ) obj -EVAL_STATS_FILE ./STATS/detailedStats.txt -HISTORY_FILE ./STATS/historyFile.txt diff --git a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/param_VNSmartAlgo.txt b/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/param_VNSmartAlgo.txt deleted file mode 100644 index ba0c4fde..00000000 --- a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/param_VNSmartAlgo.txt +++ /dev/null @@ -1,19 +0,0 @@ -DIMENSION 12 -BB_EXE bb.exe -TMP_DIR /tmp -BB_OUTPUT_TYPE OBJ -X0 * -5.12 - -# LOWER_BOUND * -5.12 -# UPPER_BOUND * 5.12 - -MAX_BB_EVAL 100 - -VNSMART_SEARCH yes - -DISPLAY_STATS bbe ( sol ) obj -DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL true -STATS_FILE ./VNSmartAlgoSearch/stats_vnsmart.txt bbe ( sol ) obj -EVAL_STATS_FILE ./VNSmartAlgoSearch/detailedStats_vnsmart.txt -HISTORY_FILE ./VNSmartAlgoSearch/historyFile_vnsmart.txt diff --git a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/paramvns.txt b/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/paramvns.txt deleted file mode 100644 index 9a214201..00000000 --- a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/paramvns.txt +++ /dev/null @@ -1,20 +0,0 @@ -DIMENSION 12 -BB_EXE bb.exe -TMP_DIR /tmp -BB_OUTPUT_TYPE OBJ -X0 * -5.12 - -# LOWER_BOUND * -5.12 -# UPPER_BOUND * 5.12 - -# MAX_BB_EVAL 500 - -VNS_MADS_SEARCH true -VNS_MADS_SEARCH_TRIGGER 0.75 - -DISPLAY_STATS bbe ( sol ) obj -DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL true -STATS_FILE ./STATS/stats_vns.txt bbe ( sol ) obj -EVAL_STATS_FILE ./STATS/detailedStats_vns.txt -HISTORY_FILE ./STATS/historyFile_vns.txt diff --git a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/x0.txt b/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/x0.txt deleted file mode 100644 index ed7b51cb..00000000 --- a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/x0.txt +++ /dev/null @@ -1 +0,0 @@ --5.12 -5.12 diff --git a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/xe.txt b/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/xe.txt deleted file mode 100644 index 8cc9589b..00000000 --- a/examples/advanced/library/Restart_VNS/problems/RASTRIGIN/xe.txt +++ /dev/null @@ -1,3 +0,0 @@ -0 0 - -0 \ No newline at end of file diff --git a/examples/advanced/library/Restart_VNS/restart_vns.cpp b/examples/advanced/library/Restart_VNS/restart_vns.cpp deleted file mode 100644 index 55e63281..00000000 --- a/examples/advanced/library/Restart_VNS/restart_vns.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/*---------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ -/* */ -/* NOMAD - Version 4 has been created and developed by */ -/* Viviane Rochon Montplaisir - Polytechnique Montreal */ -/* Christophe Tribes - Polytechnique Montreal */ -/* */ -/* The copyright of NOMAD - version 4 is owned by */ -/* Charles Audet - Polytechnique Montreal */ -/* Sebastien Le Digabel - Polytechnique Montreal */ -/* Viviane Rochon Montplaisir - Polytechnique Montreal */ -/* Christophe Tribes - Polytechnique Montreal */ -/* */ -/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ -/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ -/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ -/* for Data Valorization) */ -/* */ -/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ -/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ -/* and Exxon Mobil. */ -/* */ -/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ -/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ -/* Exxon Mobil. */ -/* */ -/* Contact information: */ -/* Polytechnique Montreal - GERAD */ -/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ -/* e-mail: nomad@gerad.ca */ -/* */ -/* 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 . */ -/* */ -/* You can find information on the NOMAD software at www.gerad.ca/nomad */ -/*---------------------------------------------------------------------------------*/ -/*------------------------------------------------------------------------------------*/ -/* example of a program that makes NOMAD restarts after a chosen stopping condition */ -/* enables to restart from current state with different parameter settings (here VNS) */ -/*------------------------------------------------------------------------------------*/ - -#include "Nomad/nomad.hpp" -#include "Algos/EvcInterface.hpp" -#include "Algos/Mads/MadsMegaIteration.hpp" -#include "Algos/AlgoStopReasons.hpp" -#include "Cache/CacheBase.hpp" -#include "Type/LHSearchType.hpp" -#include "Eval/SuccessStats.hpp" -#include -#include - - -std::shared_ptr mesh; -auto params = std::make_shared(); -auto madsStopReasons = std::make_shared>(); - -// Problem given to the solver -std::string problembName = "./problems/RASTRIGIN"; -std::string bbexe = "./problems/RASTRIGIN/bb.exe"; - -// Counter for the number of successive failure -int compteur = 0; - -// Thresholds -int stopConsFailures = 3; // Threshold for the number of successive failure -int stopMeshIndex = -2; // Threshold for the mesh index - -// Stopping conditions initialization -bool stopCondition = false; - -// Nombre d'entrée dans la méga itération -int nbEnterMegaIter = 0; - -// Number of bbeval with VNS activated -int nbBbeBeforeVNS = 0; -int nbBbeWithVNS = 0; - -// Run number -int i = 0; - -// Number and state of the iteration -int nbIteration = 0; -bool iterationSucess = false; -bool VNS = false; - - -void initAllParams(std::shared_ptr allParams, const size_t n) -{ - // Parameters creation - allParams->setAttributeValue("DIMENSION", n); - // Blackbox to evaluate - allParams->setAttributeValue("BB_EXE", bbexe); - // 100 black-box evaluations - // allParams->setAttributeValue("MAX_BB_EVAL", 200); - // Starting point - // RASTRIGIN - allParams->setAttributeValue("X0", NOMAD::Point(n, -5.12) ); - /* - // COCO - NOMAD::Point x0(n); - x0[0] = -4.426533; - x0[1] = 4.238298; - x0[2] = 1.037814; - x0[3] = -3.581491; - x0[4] = -4.835488; - x0[5] = 1.023338; - x0[6] = 2.797704; - x0[7] = -2.753894; - x0[8] = -2.859614; - x0[9] = -4.790012; - allParams->setAttributeValue("X0", x0); - */ - // Bounds - // RASTRIGIN - //allParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(n, -5.12)); - //allParams->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(n, 5.12)); - // COCO - //allParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(n, -5.0)); - //allParams->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(n, 5.0)); - - // Constraints and objective - NOMAD::BBOutputTypeList bbOutputTypes; - bbOutputTypes.push_back(NOMAD::BBOutputType::OBJ); - // RASTRIGIN - allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); - allParams->setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("bbe ( sol ) obj")); - - - // COCO - /* - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); - allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); - allParams->setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("bbe ( sol ) obj cons_h")); - */ - - allParams->setAttributeValue("DISPLAY_DEGREE", 2); - allParams->setAttributeValue("DISPLAY_ALL_EVAL", true); - - // Parameters validation - allParams->checkAndComply(); - -} - - -/*--------------------------------------*/ -/* Before each MegaIteration, verify if */ -/* the algorithm should stop. */ -/*--------------------------------------*/ -void userMegaIterationStart(const NOMAD::Step& step, - bool &stop) -{ - auto megaIter = dynamic_cast(&step); - auto bbe = NOMAD::EvcInterface::getEvaluatorControl()->getBbEval(); // Number of blackbox evaluation - - //std::cout << "CallBack START no VNS" << std::endl; - - stop = false; - - - if (nullptr != megaIter) - { - // std::cout << std::endl << "Start mega itération!" << std::endl; - ++nbIteration; - // We use the success of the previous megaIteration. The success is reset to UNDEFINED at the defaultStart before this callback function is called. - auto success = megaIter->getSuccessType(); //NOT_TRIALS, UNSUCCESSFUL, PARTIAL_SUCCESS, FULL_SUCCESS ou UNDEFINED - - // The counter is updated regarding the reuslt of the previous iteration - if (NOMAD::SuccessType::FULL_SUCCESS == success || NOMAD::SuccessType::PARTIAL_SUCCESS == success) // counter reset for success or partial success - { - //std::cout << "SUCCESS OR PARTIAL SUCCESS" << std::endl; - compteur = 0; - iterationSucess = true; - } - else if (NOMAD::SuccessType::UNDEFINED == success) // no event case - { - //std::cout << "Default type set at start" << std::endl; - } - else // update if unsuccessful or no trial points - { - //std::cout << "UNSUCCESSFUL OR NO_TRIALS" << std::endl; - ++compteur; - } - // std::cout << "Nb consecutive fails:" << compteur << std::endl; - - // We can also have access to this information through nomad statistics - // auto nbConsecutiveFail = megaIter->getConstSuccessStats().getStatsNbConsecutiveFail(); - // std::cout << "Compteur NOMAD : " << nbConsecutiveFail << std::endl; - - if (i > 0) { - // Keep information about the value of mesh index from the previous run - NOMAD::ArrayOfDouble oldMeshIndices = mesh->getMeshIndex(); - //std::cout << "old mesh indices : " << oldMeshIndices << std::endl; - - // Let's pass the mesh - //std::cout << std::endl << "Mesh :" << std::endl; - mesh = megaIter->getMesh(); - //std::cout << *mesh << std::endl; - - // Set the mesh index value - mesh->setMeshIndex(oldMeshIndices); - } - else { - // Let's pass the mesh - //std::cout << std::endl << Mesh :" << std::endl; - mesh = megaIter->getMesh(); - //std::cout << *mesh << std::endl; - } - - // Let's print a parameter on MAX_BB_EVAL - // int maxBbEval; - // maxBbEval = params->getAttributeValue("MAX_BB_EVAL"); - // std::cout << "MAX_BB_EVAL : " << maxBbEval << std::endl; - - // Collect mesh index information - NOMAD::ArrayOfDouble meshIndices = mesh->getMeshIndex(); - NOMAD::ArrayOfDouble meshIndexStop(meshIndices.size(), stopMeshIndex); - //std::cout << "mesh indices: " << meshIndices << std::endl; - // std::cout << "mesh stop indices: " << meshIndexStop << std::endl; - - // Reinitialize the iteration state - iterationSucess = false; - - // Stopping conditions: - stopCondition = (compteur >= stopConsFailures); - //std::cout << std::endl << "Stopping condition: " << stopCondition << std::endl; - - if (stopCondition) // Stop motivated by user conditions - { - stop = true; - } - } -} - -/*--------------------------------------------*/ -/* Before each MegaIteration after using VNS, */ -/* the algorithm should stop. */ -/*--------------------------------------------*/ -void userMegaIterationStartForVNS(const NOMAD::Step& step, - bool &stop) -{ - auto megaIter = dynamic_cast(&step); - auto bbe = NOMAD::EvcInterface::getEvaluatorControl()->getBbEval(); // Récupère le nombre de blackbox evaluations - - - stop = false; - - if (nullptr != megaIter) - { - - ++nbEnterMegaIter; - ++nbIteration; - // std::cout << std::endl << "Nb mega iter: " << nbEnterMegaIter << std::endl; - // We use the success of the previous megaIteration. The success is reset to UNDEFINED at the defaultStart before this callback function is called. - auto success = megaIter->getSuccessType(); //NO_TRIALS, UNSUCCESSFUL, PARTIAL_SUCCESS, FULL_SUCCESS ou UNDEFINED - - // The counter is updated regarding the reuslt of the previous iteration - if (NOMAD::SuccessType::FULL_SUCCESS == success || NOMAD::SuccessType::PARTIAL_SUCCESS == success) // counter reset for success or partial success - { - compteur = 0; - iterationSucess = true; - } - else if (NOMAD::SuccessType::UNDEFINED == success) // no event case - { - std::cout << "Default type set at start" << std::endl; - } - else // update if unsuccessful or no trial points - { - ++compteur; - } - //std::cout << "Number of successive fails: " << compteur << std::endl; - - - // Keep information about the value of mesh index from the previous run - NOMAD::ArrayOfDouble oldMeshIndices = mesh->getMeshIndex(); - // std::cout << "old mesh indices: " << oldMeshIndices << std::endl; - - // Let's pass the mesh - //std::cout << std::endl << "Mesh :" << std::endl; - mesh = megaIter->getMesh(); - //std::cout << *mesh << std::endl; - - // Set the mesh index value - mesh->setMeshIndex(oldMeshIndices); - - // Collect mesh index information - NOMAD::ArrayOfDouble meshIndices = mesh->getMeshIndex(); - NOMAD::ArrayOfDouble meshIndexStop(meshIndices.size(), stopMeshIndex); - //std::cout << "mesh indices : " << meshIndices << std::endl; - //std::cout << "mesh stop indices : " << meshIndexStop << std::endl; - - iterationSucess = false; - - // Stopping conditions: - stopCondition = (compteur >= stopConsFailures); - // std::cout << std::endl << "Stopping condition: " << stopCondition << std::endl; - - // Stop motivated by user conditions : after one megaiteration - if (NOMAD::SuccessType::UNDEFINED != success && nbEnterMegaIter > 1) - { - stop = true; - nbEnterMegaIter = 0; - nbBbeWithVNS += (bbe - nbBbeBeforeVNS); - } - } -} - - -/*------------------------------------------*/ -/* NOMAD main function */ -/*------------------------------------------*/ -int main ( int argc , char ** argv ) -{ - // Dimension (Number of variables) - size_t n = 12; - - NOMAD::MainStep TheMainStep; - - initAllParams(params, n); - TheMainStep.setAllParameters(params); - - // Custom batch Evaluator - auto ev = std::make_unique(params->getEvalParams(),NOMAD::EvalType::BB); - TheMainStep.addEvaluator(std::move(ev)); - - std::vector bf; - std::vector bi; - bool stopLoop = false; - bool stopReasonIsCallback = false; - - // Main run - try - { - i = 0; - // successive runs: - do - { - std::cout << std::endl << "MADS run #" + NOMAD::itos(i) << std::endl; - - // Stats files - std::string statsFile = problembName; - statsFile += "/STATS/stats"; - statsFile += std::to_string(i); - statsFile += ".txt bbe ( sol ) obj"; - params->setAttributeValue("STATS_FILE", NOMAD::ArrayOfString(statsFile)); - - std::string detailedStatsFile = problembName; - detailedStatsFile += "/STATS/detailedStats"; - detailedStatsFile += std::to_string(i); - detailedStatsFile += ".txt"; - params->setAttributeValue("EVAL_STATS_FILE", std::string(detailedStatsFile)); - - std::string historyFile = problembName; - historyFile += "/STATS/history"; - historyFile += std::to_string(i); - historyFile += ".txt"; - params->setAttributeValue("HISTORY_FILE", std::string(historyFile)); - - // Set callbacks - - if (!stopCondition) // MADS default without VNS - { - std::cout << "MADS default no VNS" << std::endl; - TheMainStep.addCallback(NOMAD::CallbackType::MEGA_ITERATION_START, userMegaIterationStart); - - if ( i > 0 ) - { - // Seuil compteur dynamique - stopConsFailures = static_cast(3*std::ceil(i/5.0)); - - // Desactivate VNS MADS search - params->getRunParams()->setAttributeValue("VNS_MADS_SEARCH", false); - - - // New starting points - NOMAD::ArrayOfPoint x0s; - if (bf.size() > 0) - { - x0s.push_back(bf[0]); - } - if (bi.size() > 0) - { - x0s.push_back(bi[0]); - } - params->getPbParams()->setAttributeValue("X0", x0s); - - //std::cout << mesh->getDeltaFrameSize() << std::endl; - params->getPbParams()->setAttributeValue("INITIAL_FRAME_SIZE", mesh->getDeltaFrameSize()); - - // at least one evaluation is conducted if points bf and bi are null - std::string lhSearchStr = (bf.empty() && bi.empty()) ? " 1 0" : "0 0"; - params->getRunParams()->setAttributeValue("LH_SEARCH", NOMAD::LHSearchType(lhSearchStr)); - - // Parameters validation - params->checkAndComply(); - } - - } - else // MADS default + VNS for 1 mega iteration only - { - // Update thresholds for the stopping criterion - stopConsFailures = static_cast(3*std::ceil(i/5.0)); - - TheMainStep.addCallback(NOMAD::CallbackType::MEGA_ITERATION_START, userMegaIterationStartForVNS); - nbBbeBeforeVNS = NOMAD::EvcInterface::getEvaluatorControl()->getBbEval(); // Keeps the number of blackbox evaluations before using VNS - - // Activate VNS MADS serach - params->getRunParams()->setAttributeValue("VNS_MADS_SEARCH", true); - params->getRunParams()->setAttributeValue("VNS_MADS_SEARCH_TRIGGER", NOMAD::Double(1)); - - // New starting points - NOMAD::ArrayOfPoint x0s; - if (bf.size() > 0) - { - x0s.push_back(bf[0]); - } - if (bi.size() > 0) - { - x0s.push_back(bi[0]); - } - params->getPbParams()->setAttributeValue("X0", x0s); - - //std::cout << mesh->getDeltaFrameSize() << std::endl; - params->getPbParams()->setAttributeValue("INITIAL_FRAME_SIZE", mesh->getDeltaFrameSize()); - - // at least one evaluation is conducted if points bf and bi are null - std::string lhSearchStr = (bf.empty() && bi.empty()) ? " 1 0" : "0 0"; - params->getRunParams()->setAttributeValue("LH_SEARCH", NOMAD::LHSearchType(lhSearchStr)); - - // Parameters validation - params->checkAndComply(); - - } - - // The run - TheMainStep.start(); - TheMainStep.run(); - TheMainStep.end(); - - auto algoStopReason = NOMAD::AlgoStopReasons::get(TheMainStep.getAllStopReasons()); // Récupère le stop reason de mads - stopLoop = algoStopReason->testIf(NOMAD::MadsStopType::MESH_PREC_REACHED) || algoStopReason->testIf(NOMAD::MadsStopType::MIN_MESH_INDEX_REACHED) ; // Test si le stop reason correspond MESH_PREC_REACHED - std::cout << algoStopReason->getStopReasonAsString() << std::endl; // Juste affiche le stop reason. - - stopReasonIsCallback = (algoStopReason->getStopReasonAsString() == "User-stopped in a callback function (Base)"); - - - bf.clear(); - bi.clear(); - NOMAD::CacheBase::getInstance()->findBestFeas(bf, NOMAD::Point(n), NOMAD::EvalType::BB,NOMAD::ComputeType::STANDARD); - NOMAD::CacheBase::getInstance()->findBestInf(bi, NOMAD::INF, NOMAD::Point(n), NOMAD::EvalType::BB, NOMAD::ComputeType::STANDARD); - - ++i; - - } while (!stopLoop); // run until one NOMAD termination criterion is met - -} - - catch(std::exception &e) - { - std::cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; - } - - return EXIT_SUCCESS; -} diff --git a/examples/advanced/library/StopIfBBFails/CMakeLists.txt b/examples/advanced/library/StopIfBBFails/CMakeLists.txt index 33dbeb27..e4c0da87 100644 --- a/examples/advanced/library/StopIfBBFails/CMakeLists.txt +++ b/examples/advanced/library/StopIfBBFails/CMakeLists.txt @@ -17,19 +17,4 @@ install(TARGETS stopIfBBFails.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add test for this example -#if(BUILD_TESTS MATCHES ON) -# message(STATUS " Add example test for handling bb fail") -# # Can run this test after install -# if (WIN32) -# add_test(NAME ExampleAdvancedstopIfBBFails -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./stopIfBBFails.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# else() -# add_test(NAME ExampleAdvancedstopIfBBFails -# COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./stopIfBBFails.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# endif() -#endif() +# No test for this example \ No newline at end of file diff --git a/examples/advanced/library/StopIfBBFails/stopIfBBFails.cpp b/examples/advanced/library/StopIfBBFails/stopIfBBFails.cpp index 5e5d4729..9f8f3ec9 100644 --- a/examples/advanced/library/StopIfBBFails/stopIfBBFails.cpp +++ b/examples/advanced/library/StopIfBBFails/stopIfBBFails.cpp @@ -66,7 +66,7 @@ // To run this optimization, the program must be executed in a path where styrene truth executable is available. // Styrene sources are available at https://github.com/bbopt/styrene and must be compiled prior to run this optimization. -void initAllParams( std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { const int n = 8; @@ -78,7 +78,6 @@ void initAllParams( std::shared_ptr allParams) std::vector x0 = { 54, 66, 86, 8, 29, 51, 32, 15}; allParams->setAttributeValue("X0", NOMAD::Point(x0) ); allParams->setAttributeValue("BB_EXE", std::string("./truth.exe")); // IMPORTANT: May require some change - // Bounds allParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(n, 0.0 )); @@ -91,11 +90,8 @@ void initAllParams( std::shared_ptr allParams) allParams->setAttributeValue("DISPLAY_DEGREE", 4); allParams->setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("bbe ( sol ) obj")); - // Parameters validation allParams->checkAndComply(); - - } @@ -120,14 +116,11 @@ void customEvalStopCB( NOMAD::EvalQueuePointPtr & evalQueuePoint, bool & globalS } - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) +int main() { - - NOMAD::MainStep TheMainStep; // Set parameters @@ -147,5 +140,5 @@ int main ( int argc , char ** argv ) TheMainStep.run(); TheMainStep.end(); - return 1; + return 0; } diff --git a/examples/advanced/library/StopOnConsecutiveFails/CMakeLists.txt b/examples/advanced/library/StopOnConsecutiveFails/CMakeLists.txt index 98bfc846..4e561260 100644 --- a/examples/advanced/library/StopOnConsecutiveFails/CMakeLists.txt +++ b/examples/advanced/library/StopOnConsecutiveFails/CMakeLists.txt @@ -17,19 +17,4 @@ install(TARGETS stopOnConsecutiveFails.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add test for this example -#if(BUILD_TESTS MATCHES ON) -# message(STATUS " Add example test for handling stop after consecutive fails") -# # Can run this test after install -# if (WIN32) -# add_test(NAME ExampleAdvancedstopOnConsecutiveFails -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./stopOnConsecutiveFails.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# else() -# add_test(NAME ExampleAdvancedstopOnConsecutiveFails -# COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./stopOnConsecutiveFails.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# endif() -#endif() +# No test for this example \ No newline at end of file diff --git a/examples/advanced/library/StopOnConsecutiveFails/stopOnConsecutiveFails.cpp b/examples/advanced/library/StopOnConsecutiveFails/stopOnConsecutiveFails.cpp index b3c1182d..0fc779c1 100644 --- a/examples/advanced/library/StopOnConsecutiveFails/stopOnConsecutiveFails.cpp +++ b/examples/advanced/library/StopOnConsecutiveFails/stopOnConsecutiveFails.cpp @@ -62,11 +62,11 @@ class My_Evaluator : public NOMAD::Evaluator private: public: - My_Evaluator(const std::shared_ptr& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; }; @@ -98,9 +98,8 @@ bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, return true; // the evaluation succeeded } -void initAllParams(std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { - const size_t n = 5; // Parameters creation @@ -119,9 +118,9 @@ void initAllParams(std::shared_ptr allParams) // Constraints and objective NOMAD::BBOutputTypeList bbOutputTypes; - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::OBJ); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::PB); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::OBJ); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::PB); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::PB); allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); allParams->setAttributeValue("DISPLAY_DEGREE", 2); @@ -130,7 +129,6 @@ void initAllParams(std::shared_ptr allParams) // Parameters validation requested to have access to their value. allParams->checkAndComply(); - } @@ -165,14 +163,11 @@ void userIterationCallback(const NOMAD::Step& step, } - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) +int main() { - - NOMAD::MainStep TheMainStep; // Set parameters @@ -186,12 +181,11 @@ int main ( int argc , char ** argv ) // Set main step callback TheMainStep.addCallback(NOMAD::CallbackType::MEGA_ITERATION_END, userIterationCallback); - - + // The run TheMainStep.start(); TheMainStep.run(); TheMainStep.end(); - return 1; + return 0; } diff --git a/examples/advanced/library/c_api/example1/CMakeLists.txt b/examples/advanced/library/c_api/example1/CMakeLists.txt index 58ed2ab4..ddc099d5 100644 --- a/examples/advanced/library/c_api/example1/CMakeLists.txt +++ b/examples/advanced/library/c_api/example1/CMakeLists.txt @@ -41,20 +41,19 @@ install(TARGETS example1_c_api.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) # Add a test for this example -if(BUILD_EXAMPLES MATCHES ON) - message(STATUS " Add example test for c-api 1") - # Can run this test after install +message(STATUS " Add example test for c-api 1") + +# Can run this test after install - if (WIN32) +if (WIN32) # MAYBE ENABLE the test when script is adapted to windows # add_test(NAME ExampleAdvancedC-API1 # COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./example1_c_api.exe # WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} # ) - else() - add_test(NAME ExampleAdvancedC-API1 +else() + add_test(NAME ExampleAdvancedC-API1 COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./example1_c_api.exe WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - endif() endif() diff --git a/examples/advanced/library/c_api/example1/example1_c_api.c b/examples/advanced/library/c_api/example1/example1_c_api.c index 2144be78..eea107d6 100644 --- a/examples/advanced/library/c_api/example1/example1_c_api.c +++ b/examples/advanced/library/c_api/example1/example1_c_api.c @@ -13,7 +13,6 @@ bool example1_bb(int nb_inputs, double *x, int nb_outputs, double *bb_outputs, b bool eval_ok = true; // based on G2 - double f = 1e+20, g1 = 1e+20, g2 = 1e+20; double sum1 = 0.0, sum2 = 0.0, sum3 = 0.0, prod1 = 1.0, prod2 = 1.0; for (int i = 0; i < nb_inputs; ++i) @@ -35,10 +34,10 @@ bool example1_bb(int nb_inputs, double *x, int nb_outputs, double *bb_outputs, b } } - g1 = -prod2 + 0.75; - g2 = sum2 - 7.5 * nb_inputs; + const double g1 = -prod2 + 0.75; + const double g2 = sum2 - 7.5 * nb_inputs; - f = 10 * g1 + 10 * g2; + double f = 10 * g1 + 10 * g2; if (0.0 != sum3) { f -= fabs(((sum1 - 2 * prod1) / sqrt(sum3))); @@ -71,6 +70,7 @@ int main(int argc, char **argv) // create Nomad problem NomadProblem nomad_pb = createNomadProblem(example1_bb, + NULL, nb_inputs, nb_outputs); @@ -90,9 +90,6 @@ int main(int argc, char **argv) addNomadParam(nomad_pb, "DISPLAY_ALL_EVAL true"); addNomadParam(nomad_pb, "DISPLAY_UNSUCCESSFUL false"); - // for reproducibility - addNomadValParam(nomad_pb, "NB_THREADS_OPENMP", 1); - // and the number of blackbox allowed addNomadParam(nomad_pb, "MAX_BB_EVAL 1000"); @@ -100,24 +97,22 @@ int main(int argc, char **argv) double x0[10] = {7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0, 7.0}; // starting point - double x_feas_sol[10] = {0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0}; // feasible solution - - double x_inf_sol[10] = {0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0}; // infeasible solution + NomadResult nomad_result = createNomadResult(); - double outputs_feas_sol[10] = {0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0}; // feasible solution outputs + int run_flag = solveNomadProblem(nomad_result, nomad_pb, 1, x0, NULL); + printf("Run status: %d\n", run_flag); - double outputs_inf_sol[10] = {0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0}; // infeasible solution outputs + int nb_solutions = nbSolutionsNomadResult(nomad_result); + printf("The algorithm has found %d solutions\n", nb_solutions); - bool exists_feas, exists_infeas = false; // flag which indicates if the solution exists or not + // Get a solution + double x_sol[10]; + double outputs_sol[4]; - solveNomadProblem(nomad_pb, 1, x0, - &exists_feas, x_feas_sol, outputs_feas_sol, - &exists_infeas, x_inf_sol, outputs_inf_sol, - NULL); + bool exists_feas = feasibleSolutionsFoundNomadResult(nomad_result) && + nb_solutions > 0; + loadInputSolutionsNomadResult(x_sol, 1, nomad_result); + loadOutputSolutionsNomadResult(outputs_sol, 1, nomad_result); // display found solutions if (exists_feas) @@ -126,24 +121,27 @@ int main(int argc, char **argv) printf("x_feas = [ "); for (int i = 0; i < nb_inputs; ++i) { - printf("%f ", x_feas_sol[i]); + printf("%f ", x_sol[i]); } printf(" ]\n"); printf("f_feas = "); - printf("%f \n", outputs_feas_sol[2]); + printf("%f \n", outputs_sol[2]); + printf("Constraints = [ %f %f %f ]\n", + outputs_sol[0], outputs_sol[1], outputs_sol[3]); } - - if (exists_infeas) // as a feasible solution has been found, no infeasible solution is given + else { printf("Best infeasible solution found (least infeasible with lowest f): \n"); printf("x_infeas = [ "); for (int i = 0; i < nb_inputs; ++i) { - printf("%f ", x_inf_sol[i]); + printf("%f ", x_sol[i]); } printf(" ]\n"); printf("f_infeas = "); - printf("%f \n", outputs_inf_sol[2]); + printf("%f \n", outputs_sol[2]); + printf("Constraints = [ %f %f %f ]\n", + outputs_sol[0], outputs_sol[1], outputs_sol[3]); } // NB: relaunch the problem will restart from the beginning @@ -152,13 +150,19 @@ int main(int argc, char **argv) printf("\n"); addNomadBoolParam(nomad_pb, "DISPLAY_ALL_EVAL", false); + // Set the dependant parameters to their default value + // Needed because they have been set in the previous run and are not reset by default + addNomadBoolParam(nomad_pb, "DISPLAY_INFEASIBLE", true); + addNomadBoolParam(nomad_pb, "DISPLAY_UNSUCCESSFUL", false); - exists_feas = false; - exists_infeas = false; - solveNomadProblem(nomad_pb, 1, x0, - &exists_feas, x_feas_sol, outputs_feas_sol, - &exists_infeas, x_inf_sol, outputs_inf_sol, - NULL); + run_flag = solveNomadProblem(nomad_result, nomad_pb, 1, x0, NULL); + printf("Run status: %d\n", run_flag); + + nb_solutions = nbSolutionsNomadResult(nomad_result); + exists_feas = feasibleSolutionsFoundNomadResult(nomad_result) && + nb_solutions > 1; + loadInputSolutionsNomadResult(x_sol, 1, nomad_result); + loadOutputSolutionsNomadResult(outputs_sol, 1, nomad_result); // display found solutions if (exists_feas) @@ -167,27 +171,31 @@ int main(int argc, char **argv) printf("x_feas = [ "); for (int i = 0; i < nb_inputs; ++i) { - printf("%f ", x_feas_sol[i]); + printf("%f ", x_sol[i]); } printf(" ]\n"); printf("f_feas = "); - printf("%f \n", outputs_feas_sol[2]); + printf("%f \n", outputs_sol[2]); + printf("c(x) = [ %f %f %f ]\n", + outputs_sol[0], outputs_sol[1], outputs_sol[3]); } - - if (exists_infeas) // as a feasible solution has been found, no infeasible solution is given + else { printf("Best infeasible solution found: \n"); printf("x_infeas = [ "); for (int i = 0; i < nb_inputs; ++i) { - printf("%f ", x_inf_sol[i]); + printf("%f ", x_sol[i]); } printf(" ]\n"); printf("f_infeas = "); - printf("%f \n", outputs_inf_sol[2]); + printf("%f \n", outputs_sol[2]); + printf("c(x) = [ %f %f %f ]\n", + outputs_sol[0], outputs_sol[1], outputs_sol[3]); } freeNomadProblem(nomad_pb); + freeNomadResult(nomad_result); return EXIT_SUCCESS; } diff --git a/examples/advanced/library/c_api/example2/CMakeLists.txt b/examples/advanced/library/c_api/example2/CMakeLists.txt index 1748f9d0..1d06831d 100644 --- a/examples/advanced/library/c_api/example2/CMakeLists.txt +++ b/examples/advanced/library/c_api/example2/CMakeLists.txt @@ -42,21 +42,4 @@ install(TARGETS example2_c_api.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add a test for this example -if(BUILD_EXAMPLES MATCHES ON) - message(STATUS " Add example test for c-api 2") - # Can run this test after install - - if (WIN32) -# MAYBE enable when script works for windows -# add_test(NAME ExampleAdvancedC-API2 -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./example2_c_api.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) - else() - add_test(NAME ExampleAdvancedC-API2 - COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./example2_c_api.exe - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) - endif() -endif() +# No test for this example \ No newline at end of file diff --git a/examples/advanced/library/c_api/example2/example2_c_api.c b/examples/advanced/library/c_api/example2/example2_c_api.c index 57cc6845..4f26c332 100644 --- a/examples/advanced/library/c_api/example2/example2_c_api.c +++ b/examples/advanced/library/c_api/example2/example2_c_api.c @@ -39,6 +39,7 @@ int solve_moustache_pb() // create Nomad problem NomadProblem nomad_pb = createNomadProblem(moustache_bb, + NULL, nb_inputs, nb_outputs); @@ -59,20 +60,23 @@ int solve_moustache_pb() // run problem double x0[2] = {0, 2.0}; // starting point - double x_feas_sol[2] = {0.0, 0.0}; // feasible solution - - double x_inf_sol[2] = {0.0, 0.0}; // infeasible solution - - double outputs_feas_sol[3] = {0.0, 0.0, 0.0}; // feasible solution outputs - - double outputs_inf_sol[3] = {0.0, 0.0, 0.0}; // infeasible solution outputs - - bool exists_feas, exists_infeas = false; // flag which indicates if the solution exists or not - - solveNomadProblem(nomad_pb, 1, x0, - &exists_feas, x_feas_sol, outputs_feas_sol, - &exists_infeas, x_inf_sol, outputs_inf_sol, - NULL); + NomadResult nomad_result = createNomadResult(); + int run_flag = solveNomadProblem(nomad_result, nomad_pb, 1, x0, NULL); + printf("Run status: %d\n", run_flag); + const int nb_solutions = nbSolutionsNomadResult(nomad_result); + const bool exists_feas = feasibleSolutionsFoundNomadResult(nomad_result); + printf("The solver has found %d solutions ", nb_solutions); + if (exists_feas) + { + printf("and they are feasible\n"); + } + else + { + printf("and they are infeasible\n"); + } + + freeNomadProblem(nomad_pb); + freeNomadResult(nomad_result); return 0; } @@ -127,6 +131,33 @@ bool speedreducer_bb(int nb_inputs, double *x, int nb_outputs, double *bb_output return true; } +void speedreducer_bb_block(int block_size, int nb_inputs, double *x, + int nb_outputs, double *bb_outputs, + bool *count_eval, bool *eval_ok, NomadUserDataPtr data) +{ + double *inputs = malloc(nb_inputs * sizeof(double)); + double *outputs = malloc(nb_outputs * sizeof(double)); + for (int index = 0; index < block_size; ++index) + { + for (int i = 0; i < nb_inputs; ++i) + { + inputs[i] = x[index * nb_inputs + i]; + } + // Call the blackbox on each element of the block + // There could be some applications where it is faster + // to parallelize the blocks + eval_ok[index] = speedreducer_bb(nb_inputs, inputs, + nb_outputs, outputs, + &count_eval[index], data); + for (int i = 0; i < nb_outputs; ++i) + { + bb_outputs[index * nb_outputs + i] = outputs[i]; + } + } + free(inputs); + free(outputs); +} + int solve_speedreducer_pb() { // fix essential parameters of the blackbox @@ -143,6 +174,7 @@ int solve_speedreducer_pb() // create Nomad problem NomadProblem nomad_pb = createNomadProblem(speedreducer_bb, + speedreducer_bb_block, dim, nb_outputs); @@ -163,6 +195,9 @@ int solve_speedreducer_pb() // set non opportunistic eval addNomadBoolParam(nomad_pb, "EVAL_OPPORTUNISTIC", false); + // Activate evaluation per block + addNomadValParam(nomad_pb, "BB_MAX_BLOCK_SIZE", 4); + // run problem double x0[7] = {3.000000000000000e+00, 7.500000000000000e-01, @@ -172,25 +207,30 @@ int solve_speedreducer_pb() 3.400000000000000e+00, 5.250000000000000e+00}; - double x_feas_sol[7] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // feasible solution - - double x_inf_sol[7] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // infeasible solution - - double outputs_feas_sol[12] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // feasible solution outputs - - double outputs_inf_sol[12] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // infeasible solution outputs - - bool exists_feas, exists_infeas = false; // flag which indicates if the solution exists or not - - solveNomadProblem(nomad_pb, 1, x0, - &exists_feas, x_feas_sol, outputs_feas_sol, - &exists_infeas, x_inf_sol, outputs_inf_sol, - NULL); + NomadResult nomad_result = createNomadResult(); + int run_flag = solveNomadProblem(nomad_result, + nomad_pb, 1, x0, + NULL); + printf("Run status: %d\n", run_flag); + const int nb_solutions = nbSolutionsNomadResult(nomad_result); + const bool exists_feas = feasibleSolutionsFoundNomadResult(nomad_result); + printf("The solver has found %d solutions ", nb_solutions); + if (exists_feas) + { + printf("and they are feasible\n\n"); + } + else + { + printf("and they are infeasible\n\n"); + } + + freeNomadProblem(nomad_pb); + freeNomadResult(nomad_result); return 0; } -int main(int argc, char **argv) +int main() { solve_moustache_pb(); solve_speedreducer_pb(); diff --git a/examples/advanced/library/c_api/example3/CMakeLists.txt b/examples/advanced/library/c_api/example3/CMakeLists.txt new file mode 100644 index 00000000..79089c08 --- /dev/null +++ b/examples/advanced/library/c_api/example3/CMakeLists.txt @@ -0,0 +1,45 @@ +add_executable(example3_c_api.exe example3_c_api.c) + +target_include_directories( + example3_c_api.exe + PRIVATE + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/interfaces/CInterface +) + +set_target_properties( + example3_c_api.exe + PROPERTIES + INSTALL_RPATH + "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" + SUFFIX "" +) + + +if(OpenMP_CXX_FOUND) + target_link_libraries( + example3_c_api.exe + PUBLIC + nomadCInterface + OpenMP::OpenMP_CXX + ) +else() + target_link_libraries( + example3_c_api.exe + PUBLIC nomadCInterface + ) +endif() + +if (NOT WIN32) + target_link_libraries( + example3_c_api.exe + PUBLIC m + ) +endif() + +# installing executables and libraries +install(TARGETS example3_c_api.exe + RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) + + +# No test for this example diff --git a/examples/advanced/library/c_api/example3/example3_c_api.c b/examples/advanced/library/c_api/example3/example3_c_api.c new file mode 100644 index 00000000..8fe7a312 --- /dev/null +++ b/examples/advanced/library/c_api/example3/example3_c_api.c @@ -0,0 +1,212 @@ +#include +#include +#include +#include + +#include "NomadStdCInterface.h" + +// A conceptual marine design problem +// See "An Easy-To-use Real-world Multi-objective Optimization Suite problem" +// by R. Tanabe and H. Ishibuchi +bool marine_design_bb(int nb_inputs, double *x, int nb_outputs, double *bb_outputs, bool *count_eval, NomadUserDataPtr data) +{ + bool eval_ok = true; + + // Variables + const double L = x[0]; + const double B = x[1]; + const double D = x[2]; + const double T = x[3]; + const double Vk = x[4]; + const double Cb = x[5]; + + // Parameters + const double handlingRate = 8000; + const double roundTripMiles = 5000; + const double fuelPrice = 100; + const double g = 9.8065; + + // Equations + const double verticalCenterOfBuoyancy = 0.53 * T; + const double metacentricRadius = (0.085 * Cb - 0.002) * B * B / (T * Cb); + const double verticalCenterOfGravity = 1 + 0.52 * D; + + const double displacement = 1.025 * L * B * T * Cb; + const double a = 4977.06 * Cb * Cb - 8105.61 * Cb + 4456.51; + const double b = -10847.2 * Cb * Cb + 12817 * Cb - 6960.32; + const double V = 0.5144 * Vk; + const double froudenumber = V / pow(g * L, 0.5); + const double P = pow(displacement, 2.0/3) * pow(Vk, 3) / (a + b * froudenumber); + + const double steelWeight = 0.034 * pow(L, 1.7) * pow(B, 0.7) * + pow(D, 0.4) * pow(Cb, 0.5); + const double outfitWeight = 1.0 * pow(L, 0.8) * pow(B, 0.6) * + pow(D, 0.3) * pow(Cb, 0.1); + const double machineryWeight = 0.17 * pow(P, 0.9); + const double lightShipWeight = steelWeight + outfitWeight + machineryWeight; + + const double deadweight = displacement - lightShipWeight; + + const double dailyConsumption = (0.19 * P * 24) / 1000 + 0.2; + const double seaDays = (roundTripMiles * Vk) / 24; + const double fuelCarried = dailyConsumption * (seaDays + 5); + const double portCost = 6.3 * pow(deadweight, 0.8); + + const double cargoDeadweight = deadweight - fuelCarried - 2 * pow(deadweight, 0.5); + const double portDays = 2 * (cargoDeadweight / handlingRate + 0.5); + const double roundTripsPerYear = 350.0 / (seaDays + portDays); + + const double fuelCost = 1.05 * dailyConsumption * seaDays * fuelPrice; + const double runningCosts = 40000 * pow(deadweight, 0.8); + const double voyageCosts = (fuelCost + portCost) * roundTripsPerYear; + const double shipCosts = 1.3 * (2000 * pow(steelWeight, 0.85) + + 3500 * outfitWeight + 2400 * pow(P, 0.8)); + const double capitalCosts = 0.2 * shipCosts; + const double annualCosts = capitalCosts + runningCosts + voyageCosts; + + const double annualCargo = - cargoDeadweight * roundTripsPerYear; + + // Objectives + const double f1 = annualCosts / annualCargo; + const double f2 = lightShipWeight; + const double f3 = annualCargo; + + // Constraints + const double g1 = L / B - 6.0; // >= 0 + const double g2 = 15.0 - L / D; // >= 0 + const double g3 = 19.0 - L / T; // >= 0 + const double g4 = 0.45 * pow(deadweight, 0.31) - T; // >= 0 + const double g5 = 0.7 * D + 0.7 - T; // >= 0 + const double g6 = deadweight - 3000; // >= 0 + const double g7 = 500000 - deadweight; // >= 0 + const double g8 = 0.32 - froudenumber; // >= 0 + const double g9 = verticalCenterOfBuoyancy + metacentricRadius - + verticalCenterOfGravity - 0.07 * B; // >= 0 + + // fix bb_outputs + bb_outputs[0] = f1; + bb_outputs[1] = f2; + bb_outputs[2] = f3; + bb_outputs[3] = -g1; + bb_outputs[4] = -g2; + bb_outputs[5] = -g3; + bb_outputs[6] = -g4; + bb_outputs[7] = -g5; + bb_outputs[8] = -g6; + bb_outputs[9] = -g7; + bb_outputs[10] = -g8; + bb_outputs[11] = -g9; + + *count_eval = true; + + return eval_ok; +} + +int solve_marine_design_pb() +{ + // fix essential parameters of the blackbox + int nb_inputs = 6; + int nb_outputs = 12; + char type_bb_outputs[] = "OBJ OBJ OBJ PB PB PB PB PB PB PB PB PB"; + + // the problem will terminate after 1500 evaluations + int max_bb_eval = 1500; + + // fix lower and upper bounds. + double lb[] = {150, 20, 13, 10, 14, 0.63}; + double ub[] = {274.32, 32.31, 25, 11.71, 18, 0.75}; + + // create Nomad problem + NomadProblem nomad_pb = createNomadProblem(marine_design_bb, + NULL, + nb_inputs, + nb_outputs); + + // Fix parameters without the NOMAD terminology + + // Main parameters + addNomadArrayOfDoubleParam(nomad_pb, "LOWER_BOUND", lb); + addNomadArrayOfDoubleParam(nomad_pb, "UPPER_BOUND", ub); + addNomadStringParam(nomad_pb, "BB_OUTPUT_TYPE", type_bb_outputs); + + addNomadValParam(nomad_pb, "MAX_BB_EVAL", max_bb_eval); + + // Display options + addNomadValParam(nomad_pb, "DISPLAY_DEGREE", 2); + addNomadBoolParam(nomad_pb, "DISPLAY_ALL_EVAL", false); + addNomadBoolParam(nomad_pb, "DISPLAY_UNSUCCESSFUL", false); + + // As we are in a multiobjective context, we need to explicitly + // set the choice of the algorithm used + addNomadBoolParam(nomad_pb, "DMULTIMADS_OPTIMIZATION", true); + + // For the multiobjective case, we cannot use ORTHO N+1 QUAD + addNomadParam(nomad_pb, "DIRECTION_TYPE ORTHO N+1 NEG"); + + // Here, deactivate QUAD_MODEL_SEARCH + addNomadBoolParam(nomad_pb, "QUAD_MODEL_SEARCH", false); + + // Change options for NM strategy + addNomadStringParam(nomad_pb, "DMULTIMADS_NM_STRATEGY", "MULTI"); + + // A line initialization is practically more efficient than giving a single point for + // multiobjective optimization. + // The interesting reader can report to the following reference for more information. + // Direct Multisearch for multiobjective optimization + // by A.L. Custodio, J.F.A. Madeira, A.I.F. Vaz and L.N. Vicente, 2011. + double x0s[6 * 6]; // starting points + for (size_t j = 0; j < nb_inputs; ++j) + { + for (size_t i = 0; i < nb_inputs; ++i) + { + x0s[j * nb_inputs + i] = lb[i] + (double) j * (ub[i] - lb[i]) / (nb_inputs - 1); + } + } + + // Run problem + NomadResult nomad_result = createNomadResult(); + int run_flag = solveNomadProblem(nomad_result, nomad_pb, + nb_inputs, x0s, NULL); + printf("Run status: %d\n", run_flag); + const int nb_solutions = nbSolutionsNomadResult(nomad_result); + const bool exists_feas = feasibleSolutionsFoundNomadResult(nomad_result); + printf("The solver has found %d solutions ", nb_solutions); + if (exists_feas) + { + printf("and they are feasible\n"); + } + else + { + printf("and they are infeasible\n"); + } + + double* x_solutions = malloc(nb_inputs * nb_solutions * sizeof(double)); + double* output_solutions = malloc(nb_outputs * nb_solutions * sizeof(double)); + loadInputSolutionsNomadResult(x_solutions, nb_solutions, nomad_result); + loadOutputSolutionsNomadResult(output_solutions, nb_solutions, nomad_result); + printf("Solutions:\n"); + for (int index = 0; index < nb_solutions; ++index) + { + printf("sol %d: x = [", index+1); + for (int i = 0; i < nb_inputs; ++i) + { + printf(" %f", x_solutions[index * nb_inputs + i]); + } + printf("]; f = [%f %f %f]\n", + output_solutions[index * nb_outputs], + output_solutions[index * nb_outputs + 1], + output_solutions[index * nb_outputs + 2]); + } + + free(x_solutions); + free(output_solutions); + freeNomadProblem(nomad_pb); + freeNomadResult(nomad_result); + return 0; +} + +int main() +{ + solve_marine_design_pb(); + return EXIT_SUCCESS; +} diff --git a/examples/advanced/library/exampleSuggestAndObserve/loopSuggestAndObserve.cpp b/examples/advanced/library/exampleSuggestAndObserve/loopSuggestAndObserve.cpp index bf9dbd01..8d10af91 100644 --- a/examples/advanced/library/exampleSuggestAndObserve/loopSuggestAndObserve.cpp +++ b/examples/advanced/library/exampleSuggestAndObserve/loopSuggestAndObserve.cpp @@ -88,7 +88,11 @@ bool eval_xs(const NOMAD::ArrayOfPoint &xs, std::vector& f return eval_ok; } -void initParams(std::shared_ptr& params, const std::string & cacheFileName, const std::string & initialFrameSizeAsString, const std::string & hmax0AsString, bool useCacheAndMegaSearchPoll ) +void initParams(const std::shared_ptr& params, + const std::string& cacheFileName, + const std::string& initialFrameSizeAsString, + const std::string& hmax0AsString, + bool useCacheAndMegaSearchPoll) { // Problem parameters params->setAttributeValue("DIMENSION", 2); // number of variables @@ -96,7 +100,7 @@ void initParams(std::shared_ptr& params, const std::string params->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(2, 10.0)); NOMAD::BBOutputTypeList bbot; // Definition of output types - bbot.push_back(NOMAD::BBOutputType::Type::OBJ); + bbot.emplace_back(NOMAD::BBOutputType::Type::OBJ); params->setAttributeValue("BB_OUTPUT_TYPE", bbot); if (! useCacheAndMegaSearchPoll) @@ -128,12 +132,10 @@ void initParams(std::shared_ptr& params, const std::string } - - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main(int argc, char ** argv) +int main() { try { @@ -168,7 +170,7 @@ int main(int argc, char ** argv) // MainStep runs suggest auto xs = SuggestMainStep->suggest(); - if (0 == xs.size()) + if (xs.empty()) { std::cout << "No more points to suggest at iteration " << iterationCount << "." << std::endl; // Could not suggest any more points. Break. @@ -184,7 +186,6 @@ int main(int argc, char ** argv) //THIS IS IMPORTANT (see comments in function) NOMAD::MainStep::resetCache(); - // Parameters creation (important to create a fresh one because Suggest modifies its params (X0 from cache)) auto paramsForObservePtr = std::make_shared(); @@ -214,7 +215,7 @@ int main(int argc, char ** argv) paramsForObservePtr.reset(); std::cout << "Updated parameters: " << std::endl; - for (auto p : updatedParams) + for (const auto& p : updatedParams) { std::cout << p << std::endl; NOMAD::ParameterEntry pe(p); diff --git a/examples/advanced/library/exampleSuggestAndObserve/suggestAndObserve.cpp b/examples/advanced/library/exampleSuggestAndObserve/suggestAndObserve.cpp index 3a7bca1e..9da5d9f2 100644 --- a/examples/advanced/library/exampleSuggestAndObserve/suggestAndObserve.cpp +++ b/examples/advanced/library/exampleSuggestAndObserve/suggestAndObserve.cpp @@ -96,7 +96,7 @@ void initParams(std::shared_ptr& params, const std::string params->setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(2, 10.0)); NOMAD::BBOutputTypeList bbot; // Definition of output types - bbot.push_back(NOMAD::BBOutputType::Type::OBJ); + bbot.emplace_back(NOMAD::BBOutputType::Type::OBJ); params->setAttributeValue("BB_OUTPUT_TYPE", bbot); @@ -114,12 +114,10 @@ void initParams(std::shared_ptr& params, const std::string } - - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main(int argc, char ** argv) +int main() { try { @@ -154,7 +152,7 @@ int main(int argc, char ** argv) std::cout << paramName << " ( " << paramsForObserve->getAttributeValue(paramName) << " )" << std::endl; auto updateParams = ObserveMainStep->observe(xs,fxs,"cache1.txt"); std::cout << "Updated parameters: " << std::endl; - for (auto p : updateParams) + for (const auto& p : updateParams) { std::cout << p << std::endl; } diff --git a/examples/basic/batch/MatlabBB/paramNomad.txt b/examples/basic/batch/MatlabBB/paramNomad.txt index 12f01bc0..83c1e39d 100644 --- a/examples/basic/batch/MatlabBB/paramNomad.txt +++ b/examples/basic/batch/MatlabBB/paramNomad.txt @@ -1,21 +1,21 @@ dimension 5 -# WARNING: The command to run matlab in batch mode may vary with Matlab version and OS. -# The given bat (bb.bat) command has been tested with Matlab 2021b on Windows. -# - To make sure the command works properly with your Matlab version, start a Windows shell command terminal. -# - Go into the directory of this example -# - Test the following command: bb.bat X0.txt -# - Matlab should start in background and run the 'fun.m' function. -# - The command should display '4 -10 -30', that is the objective and constraints values for X0. -# - When the blackbox Matlab command is working you can run Nomad on it. -# -# The given shell script command (bb.sh) has been tested with Matlab 2022a on OSX and Linux -# - To test the command, go into the directory of this example -# - Run the command: ./bb.sh X0.txt -# - The command should display '4 -10 -30', that is the objective and constraints values for X0. +% WARNING: The command to run matlab in batch mode may vary with Matlab version and OS. +% The given bat (bb.bat) command has been tested with Matlab 2021b on Windows. +% - To make sure the command works properly with your Matlab version, start a Windows shell command terminal. +% - Go into the directory of this example +% - Test the following command: bb.bat X0.txt +% - Matlab should start in background and run the 'fun.m' function. +% - The command should display '4 -10 -30', that is the objective and constraints values for X0. +% - When the blackbox Matlab command is working you can run Nomad on it. +% +% The given shell script command (bb.sh) has been tested with Matlab 2022a on OSX and Linux +% - To test the command, go into the directory of this example +% - Run the command: ./bb.sh X0.txt +%. - The command should display '4 -10 -30', that is the objective and constraints values for X0. -bb_exe bb.sh # for linux/osx -# bb_exe bb.bat # for windows is a cmd prompt windows +# bb_exe bb.sh # for linux/osx +bb_exe bb.bat # for windows is a cmd prompt windows @@ -27,6 +27,6 @@ display_degree 2 display_stats BBE ( SOL ) BBO display_all_eval yes -max_bb_eval 50 +max_bb_eval 5 bb_output_type OBJ PB PB diff --git a/examples/basic/batch/PythonBB/param.txt b/examples/basic/batch/PythonBB/param.txt index 33dc7c4b..88f834b0 100755 --- a/examples/basic/batch/PythonBB/param.txt +++ b/examples/basic/batch/PythonBB/param.txt @@ -1,6 +1,6 @@ DIMENSION 5 -BB_EXE '$python bb.py ' # '$python3 bb.py ' +BB_EXE '$python3 bb.py ' BB_OUTPUT_TYPE OBJ PB EB X0 ( 0 0 0 0 0 ) diff --git a/examples/basic/batch/example1/CMakeLists.txt b/examples/basic/batch/example1/CMakeLists.txt index 14cbcbfc..1445f8c9 100644 --- a/examples/basic/batch/example1/CMakeLists.txt +++ b/examples/basic/batch/example1/CMakeLists.txt @@ -6,6 +6,7 @@ set_target_properties(bb1.exe PROPERTIES SUFFIX "") install(TARGETS bb1.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) + # Add a test for this example message(STATUS " Add example batch #1") diff --git a/examples/basic/batch/example1/param.txt b/examples/basic/batch/example1/param.txt index bb23c412..5a91ec33 100644 --- a/examples/basic/batch/example1/param.txt +++ b/examples/basic/batch/example1/param.txt @@ -30,11 +30,6 @@ MAX_BB_EVAL 1000 # including cache hits MAX_EVAL 200 -# Parameters for display -DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL 1 -DISPLAY_STATS BBE ( SOL ) OBJ CONS_H - # Formatted stats into a file #STATS_FILE stats.txt BBE SOL OBJ @@ -44,4 +39,3 @@ DISPLAY_STATS BBE ( SOL ) OBJ CONS_H # Solution file (just best inputs found) #SOLUTION_FILE sol.txt - diff --git a/examples/advanced/batch/UseCacheFileForRerun/paramNextStep.txt b/examples/basic/batch/example1/param_COOPMads.txt similarity index 53% rename from examples/advanced/batch/UseCacheFileForRerun/paramNextStep.txt rename to examples/basic/batch/example1/param_COOPMads.txt index 311a5585..c033ca3d 100644 --- a/examples/advanced/batch/UseCacheFileForRerun/paramNextStep.txt +++ b/examples/basic/batch/example1/param_COOPMads.txt @@ -6,7 +6,7 @@ DIMENSION 10 # Black box -BB_EXE bb_cache.exe +BB_EXE bb1.exe BB_OUTPUT_TYPE OBJ PB PB PB # Starting point @@ -17,25 +17,31 @@ LOWER_BOUND * -20.0 UPPER_BOUND * 20.0 - # ALGORITHM PARAMETERS ###################### -# The algorithm terminates after that number black-box evaluations -MAX_BB_EVAL 150 +COOP_MADS_OPTIMIZATION yes -# If cache.txt exits it will be used. -# Possible Use Case: -# - first run (no cache file) with max_bb_eval 100. Cache file is created -# - increase max_bb_eval to 150. -# - second run uses the first 100 in the cache file and continues with real bb evals to reach 150 -USE_CACHE_FILE_FOR_RERUN true -CACHE_FILE cache.txt +# For now let us consider the same number of threads and coop mads problem +COOP_MADS_NB_PROBLEM 2 + +COOP_MADS_OPTIMIZATION_CACHE_SEARCH yes + +QUAD_MODEL_SEARCH no +NM_SEARCH no +SPECULATIVE_SEARCH no +DIRECTION_TYPE ORTHO 2n -# Parameters for display DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL 1 -DISPLAY_STATS BBE ( SOL ) OBJ CONS_H +# The algorithm terminates after that number black-box evaluations +MAX_BB_EVAL 1000 + + +# Parameters for display +DISPLAY_ALL_EVAL 1 +DISPLAY_STATS BBE THREAD_NUM THREAD_ALGO ( SOL ) OBJ +#STATS_FILE stats.txt BBE SOL OBJ + diff --git a/examples/basic/batch/example1/param_LH.txt b/examples/basic/batch/example1/param_LH.txt new file mode 100644 index 00000000..87da9e4f --- /dev/null +++ b/examples/basic/batch/example1/param_LH.txt @@ -0,0 +1,45 @@ + +# PROBLEM PARAMETERS +#################### + +# Number of variables +DIMENSION 10 + +# Black box +BB_EXE bb1.exe +BB_OUTPUT_TYPE OBJ PB PB PB + +# Starting point +# X0 ( 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 ) + +# Bounds for variables +LOWER_BOUND * -10 +UPPER_BOUND * 20 + +# All variables must be multiple of 0.0001 +GRANULARITY * 0.0001 + + +# ALGORITHM PARAMETERS +###################### + +# The algorithm terminates after that number black-box evaluations +MAX_BB_EVAL 1000 + +# The algorithm terminates after that total number of evaluations, +# including cache hits +MAX_EVAL 1100 + +# Latin Hypercube Search parameters +LH_SEARCH 100 10 + + +# DISPLAY PARAMETERS +#################### +DISPLAY_DEGREE 2 +DISPLAY_INFEASIBLE true +DISPLAY_STATS BBE EVAL ( SOL ) OBJ CONS_H H_MAX +#STATS_FILE stats.txt BBE SOL OBJ + + + diff --git a/examples/basic/batch/example1/param_LH_ONLY.txt b/examples/basic/batch/example1/param_LH_ONLY.txt new file mode 100644 index 00000000..4979577a --- /dev/null +++ b/examples/basic/batch/example1/param_LH_ONLY.txt @@ -0,0 +1,27 @@ + +# PROBLEM PARAMETERS +#################### + +# Number of variables +DIMENSION 10 + +# Black box +BB_EXE bb1.exe +BB_OUTPUT_TYPE OBJ PB PB EB + +# Starting point +X0 ( 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 ) + +LOWER_BOUND * 0.0 +UPPER_BOUND * 10.0 + + +# ALGORITHM PARAMETERS +###################### + +LH_EVAL 10 # Enabling LH eval disables default Mads optimization + +# Parameters for display +DISPLAY_DEGREE 3 +DISPLAY_STATS BBE ( SOL ) OBJ + diff --git a/examples/basic/batch/example2/param_NM.txt b/examples/basic/batch/example1/param_NM.txt similarity index 57% rename from examples/basic/batch/example2/param_NM.txt rename to examples/basic/batch/example1/param_NM.txt index b215562a..70b59812 100644 --- a/examples/basic/batch/example2/param_NM.txt +++ b/examples/basic/batch/example1/param_NM.txt @@ -3,18 +3,15 @@ #################### # Number of variables -DIMENSION 5 +DIMENSION 10 # Black box -BB_EXE bb2.exe -BB_OUTPUT_TYPE OBJ PB PB +BB_EXE bb1.exe +BB_OUTPUT_TYPE OBJ PB PB PB # Starting point -X0 ( 0 0 0 0 0 ) +X0 ( 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 ) -LOWER_BOUND * -6 # 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 # ALGORITHM PARAMETERS ###################### @@ -23,11 +20,12 @@ UPPER_BOUND ( 5 6 7 - - ) # x_1 <= 5, x_2 <= 6, x_3 <= 7 NM_OPTIMIZATION true # The algorithm terminates after that number black-box evaluations -MAX_BB_EVAL 400 +MAX_BB_EVAL 1000 + # DISPLAY PARAMETERS #################### # Show more info - display degree = 3 -DISPLAY_DEGREE 3 -DISPLAY_MAX_STEP_LEVEL 10 +DISPLAY_STATS BBE ( SOL ) OBJ CONS_H #STATS_FILE stats.txt BBE SOL OBJ + diff --git a/examples/basic/batch/example1/x0.txt b/examples/basic/batch/example1/x0.txt new file mode 100644 index 00000000..06af1ce9 --- /dev/null +++ b/examples/basic/batch/example1/x0.txt @@ -0,0 +1 @@ +5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 diff --git a/examples/basic/batch/example2/param.txt b/examples/basic/batch/example2/param.txt index 457c150b..0ecc1b65 100644 --- a/examples/basic/batch/example2/param.txt +++ b/examples/basic/batch/example2/param.txt @@ -24,17 +24,14 @@ MAX_BB_EVAL 1000 MEGA_SEARCH_POLL true # Generate search and poll steps trial points before starting evaluation -NB_THREADS_OPENMP 4 # Number of threads to perform blackbox evaluation - # This requires to have Nomad built with OpenMP (see $NOMAD_HOME/README.txt) - # With this parameter, the default thread number (1) is replaced. +NB_THREADS_PARALLEL_EVAL 4 # Number of threads to perform blackbox evaluation + # This requires to have Nomad built with OpenMP (see $NOMAD_HOME/README.txt) + # With this parameter, the default thread number (1) is replaced. # The algorithm terminates after that total number of evaluations, # including cache hits MAX_EVAL 200 -QUAD_MODEL_SEARCH no -DIRECTION_TYPE ORTHO 2N - # DISPLAY PARAMETERS #################### DISPLAY_DEGREE 2 diff --git a/examples/basic/batch/multi_obj/param.txt b/examples/basic/batch/multi_obj/param.txt index 5d374817..749f6d03 100644 --- a/examples/basic/batch/multi_obj/param.txt +++ b/examples/basic/batch/multi_obj/param.txt @@ -23,12 +23,12 @@ DMULTIMADS_OPTIMIZATION yes # For multiobjctive, sort should not use the default quad model info EVAL_QUEUE_SORT DIR_LAST_SUCCESS -# Let's deactivate all default search methods +# Let's deactivate all default search methods except NM (prototype) # and do ORTHO 2n for more intense poll (default is n+1) DIRECTION_TYPE ORTHO 2n QUAD_MODEL_SEARCH no -NM_SEARCH no SPECULATIVE_SEARCH no +DMULTIMADS_NM_STRATEGY MULTI DISPLAY_DEGREE 2 DISPLAY_ALL_EVAL yes diff --git a/examples/basic/batch/multi_obj/x.txt b/examples/basic/batch/multi_obj/x.txt new file mode 100644 index 00000000..0b3eef12 --- /dev/null +++ b/examples/basic/batch/multi_obj/x.txt @@ -0,0 +1 @@ +2.0 2.0 diff --git a/examples/basic/batch/multi_obj2/CMakeLists.txt b/examples/basic/batch/multi_obj2/CMakeLists.txt index 2814ea58..5c15976c 100644 --- a/examples/basic/batch/multi_obj2/CMakeLists.txt +++ b/examples/basic/batch/multi_obj2/CMakeLists.txt @@ -7,10 +7,4 @@ set_target_properties(bbMO2.exe PROPERTIES SUFFIX "") install(TARGETS bbMO2.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add a test for this example -message(STATUS " Add example batch multi_obj 2") - -# Test run in working directory AFTER install of bb.exe executable -add_test(NAME ExampleMultiObj2BasicBatch - COMMAND ${CMAKE_INSTALL_PREFIX}/bin/nomad param.txt - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) +# No test for this example \ No newline at end of file diff --git a/examples/basic/batch/multi_obj2/param.txt b/examples/basic/batch/multi_obj2/param.txt index 3af84d82..9424656a 100644 --- a/examples/basic/batch/multi_obj2/param.txt +++ b/examples/basic/batch/multi_obj2/param.txt @@ -25,7 +25,6 @@ NM_SEARCH no SPECULATIVE_SEARCH no DISPLAY_DEGREE 2 -DISPLAY_ALL_EVAL yes DISPLAY_STATS BBE ( SOL ) BBO # Display the number of evaluation (BBE), # the current solution ( SOL ) and the objectives diff --git a/examples/basic/batch/multi_obj2/param_testQMS.txt b/examples/basic/batch/multi_obj2/param_testQMS.txt new file mode 100644 index 00000000..d83a073e --- /dev/null +++ b/examples/basic/batch/multi_obj2/param_testQMS.txt @@ -0,0 +1,40 @@ +DIMENSION 3 # number of variables + + +BB_EXE bbMO2.exe +BB_OUTPUT_TYPE OBJ OBJ + +X0 ( 0 0 0 ) # starting point + +LOWER_BOUND * -5 +UPPER_BOUND * 5 + +MAX_BB_EVAL 1000 + +# DMultiMads is enabled (default Mads is disabled) +DMULTIMADS_OPTIMIZATION yes +DMULTIMADS_QUAD_DMS_SEARCH yes +DMULTIMADS_QUAD_MODEL_SEARCH no +DMULTIMADS_QMS_PRIOR_COMBINE_OBJ no + +# For multiobjctive, sort should not use the default quad model info +EVAL_QUEUE_SORT DIR_LAST_SUCCESS + +# Let's deactivate all default search methods +# and do ORTHO n+1 Neg (Neg is for disabling quad model (n+1)th direction) +DIRECTION_TYPE ORTHO n+1 neg +QUAD_MODEL_SEARCH no +NM_SEARCH no +SPECULATIVE_SEARCH no + +DISPLAY_DEGREE 2 +DISPLAY_STATS BBE ( SOL ) BBO # Display the number of evaluation (BBE), + # the current solution ( SOL ) and the objectives + + +SOLUTION_FILE sol.txt # Write the approximated Pareto points + # in a file during the run + + +HISTORY_FILE history.txt + diff --git a/examples/basic/batch/multi_obj2/x.txt b/examples/basic/batch/multi_obj2/x.txt new file mode 100644 index 00000000..0b3eef12 --- /dev/null +++ b/examples/basic/batch/multi_obj2/x.txt @@ -0,0 +1 @@ +2.0 2.0 diff --git a/examples/basic/batch/single_obj/CMakeLists.txt b/examples/basic/batch/single_obj/CMakeLists.txt deleted file mode 100644 index af96eefc..00000000 --- a/examples/basic/batch/single_obj/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(CMAKE_EXECUTABLE_SUFFIX .exe) -add_executable(bb.exe bb.cpp ) -set_target_properties(bb.exe PROPERTIES SUFFIX "") - - -# installing executables and libraries -install(TARGETS bb.exe - RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) - -# Add a test for this example -message(STATUS " Add example batch single_obj") - -# Test run in working directory AFTER install of bb.exe executable -add_test(NAME ExampleSingleObjBasicBatch - COMMAND ${CMAKE_INSTALL_PREFIX}/bin/nomad param.txt - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/examples/basic/batch/single_obj/param.txt b/examples/basic/batch/single_obj/param.txt deleted file mode 100644 index f3a60f61..00000000 --- a/examples/basic/batch/single_obj/param.txt +++ /dev/null @@ -1,40 +0,0 @@ -DIMENSION 5 # number of variables - - -BB_EXE bb.exe # 'bb.exe' is a program that -BB_OUTPUT_TYPE OBJ PB EB # takes in argument the name of - # a text file containing 5 - # values, and that displays 3 - # values that correspond to the - # objective function value (OBJ), - # and two constraints values g1 - # and g2 with g1 <= 0 and - # g2 <= 0; 'PB' and 'EB' - # correspond to constraints that - # are treated by the Progressive - # and Extreme Barrier approaches - # (all constraint-handling - # options are described in the - # detailed parameters list) - -X0 ( 0 0 0 0 0 ) # starting point - -LOWER_BOUND * -6 # 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 # indicates a directory where - # temporary files are put - # (increases performance by ~100% - # if you're working on a network - # account and if TMP_DIR is on a - # local disk) - -DISPLAY_DEGREE 2 -DISPLAY_STATS BBE ( SOL ) OBJ CONS_H # Display the number of evaluation (BBE), - # the current solution ( SOL ) and the objective -DISPLAY_INFEASIBLE yes # Allow to display infeasible solution during PhaseOne diff --git a/examples/basic/batch/single_obj/x.txt b/examples/basic/batch/single_obj/x.txt deleted file mode 100644 index 88b14b24..00000000 --- a/examples/basic/batch/single_obj/x.txt +++ /dev/null @@ -1 +0,0 @@ -0 0 0 0 0 diff --git a/examples/basic/batch/single_obj_MPIparallel/param.txt b/examples/basic/batch/single_obj_MPIparallel/param.txt index 8c20a406..e18b2896 100644 --- a/examples/basic/batch/single_obj_MPIparallel/param.txt +++ b/examples/basic/batch/single_obj_MPIparallel/param.txt @@ -1,16 +1,17 @@ DIMENSION 5 # number of variables -BB_EXE '$mpirun $-np $4 bb4.exe' # WARNING Adjust the path to mpirun +BB_EXE '$/opt/homebrew/bin/mpirun $-np $4 bb4.exe' # WARNING Adjust the path to mpirun # or mpiexec according to your setup. -BB_MAX_BLOCK_SIZE 20 # At most, 20 points are put in a block for evaluation +BB_MAX_BLOCK_SIZE 20 MEGA_SEARCH_POLL yes # Generate search and poll trial points before evaluation - # Max points put in box. Without this option, single point + # Max points put in block. Without this option, single point # can be passed in a block for evaluation creating a bottleneck. DIRECTION_TYPE ORTHO 2N # Single pass for generating poll trial points # Better to have more points in blocks + BB_OUTPUT_TYPE OBJ PB PB X0 ( 0 0 0 0 0 ) # starting point diff --git a/examples/basic/batch/single_obj_parallel/CMakeLists.txt b/examples/basic/batch/single_obj_parallel/CMakeLists.txt index 742e2226..13f6becf 100644 --- a/examples/basic/batch/single_obj_parallel/CMakeLists.txt +++ b/examples/basic/batch/single_obj_parallel/CMakeLists.txt @@ -1,11 +1,11 @@ set(CMAKE_EXECUTABLE_SUFFIX .exe) -add_executable(bb3.exe bb.cpp ) -set_target_properties(bb3.exe PROPERTIES SUFFIX "") +add_executable(bb_s.exe bb.cpp ) +set_target_properties(bb_s.exe PROPERTIES SUFFIX "") -target_link_libraries(bb3.exe PUBLIC OpenMP::OpenMP_CXX) +target_link_libraries(bb_s.exe PUBLIC OpenMP::OpenMP_CXX) # installing executables and libraries -install(TARGETS bb3.exe +install(TARGETS bb_s.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) # Add a test for this example diff --git a/examples/basic/batch/single_obj_parallel/param.txt b/examples/basic/batch/single_obj_parallel/param.txt index 5368fcdf..c1582694 100644 --- a/examples/basic/batch/single_obj_parallel/param.txt +++ b/examples/basic/batch/single_obj_parallel/param.txt @@ -1,6 +1,6 @@ DIMENSION 5 # number of variables -BB_EXE bb3.exe +BB_EXE bb_s.exe BB_MAX_BLOCK_SIZE 4 diff --git a/examples/basic/batch/surrogate_sort/CMakeLists.txt b/examples/basic/batch/surrogate_sort/CMakeLists.txt index 1cacbec9..6e91fee3 100644 --- a/examples/basic/batch/surrogate_sort/CMakeLists.txt +++ b/examples/basic/batch/surrogate_sort/CMakeLists.txt @@ -7,10 +7,4 @@ set_target_properties(ss_sgte.exe PROPERTIES SUFFIX "") install(TARGETS ss_bb.exe ss_sgte.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add a test for this example -message(STATUS " Add example batch surrogate sort") - -# Test run in working directory AFTER install of bb executable -add_test(NAME ExampleSurrogateSortBasicBatch - COMMAND ${CMAKE_INSTALL_PREFIX}/bin/nomad param.txt - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) +# No test for this example diff --git a/examples/basic/batch/surrogate_sort/param.txt b/examples/basic/batch/surrogate_sort/param.txt index 5a33a8db..1c17a49c 100644 --- a/examples/basic/batch/surrogate_sort/param.txt +++ b/examples/basic/batch/surrogate_sort/param.txt @@ -28,9 +28,6 @@ MAX_BB_EVAL 100 # Use surrogate executable to sort points before evaluating them with the blackbox EVAL_QUEUE_SORT SURROGATE -# Using only one thread for clarity and reproducibility -NB_THREADS_OPENMP 1 - # Display parameters #################### DISPLAY_DEGREE 2 diff --git a/examples/basic/batch/surrogate_sort/param_surrogateOptim.txt b/examples/basic/batch/surrogate_sort/param_surrogateOptim.txt index 1bf29a09..f07fb5c5 100644 --- a/examples/basic/batch/surrogate_sort/param_surrogateOptim.txt +++ b/examples/basic/batch/surrogate_sort/param_surrogateOptim.txt @@ -23,10 +23,9 @@ UPPER_BOUND * 20.0 # The algorithm terminates after that number surrogate evaluations MAX_SURROGATE_EVAL_OPTIMIZATION 100 -# Use surrogate evaluation for optimization +# Use surrogate evaluation for optimization EVAL_SURROGATE_OPTIMIZATION yes - # Display parameters #################### DISPLAY_ALL_EVAL true diff --git a/examples/basic/library/CustomSurrogateOrdering/CMakeLists.txt b/examples/basic/library/CustomSurrogateOrdering/CMakeLists.txt index 24c9d7d9..177f7546 100644 --- a/examples/basic/library/CustomSurrogateOrdering/CMakeLists.txt +++ b/examples/basic/library/CustomSurrogateOrdering/CMakeLists.txt @@ -17,19 +17,4 @@ install(TARGETS customSurrogateOrdering.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add test for this example -#if(BUILD_TESTS MATCHES ON) -# message(STATUS " Add example test for custom ordering of points before evaluation") -# # Can run this test after install -# if (WIN32) -# add_test(NAME ExampleAdvancedcustomSurrogateOrdering -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./customSurrogateOrdering.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# else() -# add_test(NAME ExampleAdvancedcustomSurrogateOrdering -# COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./customSurrogateOrdering.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# endif() -#endif() +# No test for this example \ No newline at end of file diff --git a/examples/basic/library/CustomSurrogateOrdering/customSurrogateOrdering.cpp b/examples/basic/library/CustomSurrogateOrdering/customSurrogateOrdering.cpp index f17e2eac..19b785ce 100644 --- a/examples/basic/library/CustomSurrogateOrdering/customSurrogateOrdering.cpp +++ b/examples/basic/library/CustomSurrogateOrdering/customSurrogateOrdering.cpp @@ -64,11 +64,11 @@ class My_Evaluator : public NOMAD::Evaluator private: public: - My_Evaluator(const std::shared_ptr& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; }; @@ -105,11 +105,11 @@ bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, class My_Surrogate_Evaluator : public NOMAD::Evaluator { public: - My_Surrogate_Evaluator(const std::shared_ptr& evalParams) + explicit My_Surrogate_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::SURROGATE) {} - ~My_Surrogate_Evaluator() {} + ~My_Surrogate_Evaluator() override = default; std::vector eval_block(NOMAD::Block &block, const NOMAD::Double &hMax, @@ -127,22 +127,20 @@ std::vector My_Surrogate_Evaluator::eval_block(NOMAD::Block &block, NOMAD::Point P0(n, 0); // Start evaluation - for (auto it = block.begin(); it != block.end(); it++) + for (auto & it : block) { // Use distance to P0 for objective - NOMAD::Double d = NOMAD::Point::dist(P0, *(*it)->getX()); + NOMAD::Double d = NOMAD::Point::dist(P0, *it->getX()); std::string bbo = d.tostring(); bbo += " 0.0 0.0"; // Both constraints are feasible - (*it)->setBBO(bbo); + it->setBBO(bbo); } return success; } - - -void initAllParams(std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { // Parameters creation allParams->setAttributeValue("DIMENSION", n); @@ -150,7 +148,7 @@ void initAllParams(std::shared_ptr allParams) // Starting point allParams->setAttributeValue("X0", NOMAD::Point(n, 0.0) ); - // Bounds + // Set bounds allParams->setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(n, -6.0 )); // all var. >= -6 NOMAD::ArrayOfDouble ub(n); ub[0] = 5.0; // x_1 <= 5 @@ -160,9 +158,9 @@ void initAllParams(std::shared_ptr allParams) // Constraints and objective NOMAD::BBOutputTypeList bbOutputTypes; - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::OBJ); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::PB); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::PB); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::OBJ); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::PB); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::PB); allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); // Use surrogate for sorting @@ -175,25 +173,21 @@ void initAllParams(std::shared_ptr allParams) allParams->setAttributeValue("NM_SEARCH", false); allParams->setAttributeValue("DIRECTION_TYPE", NOMAD::DirectionType::ORTHO_NP1_NEG); - + // Set display parameters allParams->setAttributeValue("DISPLAY_DEGREE", 2); allParams->setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("bbe ( sol ) obj")); allParams->setAttributeValue("DISPLAY_ALL_EVAL", true); // Parameters validation requested to have access to their value. allParams->checkAndComply(); - } - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) +int main() { - - NOMAD::MainStep TheMainStep; // Set parameters @@ -208,7 +202,7 @@ int main ( int argc , char ** argv ) // Custom SURROGATE evaluator creation auto evSurrogate = std::make_unique(params->getEvalParams()); TheMainStep.addEvaluator(std::move(evSurrogate)); - // Warning: Need to set ordering with surrogate to use the surrogate. See EVAL_QUEUE_SORT parameter set above. + // Warning: Need to set ordering with surrogate to use the surrogate. See EVAL_QUEUE_SORT parameter set above // The run TheMainStep.start(); diff --git a/examples/basic/library/StopOnFTarget/CMakeLists.txt b/examples/basic/library/StopOnFTarget/CMakeLists.txt index 4b74e770..4063438f 100644 --- a/examples/basic/library/StopOnFTarget/CMakeLists.txt +++ b/examples/basic/library/StopOnFTarget/CMakeLists.txt @@ -17,19 +17,4 @@ install(TARGETS stopOnFTarget.exe RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) -# Add test for this example -#if(BUILD_TESTS MATCHES ON) -# message(STATUS " Add example test for handling stop if F hit target") -# # Can run this test after install -# if (WIN32) -# add_test(NAME ExampleAdvancedstopOnFTarget -# COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./stopOnFTarget.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# else() -# add_test(NAME ExampleAdvancedstopOnFTarget -# COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./stopOnFTarget.exe -# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# ) -# endif() -#endif() +# No test for this example \ No newline at end of file diff --git a/examples/basic/library/StopOnFTarget/stopOnFTarget.cpp b/examples/basic/library/StopOnFTarget/stopOnFTarget.cpp index 5bd299cd..ea2c29da 100644 --- a/examples/basic/library/StopOnFTarget/stopOnFTarget.cpp +++ b/examples/basic/library/StopOnFTarget/stopOnFTarget.cpp @@ -62,11 +62,11 @@ class My_Evaluator : public NOMAD::Evaluator private: public: - My_Evaluator(const std::shared_ptr& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override; }; @@ -98,9 +98,8 @@ bool My_Evaluator::eval_x(NOMAD::EvalPoint &x, return true; // the evaluation succeeded } -void initAllParams(std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { - const size_t n = 5; // Parameters creation @@ -119,10 +118,10 @@ void initAllParams(std::shared_ptr allParams) // Constraints and objective NOMAD::BBOutputTypeList bbOutputTypes; - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::OBJ); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::EB); - bbOutputTypes.push_back(NOMAD::BBOutputType::Type::EB); - allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::OBJ); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::EB); + bbOutputTypes.emplace_back(NOMAD::BBOutputType::Type::EB); + allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes); // Algo for search allParams->setAttributeValue("NM_SEARCH", false); @@ -133,7 +132,7 @@ void initAllParams(std::shared_ptr allParams) // Parameters validation requested to have access to their value. allParams->checkAndComply(); - + } @@ -142,7 +141,7 @@ void initAllParams(std::shared_ptr allParams) /* the algorithm should stop. */ /*----------------------------------------*/ void userIterationCallback(const NOMAD::Step& step, - bool &stop) + bool &stop) { // Several NOMAD::Algorithm are used by NOMAD. // We are interested only on the main Mads (Mega) Iteration. @@ -155,11 +154,10 @@ void userIterationCallback(const NOMAD::Step& step, { // Fetch the best feasible point in the cache std::vector bestFeas; - NOMAD::CacheBase::getInstance()->findBestFeas(bestFeas, NOMAD::Point() /* no fixed variables */, - NOMAD::EvalType::BB, NOMAD::ComputeType::STANDARD); + NOMAD::CacheBase::getInstance()->findBestFeas(bestFeas); for (const auto & evalP: bestFeas) { - if ( evalP.getF() <= FTarget) + if ( evalP.getF(NOMAD::defaultFHComputeType) <= FTarget) { // Stop motivated by user conditions stop = true; @@ -174,14 +172,11 @@ void userIterationCallback(const NOMAD::Step& step, } - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main ( int argc , char ** argv ) +int main() { - - NOMAD::MainStep TheMainStep; // Set parameters @@ -196,11 +191,10 @@ int main ( int argc , char ** argv ) // Set main step callback TheMainStep.addCallback(NOMAD::CallbackType::MEGA_ITERATION_END, userIterationCallback); - // The run TheMainStep.start(); TheMainStep.run(); TheMainStep.end(); return 1; -} +} diff --git a/examples/basic/library/example1/example1_lib.cpp b/examples/basic/library/example1/example1_lib.cpp index 8d7f0e2a..4ff58422 100644 --- a/examples/basic/library/example1/example1_lib.cpp +++ b/examples/basic/library/example1/example1_lib.cpp @@ -59,11 +59,11 @@ class My_Evaluator : public NOMAD::Evaluator { public: - My_Evaluator(const std::shared_ptr& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) // Evaluator for true blackbox evaluations only {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double &hMax, bool &countEval) const override { @@ -95,7 +95,7 @@ class My_Evaluator : public NOMAD::Evaluator } g1 = -prod2 + 0.75; - g2 = sum2 -7.5 * n; + g2 = sum2 -7.5 * (double)n; f = 10*g1 + 10*g2; if (0.0 != sum3) @@ -109,6 +109,7 @@ class My_Evaluator : public NOMAD::Evaluator } NOMAD::Double c2000 = -f-2000; + // Double::tostring function uses FULL precision std::string bbo = g1.tostring(); bbo += " " + g2.tostring(); bbo += " " + f.tostring(); @@ -141,7 +142,7 @@ class My_Evaluator : public NOMAD::Evaluator }; -void initAllParams(std::shared_ptr allParams) +void initAllParams(const std::shared_ptr& allParams) { // Parameters creation // Number of variables @@ -157,10 +158,10 @@ void initAllParams(std::shared_ptr allParams) // Constraints and objective NOMAD::BBOutputTypeList bbOutputTypes; - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); // g1 - bbOutputTypes.push_back(NOMAD::BBOutputType::PB); // g2 - bbOutputTypes.push_back(NOMAD::BBOutputType::OBJ); // f - bbOutputTypes.push_back(NOMAD::BBOutputType::EB); // c2000 + bbOutputTypes.emplace_back(NOMAD::BBOutputType::PB); // g1 + bbOutputTypes.emplace_back(NOMAD::BBOutputType::PB); // g2 + bbOutputTypes.emplace_back(NOMAD::BBOutputType::OBJ); // f + bbOutputTypes.emplace_back(NOMAD::BBOutputType::EB); // c2000 allParams->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes ); allParams->setAttributeValue("DIRECTION_TYPE", NOMAD::DirectionType::ORTHO_2N); allParams->setAttributeValue("DISPLAY_DEGREE", 2); @@ -181,21 +182,22 @@ void initAllParams(std::shared_ptr allParams) /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main (int argc, char **argv) +int main() { - NOMAD::MainStep TheMainStep; try { + // Set parameters auto params = std::make_shared(); initAllParams(params); TheMainStep.setAllParameters(params); - + + // Set evaluator auto ev = std::make_unique(params->getEvalParams()); TheMainStep.addEvaluator(std::move(ev)); - - + + // Run optimization TheMainStep.start(); TheMainStep.run(); TheMainStep.end(); diff --git a/examples/basic/library/example2/example2_lib.cpp b/examples/basic/library/example2/example2_lib.cpp index ce912d9d..e15cbcab 100644 --- a/examples/basic/library/example2/example2_lib.cpp +++ b/examples/basic/library/example2/example2_lib.cpp @@ -57,13 +57,12 @@ /* equality constraint. */ /* */ /* Modified problem: */ -/* Geometric constraint x1+...+x4+d=10 */ /* Pb dimension is set to n=4 */ /* Set an inequality constraint: */ /* x1+...+x4<=10 */ /* If constraint is verified */ /* - Pick up d = 10-(x1+...+x4) */ -/* - Compute f=-(x1^2+...+x^4^2+d^2) */ +/* - Compute f=-(x1^2+...+x4^2+d^2) */ /* - Count eval */ /* If constraint is not verified */ /* - f=Inf */ @@ -74,11 +73,11 @@ class My_Evaluator : public NOMAD::Evaluator { public: - My_Evaluator(const std::shared_ptr& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double& hMax, bool &countEval) const override { @@ -98,7 +97,7 @@ class My_Evaluator : public NOMAD::Evaluator if (s1 > 10) { c1 = s1; - std::string bbo = f.tostring() + " " + c1.tostring(); // f is not really computed. But the point is infeasible and we handle the constraint with EB, so it does not matter. The point is simply discarded. + std::string bbo = f.tostring() + " " + c1.tostring(); // f is not really computed. But the point is infeasible, and we handle the constraint with EB, so it does not matter. The point is simply discarded. x.setBBO(bbo); countEval = false; // DO NOT count as a blackbox evaluation when geometric constraint is not verified @@ -143,14 +142,14 @@ void initParams(NOMAD::AllParameters &p) // parameters creation size_t n = 4; // Number of variables of the modified problem p.setAttributeValue("DIMENSION", n); - p.setAttributeValue("BB_OUTPUT_TYPE", NOMAD::stringToBBOutputTypeList("OBJ EB")); // EB constraint: If a point is infeasible it is simply discarded. F (costly part) is not computed. + p.setAttributeValue("BB_OUTPUT_TYPE", NOMAD::stringToBBOutputTypeList("OBJ EB")); // EB constraint: If a point is infeasible it is simply discarded. F (costly part) is not computed. p.setAttributeValue("X0", NOMAD::Point(n,5.0)); // starting point (0.0 0.0 0.0 0.0 0.0) p.setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(n, 0.0)); // all var. >= 0 p.setAttributeValue("UPPER_BOUND", NOMAD::ArrayOfDouble(n, 5.0)); // all var. >= 0); // the algorithm terminates after 100 black-box evaluations, - // or 10000 total evaluations, including cache hits and evalutions for + // or 10000 total evaluations, including cache hits and evaluations for // which countEval was false. p.setAttributeValue("MAX_BB_EVAL", 200); p.setAttributeValue("MAX_EVAL", 10000); @@ -166,7 +165,7 @@ void initParams(NOMAD::AllParameters &p) /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ -int main (int argc, char **argv) +int main() { auto TheMainStep = std::make_unique(); diff --git a/examples/basic/library/example3/CMakeLists.txt b/examples/basic/library/example3/CMakeLists.txt deleted file mode 100644 index 3d4d7791..00000000 --- a/examples/basic/library/example3/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -add_executable(example3_lib.exe example3_lib.cpp ) - -target_include_directories(example3_lib.exe PRIVATE - ${CMAKE_SOURCE_DIR}/src) - -set_target_properties(example3_lib.exe PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" SUFFIX "") - - -if(OpenMP_CXX_FOUND) - target_link_libraries(example3_lib.exe PUBLIC nomadAlgos nomadUtils nomadEval OpenMP::OpenMP_CXX) -else() - target_link_libraries(example3_lib.exe PUBLIC nomadAlgos nomadUtils nomadEval) -endif() - -# installing executables and libraries -install(TARGETS example3_lib.exe - RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) - - -# Add a test for this example -message(STATUS " Add example library #3") - -# Can run this test after install -if (WIN32) - add_test(NAME Example3BasicLib - COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./example3_lib.exe - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) -else() - add_test(NAME Example3BasicLib - COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./example3_lib.exe - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) -endif() diff --git a/examples/basic/library/example3/example3_lib.cpp b/examples/basic/library/example3/example3_lib.cpp deleted file mode 100644 index a8781bf9..00000000 --- a/examples/basic/library/example3/example3_lib.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/*---------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ -/* */ -/* NOMAD - Version 4 has been created and developed by */ -/* Viviane Rochon Montplaisir - Polytechnique Montreal */ -/* Christophe Tribes - Polytechnique Montreal */ -/* */ -/* The copyright of NOMAD - version 4 is owned by */ -/* Charles Audet - Polytechnique Montreal */ -/* Sebastien Le Digabel - Polytechnique Montreal */ -/* Viviane Rochon Montplaisir - Polytechnique Montreal */ -/* Christophe Tribes - Polytechnique Montreal */ -/* */ -/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ -/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ -/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ -/* for Data Valorization) */ -/* */ -/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ -/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ -/* and Exxon Mobil. */ -/* */ -/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ -/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ -/* Exxon Mobil. */ -/* */ -/* Contact information: */ -/* Polytechnique Montreal - GERAD */ -/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ -/* e-mail: nomad@gerad.ca */ -/* */ -/* 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 . */ -/* */ -/* You can find information on the NOMAD software at www.gerad.ca/nomad */ -/*---------------------------------------------------------------------------------*/ - -#include "Nomad/nomad.hpp" - -/*----------------------------------------*/ -/* The problem */ -/*----------------------------------------*/ -class My_Evaluator : public NOMAD::Evaluator -{ -public: - - // Create a EvalType::BB evaluator. - My_Evaluator(const std::shared_ptr& evalParams) - : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) - {} - - ~My_Evaluator() {} - - bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double& hMax, bool &countEval) const override - { - bool eval_ok = false; - size_t n = x.size(); - - NOMAD::Double f = 0.0; // Objective value - NOMAD::Double c1 = 0.0; // Constraint 1 - NOMAD::Double c2 = 0.0; // Constraint 2 - - try - { - for (size_t i = 0; i < n; i++) - { - NOMAD::Double xi = x[i]; - c1 += (xi-1).pow2(); - c2 += (xi+1).pow2(); - } - c1 = c1-25; - c2 = 25-c2; - - f = x[n-1]; - std::string bbo = f.tostring() + " " + c1.tostring() + " " + c2.tostring(); - x.setBBO(bbo); - eval_ok = true; - } - catch (std::exception &e) - { - std::string err("Exception: "); - err += e.what(); - throw std::logic_error(err); - } - - - countEval = true; // count a black-box evaluation - - return eval_ok; // the evaluation succeeded - } - - // Wrapper around eval_x - // If eval_block is not defined here, eval_x is called sequentially - // for each point in the block, and a warning is shown. - // The user may redefine eval_block to optimize parallelism management. - std::vector eval_block(std::vector> &block, - const NOMAD::Double& hMax, - std::vector &countEval) const override - { - std::vector evalOk(block.size(), false); - countEval.resize(block.size(), false); - - for (size_t index = 0; index < block.size(); index++) - { - bool countEval1 = false; - evalOk[index] = eval_x(*block[index], hMax, countEval1); - countEval[index] = countEval1; - } - - return evalOk; - } -}; - - - - -void initParams(NOMAD::AllParameters &p) -{ - // parameters creation - size_t n = 6; // Number of variables - p.setAttributeValue("DIMENSION", n); - p.setAttributeValue("BB_OUTPUT_TYPE", NOMAD::stringToBBOutputTypeList("OBJ PB PB")); - - NOMAD::Point X0(n, 0.0); - X0[n-1] = -4.0; // starting point (0.0 0.0 0.0 0.0 0.0 -4.0) - p.setAttributeValue("X0", X0); - p.setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(n, -6.0)); // all var. >= -6 - NOMAD::ArrayOfDouble ub(n); // 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 - ub[n-1] = 6.0; // x_6 <= 6 - p.setAttributeValue("UPPER_BOUND", ub); - - // the algorithm terminates after MAX_BB_EVAL black-box evaluations, or MAX_EVAL total evaluations (including cache hits). - p.setAttributeValue("MAX_BB_EVAL", 1000); - p.setAttributeValue("MAX_EVAL", 1000); - p.setAttributeValue("BB_MAX_BLOCK_SIZE", (size_t)8); - p.setAttributeValue("NB_THREADS_OPENMP",1); // Using a single thread is recommanded with block eval - - NOMAD::ArrayOfDouble minMeshSize(n, 0.1); - minMeshSize[4] = 0.2; - p.setAttributeValue("MIN_MESH_SIZE", minMeshSize); - - NOMAD::Point fixedVariable(n); - fixedVariable[5] = X0[5]; - p.setAttributeValue("FIXED_VARIABLE", fixedVariable); - - p.setAttributeValue("DISPLAY_DEGREE", 2); - p.setAttributeValue("DISPLAY_ALL_EVAL", true); - p.setAttributeValue("DISPLAY_STATS", NOMAD::ArrayOfString("EVAL BLK_EVA ( SOL ) OBJ CONS_H H_MAX")); - - // parameters validation - p.checkAndComply(); -} - -/*------------------------------------------*/ -/* NOMAD main function */ -/*------------------------------------------*/ -int main (int argc, char **argv) -{ - auto TheMainStep = std::make_unique(); - - // Initialize all parameters - auto params = std::make_shared(); - initParams(*params); - TheMainStep->setAllParameters(params); - - // Custom Evaluator creation - auto ev = std::make_unique(params->getEvalParams()); - TheMainStep->addEvaluator(std::move(ev)); - - try - { - // Algorithm creation and execution - TheMainStep->start(); - TheMainStep->run(); - TheMainStep->end(); - } - - catch(std::exception &e) - { - std::cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; - } - - return 0; -} diff --git a/examples/basic/library/example4/CMakeLists.txt b/examples/basic/library/example4/CMakeLists.txt deleted file mode 100644 index dbcc9296..00000000 --- a/examples/basic/library/example4/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -add_executable(example4_lib.exe example4_lib.cpp ) - -target_include_directories(example4_lib.exe PRIVATE - ${CMAKE_SOURCE_DIR}/src) - -set_target_properties(example4_lib.exe PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" SUFFIX "") - - -if(OpenMP_CXX_FOUND) - target_link_libraries(example4_lib.exe PUBLIC nomadAlgos nomadUtils nomadEval OpenMP::OpenMP_CXX) -else() - target_link_libraries(example4_lib.exe PUBLIC nomadAlgos nomadUtils nomadEval) -endif() - -# installing executables and libraries -install(TARGETS example4_lib.exe - RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) - - -# Add a test for this example -message(STATUS " Add example library #4") - -# Can run this test after install -if (WIN32) - add_test(NAME example4BasicLib - COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./example4_lib.exe - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) -else() - add_test(NAME example4BasicLib - COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./example4_lib.exe - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) -endif() diff --git a/examples/basic/library/example4/example4_lib.cpp b/examples/basic/library/example4/example4_lib.cpp deleted file mode 100644 index 1086f836..00000000 --- a/examples/basic/library/example4/example4_lib.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/*---------------------------------------------------------------------------------*/ -/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ -/* */ -/* NOMAD - Version 4 has been created and developed by */ -/* Viviane Rochon Montplaisir - Polytechnique Montreal */ -/* Christophe Tribes - Polytechnique Montreal */ -/* */ -/* The copyright of NOMAD - version 4 is owned by */ -/* Charles Audet - Polytechnique Montreal */ -/* Sebastien Le Digabel - Polytechnique Montreal */ -/* Viviane Rochon Montplaisir - Polytechnique Montreal */ -/* Christophe Tribes - Polytechnique Montreal */ -/* */ -/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ -/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ -/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ -/* for Data Valorization) */ -/* */ -/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ -/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ -/* and Exxon Mobil. */ -/* */ -/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ -/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ -/* Exxon Mobil. */ -/* */ -/* Contact information: */ -/* Polytechnique Montreal - GERAD */ -/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ -/* e-mail: nomad@gerad.ca */ -/* */ -/* 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 . */ -/* */ -/* You can find information on the NOMAD software at www.gerad.ca/nomad */ -/*---------------------------------------------------------------------------------*/ - -#include "Nomad/nomad.hpp" - -/*----------------------------------------*/ -/* The problem */ -/*----------------------------------------*/ -class My_Evaluator : public NOMAD::Evaluator -{ -public: - My_Evaluator(const std::shared_ptr& evalParams, NOMAD::EvalType evalType) - : NOMAD::Evaluator(evalParams, evalType) - {} - - ~My_Evaluator() {} - - bool eval_x(NOMAD::EvalPoint &x, const NOMAD::Double& hMax, bool &countEval) const override - { - bool eval_ok = false; - size_t n = x.size(); - - NOMAD::Double f = 0.0; // Objective value - NOMAD::Double c1 = 0.0; // Constraint 1 - NOMAD::Double c2 = 0.0; // Constraint 2 - - try - { - if (NOMAD::EvalType::BB == _evalType) - { - for (size_t i = 0; i < n; i++) - { - NOMAD::Double xi = x[i]; - c1 += (xi-1).pow2(); - c2 += (xi+1).pow2(); - } - c1 = c1-25; - c2 = 25-c2; - - } - else - { - c1 = x[0]*x[0]-5; - c2 = 5-x[1]*x[1]; - } - - f = x[n-1]; - std::string bbo = f.tostring() + " " + c1.tostring() + " " + c2.tostring(); - x.setBBO(bbo); // Eval type and Bb output types are determined automatically - eval_ok = true; - } - catch (std::exception &e) - { - std::string err("Exception: "); - err += e.what(); - throw std::logic_error(err); - } - - - countEval = true; // count a black-box evaluation - - return eval_ok; // the evaluation succeeded - } - - // Wrapper around eval_x - // If eval_block is not defined here, eval_x is called sequentially - // for each point in the block, and a warning is shown. - // The user may redefine eval_block to optimize parallelism management. - std::vector eval_block(std::vector> &block, - const NOMAD::Double& hMax, - std::vector &countEval) const override - { - std::vector evalOk(block.size(), false); - countEval.resize(block.size(), false); - - for (size_t index = 0; index < block.size(); index++) - { - bool countEval1 = false; - evalOk[index] = eval_x(*block[index], hMax, countEval1); - countEval[index] = countEval1; - } - - return evalOk; - } -}; - - - - -void initParams(NOMAD::AllParameters &p) -{ - // parameters creation - size_t n = 6; // Number of variables - p.setAttributeValue("DIMENSION", n); - p.setAttributeValue("BB_OUTPUT_TYPE", NOMAD::stringToBBOutputTypeList("OBJ EB EB")); - - - NOMAD::Point X0(n, 0.0); - // X0[n-1] = -4.0; // starting point (0.0 0.0 0.0 0.0 0.0 -4.0) - p.setAttributeValue("X0", X0); - p.setAttributeValue("LOWER_BOUND", NOMAD::ArrayOfDouble(n, -6.0)); // all var. >= -6 - NOMAD::ArrayOfDouble ub(n); // 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 - ub[n-1] = 6.0; // x_6 <= 6 - p.setAttributeValue("UPPER_BOUND", ub); - - // the algorithm terminates after MAX_BB_EVAL black-box evaluations. - p.setAttributeValue("MAX_BB_EVAL", 1000); - p.setAttributeValue("EVAL_SURROGATE_COST", 10); - p.setAttributeValue("EVAL_QUEUE_SORT",NOMAD::EvalSortType::SURROGATE); - - - // Using surrogate for sort and the options below => no quad model is used. - p.setAttributeValue("QUAD_MODEL_SEARCH", false); - p.setAttributeValue("NM_SEARCH", false); - p.setAttributeValue("DIRECTION_TYPE", NOMAD::DirectionType::ORTHO_2N); - - p.setAttributeValue("DISPLAY_DEGREE", 2); - - - // parameters validation - p.checkAndComply(); -} - -/*------------------------------------------*/ -/* NOMAD main function */ -/*------------------------------------------*/ -int main (int argc, char **argv) -{ - auto TheMainStep = std::make_unique(); - - // Initialize all parameters - auto params = std::make_shared(); - initParams(*params); - TheMainStep->setAllParameters(params); - - // Custom BB evaluator creation - auto evBB = std::make_unique(params->getEvalParams(),NOMAD::EvalType::BB); - TheMainStep->addEvaluator(std::move(evBB)); - - // Custom SURROGATE evaluator creation - auto evSurrogate = std::make_unique(params->getEvalParams(),NOMAD::EvalType::SURROGATE); - TheMainStep->addEvaluator(std::move(evSurrogate)); - try - { - // Algorithm creation and execution - TheMainStep->start(); - TheMainStep->run(); - TheMainStep->end(); - } - - catch(std::exception &e) - { - std::cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; - } - - return 0; -} diff --git a/examples/basic/library/multi_obj/CMakeLists.txt b/examples/basic/library/multi_obj/CMakeLists.txt new file mode 100644 index 00000000..11615c0c --- /dev/null +++ b/examples/basic/library/multi_obj/CMakeLists.txt @@ -0,0 +1,29 @@ +add_executable(multi_obj_lib.exe multi_obj_lib.cpp) + +target_include_directories(multi_obj_lib.exe PRIVATE ${CMAKE_SOURCE_DIR}/src) + +set_target_properties(multi_obj_lib.exe PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" SUFFIX "") + +if(OpenMP_CXX_FOUND) + target_link_libraries(multi_obj_lib.exe PUBLIC nomadAlgos nomadUtils nomadEval OpenMP::OpenMP_CXX) +else() + target_link_libraries(multi_obj_lib.exe PUBLIC nomadAlgos nomadUtils nomadEval) +endif() + +# installing executables and libraries +install(TARGETS multi_obj_lib.exe + RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} ) + +# Add a test for this example +message(STATUS " Add multi obj library example") + +# Can run this test after install +if (WIN32) + add_test(NAME MultiObjBasicLib + COMMAND bash.exe ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./multi_obj_lib.exe + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +else() + add_test(NAME MultiObjBasicLib + COMMAND ${CMAKE_BINARY_DIR}/examples/runExampleTest.sh ./multi_obj_lib.exe + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +endif() diff --git a/examples/basic/library/multi_obj/multi_obj_lib.cpp b/examples/basic/library/multi_obj/multi_obj_lib.cpp new file mode 100644 index 00000000..1d10d744 --- /dev/null +++ b/examples/basic/library/multi_obj/multi_obj_lib.cpp @@ -0,0 +1,279 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +/** + \file multi_obj_lib.cpp + \brief Library example for nomad (DMulti-MADS algorithm) + \author Ludovic Salomon + \date 2024 + */ + +#include "Nomad/nomad.hpp" +#include "Type/DMultiMadsSearchStrategyType.hpp" + +// A conceptual marine design problem +// See "An Easy-To-use Real-world Multi-objective Optimization Suite problem" +// by R. Tanabe and H. Ishibuchi +class MarineDesignProblem : public NOMAD::Evaluator +{ +public: + explicit MarineDesignProblem(const std::shared_ptr& evalParams) + : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) + {} + + ~MarineDesignProblem() override = default; + + bool eval_x(NOMAD::EvalPoint& x, const NOMAD::Double& hMax, bool& countEval) const override + { + bool eval_ok = false; + + NOMAD::Double f1 = 1e20, f2 = 1e20, f3 = 1e20; + + try + { + // Variables + const double L = x[0].todouble(); + const double B = x[1].todouble(); + const double D = x[2].todouble(); + const double T = x[3].todouble(); + const double Vk = x[4].todouble(); + const double Cb = x[5].todouble(); + + // Parameters + const double handlingRate = 8000; + const double roundTripMiles = 5000; + const double fuelPrice = 100; + const double g = 9.8065; + + // Equations + const double verticalCenterOfBuoyancy = 0.53 * T; + const double metacentricRadius = (0.085 * Cb - 0.002) * B * B / (T * Cb); + const double verticalCenterOfGravity = 1 + 0.52 * D; + + const double displacement = 1.025 * L * B * T * Cb; + const double a = 4977.06 * Cb * Cb - 8105.61 * Cb + 4456.51; + const double b = -10847.2 * Cb * Cb + 12817 * Cb - 6960.32; + const double V = 0.5144 * Vk; + const double froudenumber = V / std::pow(g * L, 0.5); + const double P = std::pow(displacement, 2.0/3) * std::pow(Vk, 3) / (a + b * froudenumber); + + const double steelWeight = 0.034 * std::pow(L, 1.7) * std::pow(B, 0.7) * + std::pow(D, 0.4) * std::pow(Cb, 0.5); + const double outfitWeight = 1.0 * std::pow(L, 0.8) * std::pow(B, 0.6) * + std::pow(D, 0.3) * std::pow(Cb, 0.1); + const double machineryWeight = 0.17 * std::pow(P, 0.9); + const double lightShipWeight = steelWeight + outfitWeight + machineryWeight; + + const double deadweight = displacement - lightShipWeight; + + const double dailyConsumption = (0.19 * P * 24) / 1000 + 0.2; + const double seaDays = (roundTripMiles * Vk) / 24; + const double fuelCarried = dailyConsumption * (seaDays + 5); + const double portCost = 6.3 * std::pow(deadweight, 0.8); + + const double cargoDeadweight = deadweight - fuelCarried - 2 * std::pow(deadweight, 0.5); + const double portDays = 2 * (cargoDeadweight / handlingRate + 0.5); + const double roundTripsPerYear = 350.0 / (seaDays + portDays); + + const double fuelCost = 1.05 * dailyConsumption * seaDays * fuelPrice; + const double runningCosts = 40000 * std::pow(deadweight, 0.8); + const double voyageCosts = (fuelCost + portCost) * roundTripsPerYear; + const double shipCosts = 1.3 * (2000 * std::pow(steelWeight, 0.85) + + 3500 * outfitWeight + 2400 * std::pow(P, 0.8)); + const double capitalCosts = 0.2 * shipCosts; + const double annualCosts = capitalCosts + runningCosts + voyageCosts; + + const double annualCargo = - cargoDeadweight * roundTripsPerYear; + + // Objectives + f1 = annualCosts / annualCargo; + f2 = lightShipWeight; + f3 = annualCargo; + + // Constraints + const NOMAD::Double g1 = L / B - 6.0; // >= 0 + const NOMAD::Double g2 = 15.0 - L / D; // >= 0 + const NOMAD::Double g3 = 19.0 - L / T; // >= 0 + const NOMAD::Double g4 = 0.45 * std::pow(deadweight, 0.31) - T; // >= 0 + const NOMAD::Double g5 = 0.7 * D + 0.7 - T; // >= 0 + const NOMAD::Double g6 = deadweight - 3000; // >= 0 + const NOMAD::Double g7 = 500000 - deadweight; // >= 0 + const NOMAD::Double g8 = 0.32 - froudenumber; // >= 0 + const NOMAD::Double g9 = verticalCenterOfBuoyancy + metacentricRadius - + verticalCenterOfGravity - 0.07 * B; // >= 0 + + std::string bbo = f1.tostring() + " " + f2.tostring() + " " + f3.tostring(); + bbo += " " + (-g1).tostring(); + bbo += " " + (-g2).tostring(); + bbo += " " + (-g3).tostring(); + bbo += " " + (-g4).tostring(); + bbo += " " + (-g5).tostring(); + bbo += " " + (-g6).tostring(); + bbo += " " + (-g7).tostring(); + bbo += " " + (-g8).tostring(); + bbo += " " + (-g9).tostring(); + + x.setBBO(bbo); + + eval_ok = true; + } + catch (std::exception& e) + { + std::string err("Exception: "); + err += e.what(); + throw std::logic_error(err); + } + countEval = true; + return eval_ok; + } +}; + +// Main function +int main() +{ + NOMAD::MainStep TheMainStep; + + try + { + // Parameters creation + auto params = std::make_shared(); + + // Dimensions of the blackbox, inputs and outputs + const size_t n = 6; + params->setAttributeValue("DIMENSION", n); + + NOMAD::ArrayOfDouble lb(n, 0); + lb[0] = 150; + lb[1] = 20; + lb[2] = 13; + lb[3] = 10; + lb[4] = 14; + lb[5] = 0.63; + params->setAttributeValue("LOWER_BOUND", lb); + + NOMAD::ArrayOfDouble ub(n, 0); + ub[0] = 274.32; + ub[1] = 32.31; + ub[2] = 25; + ub[3] = 11.71; + ub[4] = 18; + ub[5] = 0.75; + params->setAttributeValue("UPPER_BOUND", ub); + + // Outputs, constraints and objectives + NOMAD::BBOutputTypeList bbOutputTypes; + for (size_t i = 0; i < 3; ++i) + { + bbOutputTypes.emplace_back(NOMAD::BBOutputType::OBJ); + } + for (size_t i = 0; i < 9; ++i) + { + bbOutputTypes.emplace_back(NOMAD::BBOutputType::EB); // We want a two-phase approach + } + params->setAttributeValue("BB_OUTPUT_TYPE", bbOutputTypes); + + // A line initialization is practically more efficient than giving a single point for + // multiobjective optimization. + // The interesting reader can report to the following reference for more information. + // Direct Multisearch for multiobjective optimization + // by A.L. Custodio, J.F.A. Madeira, A.I.F. Vaz and L.N. Vicente, 2011. + NOMAD::ArrayOfPoint x0s; + for (size_t j = 0; j < n; ++j) + { + NOMAD::Point x0(n, 0); + for (size_t i = 0; i < n; ++i) + { + x0[i] = lb[i] + (double) j * (ub[i] - lb[i]) / (n - 1); + } + x0s.push_back(x0); + } + // Starting point + params->setAttributeValue("X0", x0s); + + // Algorithm parameters + // 1- Terminate after this number of maximum blackbox evaluations. + params->setAttributeValue("MAX_BB_EVAL", 3000); + + // 2- Use n+1 directions + params->setAttributeValue("DIRECTION_TYPE", NOMAD::DirectionType::ORTHO_NP1_NEG); + + // 3- For multiobjective optimization, these parameters are required. + params->setAttributeValue("DMULTIMADS_OPTIMIZATION", true); + // For multiobjective optimization, sort cannot use the default quad model info. + params->setAttributeValue("EVAL_QUEUE_SORT", NOMAD::EvalSortType::DIR_LAST_SUCCESS); + params->setAttributeValue("NM_SEARCH", false); // Deactivate Nelder-Mead search + // NB: by default, QUAD_MODEL_SEARCH is activated; to deactivate it, uncomment + // params->setAttributeValue("QUAD_MODEL_SEARCH", true); // Deactivate Quad Model search + // Change Quad Model search strategy for DMultiMads + params->setAttributeValue("DMULTIMADS_QUAD_MODEL_STRATEGY", NOMAD::DMultiMadsQuadSearchType::DMS); + + // Advanced attributes for DMultiMads + params->setAttributeValue("DMULTIMADS_SELECT_INCUMBENT_THRESHOLD", 2); + + // 4- Other useful parameters + params->setAttributeValue("DISPLAY_DEGREE", 2); + params->setAttributeValue("SOLUTION_FILE", std::string("sol.txt")); // Save the Pareto front approximation + // params->setAttributeValue("HISTORY_FILE", std::string("history.txt")); // Save history. To uncomment if you want it. + + // Validate + params->checkAndComply(); + + // Run the solver + TheMainStep.setAllParameters(params); + auto ev = std::make_unique(params->getEvalParams()); + TheMainStep.addEvaluator(std::move(ev)); + + TheMainStep.start(); + TheMainStep.run(); + TheMainStep.end(); + } + + catch(std::exception &e) + { + std::cerr << "\nNOMAD has been interrupted (" << e.what() << ")\n\n"; + } + return 0; +} diff --git a/examples/basic/library/single_obj_parallel/basic_lib.cpp b/examples/basic/library/single_obj_parallel/basic_lib.cpp index 73ed7875..a3382840 100644 --- a/examples/basic/library/single_obj_parallel/basic_lib.cpp +++ b/examples/basic/library/single_obj_parallel/basic_lib.cpp @@ -52,50 +52,42 @@ #include #endif -// Number of threads to be used in parallel -#define NUM_THREADS 6 - -// A structure to pass arguments to the evaluation wrapper function -class My_Evaluator; -typedef struct Arg_Eval_tag { - std::shared_ptr x; - NOMAD::Double hMax; - bool countEval; -} Arg_Eval_t; - +// Number of threads to be used for evaluation of a block of points in parallel +#define NUM_THREADS_EVAL 6 // Wrapper of eval_x used for parallel evaluation. -bool wrapper_eval_x(Arg_Eval_t& eval_arg) +bool wrapper_eval_x(std::shared_ptr & x, const NOMAD::Double& hmax, bool & countEval) { + + // std::cout << "Thread #" << omp_get_thread_num() << std::endl; + NOMAD::Double c1 = 0.0, c2 = 0.0; - NOMAD::EvalPoint& x = *(eval_arg.x); for (int i = 0; i < 5; i++) { - c1 += (x[i]-1).pow2(); - c2 += (x[i]+1).pow2(); + c1 += ((*x)[i]-1).pow2(); + c2 += ((*x)[i]+1).pow2(); } - NOMAD::Double f = x[4]; // objective value + NOMAD::Double f = (*x)[4]; // objective value c1 = c1-25; // constraint 1 c2 = 25-c2; // constraint 2 std::string bbo = f.tostring() + " " + c1.tostring() + " " + c2.tostring(); - eval_arg.x->setBBO(bbo); + x->setBBO(bbo); - eval_arg.countEval = true; // count a black-box evaluation + countEval = true; // count a black-box evaluation return true; // Eval ok } - class My_Evaluator : public NOMAD::Evaluator { public: - My_Evaluator(const std::shared_ptr& evalParams) + explicit My_Evaluator(const std::shared_ptr& evalParams) : NOMAD::Evaluator(evalParams, NOMAD::EvalType::BB) {} - ~My_Evaluator() {} + ~My_Evaluator() override = default; // Implementation std::vector eval_block(std::vector> &block, @@ -105,40 +97,31 @@ class My_Evaluator : public NOMAD::Evaluator { std::vector evalOk(block.size(), false); listCountEval.resize(block.size(), false); // Evaluations are not counted until eval_x is called and sets countEval - - // Arguments passed to the evaluation wrapper - Arg_Eval_t* eval_arg = new Arg_Eval_t[block.size()]; - - std::vector>::iterator it_x = block.begin(), end_x = block.end(); - size_t i = 0; + + int i; #ifdef _OPENMP - #pragma omp parallel + #pragma omp parallel for num_threads(NUM_THREADS_EVAL) shared(block,evalOk,listCountEval, hMax) private(i) #endif - for (it_x = block.begin(); it_x != end_x; ++it_x, ++i) + for(i = 0; i < (int)block.size(); i++) { - // A thread is created for each x in the block. - eval_arg[i].x = (*it_x); - eval_arg[i].hMax = hMax.todouble(); - evalOk[i] = wrapper_eval_x(eval_arg[i]); - listCountEval[i] = eval_arg[i].countEval; + bool countEval = false; + evalOk[i] = wrapper_eval_x(block[i],hMax, countEval); + listCountEval[i] = countEval; } - // End of parallel block - - delete[] eval_arg; return evalOk; } }; -void initParams(std::shared_ptr& params) +void initParams(const std::shared_ptr& params) { params->setAttributeValue("DIMENSION", 5); // number of variables NOMAD::BBOutputTypeList bbot; // Definition of output types - bbot.push_back(NOMAD::BBOutputType::OBJ); - bbot.push_back(NOMAD::BBOutputType::PB); - bbot.push_back(NOMAD::BBOutputType::EB); + bbot.emplace_back(NOMAD::BBOutputType::OBJ); + bbot.emplace_back(NOMAD::BBOutputType::PB); + bbot.emplace_back(NOMAD::BBOutputType::EB); params->setAttributeValue("BB_OUTPUT_TYPE", bbot); // params->setAttributeValue("DISPLAY_ALL_EVAL", true); // displays all evaluations. @@ -149,7 +132,7 @@ void initParams(std::shared_ptr& params) params->setAttributeValue("SPECULATIVE_SEARCH", false); params->setAttributeValue("NM_SEARCH", false); params->setAttributeValue("QUAD_MODEL_SEARCH", false); - // Use single pass poll method with n+1 points -> 6 trial points in a block per poll + // Use poll method n+1 uni -> 6 trial points per poll on a single pass params->setAttributeValue("DIRECTION_TYPE",NOMAD::DirectionType::NP1_UNI); params->setAttributeValue("X0", NOMAD::Point(5,0.0)); // starting point @@ -165,18 +148,16 @@ void initParams(std::shared_ptr& params) // 100 black-box evaluations // Max number of points to be given as a block for evaluation - // This option is required to perform parallel evaluations in eval_block - // function above - params->setAttributeValue("BB_MAX_BLOCK_SIZE", NUM_THREADS); + // This option is required to perform parallel evaluations + // All points in a block will be evaluated in parallel + params->setAttributeValue("BB_MAX_BLOCK_SIZE", NUM_THREADS_EVAL); - // A single thread is used for Nomad "parallel" evaluation queue. - params->setAttributeValue("NB_THREADS_OPENMP", 1); + // NOTE: A single thread is used for Nomad "parallel" evaluation queue. // parameters validation: params->checkAndComply(); } - /*------------------------------------------*/ /* NOMAD main function */ /*------------------------------------------*/ @@ -184,13 +165,21 @@ int main(int argc, char ** argv) { try { + +#ifdef _OPENMP + // This is important for nested parallel regions. Nomad parallel region + // for evaluation queue and a parallel region for block evaluation. + omp_set_nested(true); + omp_set_dynamic(false); +#endif + auto TheMainStep = std::make_unique(); // Parameters creation auto params = std::make_shared(); initParams(params); TheMainStep->setAllParameters(params); - + // Custom Evaluator auto ev = std::make_unique(params->getEvalParams()); TheMainStep->addEvaluator(std::move(ev)); From f68a24f2e237a655aae970a351576d84c6955749 Mon Sep 17 00:00:00 2001 From: Christophe Tribes Date: Thu, 23 Jan 2025 15:29:08 -0500 Subject: [PATCH 13/51] Update source --- src/Algos/AlgoStopReasons.hpp | 6 +- src/Algos/Algorithm.cpp | 103 +- src/Algos/Algorithm.hpp | 12 +- src/Algos/COOPMads/COOPMads.cpp | 181 + src/Algos/COOPMads/COOPMads.hpp | 102 + src/Algos/COOPMads/CacheSearchMethod.cpp | 188 + .../CacheSearchMethod.hpp} | 49 +- src/Algos/CacheInterface.cpp | 12 +- src/Algos/CacheInterface.hpp | 26 +- src/Algos/CoordinateSearch/CS.cpp | 2 +- src/Algos/CoordinateSearch/CS.hpp | 7 +- .../CoordinateSearch/CSInitialization.hpp | 6 +- src/Algos/CoordinateSearch/CSIteration.hpp | 9 +- .../CoordinateSearch/CSMegaIteration.hpp | 6 +- src/Algos/CoordinateSearch/CSMesh.cpp | 16 +- src/Algos/CoordinateSearch/CSMesh.hpp | 9 +- src/Algos/CoordinateSearch/CSPoll.cpp | 2 +- src/Algos/CoordinateSearch/CSPoll.hpp | 8 +- src/Algos/CoordinateSearch/CSPollMethod.hpp | 8 +- src/Algos/CoordinateSearch/CSUpdate.cpp | 27 +- src/Algos/CoordinateSearch/CSUpdate.hpp | 8 +- src/Algos/DMultiMads/DMultiMads.cpp | 14 +- src/Algos/DMultiMads/DMultiMads.hpp | 8 +- src/Algos/DMultiMads/DMultiMadsBarrier.cpp | 1762 ++++--- src/Algos/DMultiMads/DMultiMadsBarrier.hpp | 154 +- ...DMultiMadsExpansionIntLineSearchMethod.cpp | 418 ++ ...DMultiMadsExpansionIntLineSearchMethod.hpp | 114 + src/Algos/DMultiMads/DMultiMadsIteration.cpp | 60 +- src/Algos/DMultiMads/DMultiMadsIteration.hpp | 6 +- .../DMultiMads/DMultiMadsMegaIteration.cpp | 2 +- .../DMultiMads/DMultiMadsMegaIteration.hpp | 6 +- .../DMultiMadsMiddlePointSearchMethod.cpp | 262 ++ .../DMultiMadsMiddlePointSearchMethod.hpp | 99 + .../DMultiMads/DMultiMadsNMSearchMethod.cpp | 725 +++ .../DMultiMads/DMultiMadsNMSearchMethod.hpp | 121 + .../DMultiMadsQuadDMSSearchMethod.cpp | 547 +++ .../DMultiMadsQuadDMSSearchMethod.hpp | 126 + .../DMultiMadsQuadModSearchMethod.cpp | 601 +++ .../DMultiMadsQuadModSearchMethod.hpp | 120 + src/Algos/DMultiMads/DMultiMadsUpdate.cpp | 67 +- src/Algos/DMultiMads/DMultiMadsUpdate.hpp | 6 +- src/Algos/DiscoMads/DiscoMads.cpp | 4 +- src/Algos/DiscoMads/DiscoMads.hpp | 6 +- src/Algos/DiscoMads/DiscoMadsBarrier.cpp | 69 +- src/Algos/DiscoMads/DiscoMadsBarrier.hpp | 30 +- src/Algos/DiscoMads/DiscoMadsIteration.cpp | 12 +- src/Algos/DiscoMads/DiscoMadsIteration.hpp | 8 +- .../DiscoMads/DiscoMadsMegaIteration.cpp | 172 +- .../DiscoMads/DiscoMadsMegaIteration.hpp | 18 +- src/Algos/DiscoMads/DiscoMadsUpdate.cpp | 2 +- src/Algos/DiscoMads/DiscoMadsUpdate.hpp | 6 +- src/Algos/DiscoMads/RevealingPoll.cpp | 18 +- src/Algos/DiscoMads/RevealingPoll.hpp | 6 +- src/Algos/EvcInterface.cpp | 42 +- src/Algos/EvcInterface.hpp | 11 +- src/Algos/Initialization.cpp | 3 +- src/Algos/Initialization.hpp | 6 +- src/Algos/Iteration.hpp | 8 +- src/Algos/IterationUtils.cpp | 86 +- src/Algos/IterationUtils.hpp | 44 +- src/Algos/LatinHypercubeSampling/LH.cpp | 6 +- src/Algos/LatinHypercubeSampling/LH.hpp | 7 +- src/Algos/Mads/DoublePollMethod.hpp | 6 +- src/Algos/Mads/GMesh.cpp | 22 +- src/Algos/Mads/GMesh.hpp | 10 +- src/Algos/Mads/LHSearchMethod.hpp | 9 +- src/Algos/Mads/Mads.cpp | 203 +- src/Algos/Mads/Mads.hpp | 75 +- src/Algos/Mads/MadsInitialization.cpp | 99 +- src/Algos/Mads/MadsInitialization.hpp | 8 +- src/Algos/Mads/MadsIteration.cpp | 43 +- src/Algos/Mads/MadsIteration.hpp | 6 +- src/Algos/Mads/MadsMegaIteration.cpp | 4 +- src/Algos/Mads/MadsMegaIteration.hpp | 8 +- src/Algos/Mads/MadsUpdate.cpp | 51 +- src/Algos/Mads/MadsUpdate.hpp | 6 +- src/Algos/Mads/MegaSearchPoll.cpp | 10 +- src/Algos/Mads/MegaSearchPoll.hpp | 12 +- src/Algos/Mads/NMSearchMethod.cpp | 21 +- src/Algos/Mads/NMSearchMethod.hpp | 16 +- src/Algos/Mads/NP1UniPollMethod.cpp | 6 +- src/Algos/Mads/NP1UniPollMethod.hpp | 6 +- src/Algos/Mads/Ortho2NPollMethod.cpp | 2 +- src/Algos/Mads/Ortho2NPollMethod.hpp | 6 +- src/Algos/Mads/OrthoNPlus1PollMethod.cpp | 17 +- src/Algos/Mads/OrthoNPlus1PollMethod.hpp | 6 +- src/Algos/Mads/Poll.cpp | 243 +- src/Algos/Mads/Poll.hpp | 52 +- src/Algos/Mads/PollMethodBase.cpp | 173 +- src/Algos/Mads/PollMethodBase.hpp | 73 +- src/Algos/Mads/QPSolverAlgoSearchMethod.cpp | 22 +- src/Algos/Mads/QPSolverAlgoSearchMethod.hpp | 14 +- src/Algos/Mads/QR2NPollMethod.cpp | 155 + .../SSDMads.hpp => Mads/QR2NPollMethod.hpp} | 48 +- src/Algos/Mads/QuadSearchMethod.cpp | 33 +- src/Algos/Mads/QuadSearchMethod.hpp | 21 +- src/Algos/Mads/Search.cpp | 75 +- src/Algos/Mads/Search.hpp | 15 +- src/Algos/Mads/SearchMethodAlgo.hpp | 8 +- src/Algos/Mads/SearchMethodBase.cpp | 7 +- src/Algos/Mads/SearchMethodBase.hpp | 27 +- src/Algos/Mads/SearchMethodSimple.cpp | 16 +- src/Algos/Mads/SearchMethodSimple.hpp | 27 +- src/Algos/Mads/SgtelibSearchMethod.cpp | 6 +- src/Algos/Mads/SgtelibSearchMethod.hpp | 6 +- src/Algos/Mads/SimpleLineSearchMethod.hpp | 10 +- src/Algos/Mads/SinglePollMethod.hpp | 6 +- src/Algos/Mads/SpeculativeSearchMethod.cpp | 4 +- src/Algos/Mads/SpeculativeSearchMethod.hpp | 6 +- src/Algos/Mads/TemplateAlgoSearchMethod.cpp | 4 +- src/Algos/Mads/TemplateAlgoSearchMethod.hpp | 6 +- src/Algos/Mads/UserPollMethod.cpp | 130 + src/Algos/Mads/UserPollMethod.hpp | 94 + src/Algos/Mads/UserSearchMethod.cpp | 86 +- src/Algos/Mads/UserSearchMethod.hpp | 31 +- src/Algos/Mads/VNSSearchMethod.cpp | 28 +- src/Algos/Mads/VNSSearchMethod.hpp | 6 +- src/Algos/Mads/VNSmartSearchMethod.cpp | 41 +- src/Algos/Mads/VNSmartSearchMethod.hpp | 6 +- src/Algos/MainStep.cpp | 293 +- src/Algos/MainStep.hpp | 23 +- src/Algos/MegaIteration.cpp | 11 - src/Algos/MegaIteration.hpp | 18 +- src/Algos/NelderMead/NM.cpp | 20 +- src/Algos/NelderMead/NM.hpp | 8 +- src/Algos/NelderMead/NMAllReflective.cpp | 16 +- src/Algos/NelderMead/NMAllReflective.hpp | 6 +- src/Algos/NelderMead/NMInitialization.cpp | 9 +- src/Algos/NelderMead/NMInitialization.hpp | 6 +- src/Algos/NelderMead/NMInitializeSimplex.cpp | 35 +- src/Algos/NelderMead/NMInitializeSimplex.hpp | 8 +- src/Algos/NelderMead/NMIteration.cpp | 2 +- src/Algos/NelderMead/NMIteration.hpp | 6 +- src/Algos/NelderMead/NMIterationUtils.cpp | 17 +- src/Algos/NelderMead/NMIterationUtils.hpp | 6 +- src/Algos/NelderMead/NMMegaIteration.cpp | 13 +- src/Algos/NelderMead/NMMegaIteration.hpp | 6 +- src/Algos/NelderMead/NMReflective.cpp | 81 +- src/Algos/NelderMead/NMReflective.hpp | 6 +- src/Algos/NelderMead/NMShrink.cpp | 2 +- src/Algos/NelderMead/NMShrink.hpp | 6 +- src/Algos/NelderMead/NMSimplexEvalPoint.cpp | 23 +- src/Algos/NelderMead/NMSimplexEvalPoint.hpp | 6 +- src/Algos/NelderMead/NMUpdate.hpp | 6 +- src/Algos/PSDMads/PSDMads.cpp | 262 +- src/Algos/PSDMads/PSDMads.hpp | 11 +- src/Algos/PSDMads/PSDMadsMegaIteration.cpp | 7 +- src/Algos/PSDMads/PSDMadsMegaIteration.hpp | 6 +- .../PSDMads/PSDMadsMegaIteration_prev.cpp | 222 + .../PSDMadsMegaIteration_prev.hpp} | 60 +- src/Algos/PhaseOne/PhaseOne.cpp | 26 +- src/Algos/PhaseOne/PhaseOne.hpp | 6 +- src/Algos/Projection.cpp | 514 ++ src/Algos/Projection.hpp | 125 + src/Algos/QPSolverAlgo/DoglegTRSolver.cpp | 261 + src/Algos/QPSolverAlgo/DoglegTRSolver.hpp | 78 + src/Algos/QPSolverAlgo/L1AugLagSolver.cpp | 1511 ++++++ src/Algos/QPSolverAlgo/L1AugLagSolver.hpp | 209 + .../QPSolverAlgo/LevenbergMarquardtSolver.cpp | 598 +++ .../QPSolverAlgo/LevenbergMarquardtSolver.hpp | 123 + .../ProjectedConjugateGradientSolver.cpp | 584 +++ .../ProjectedConjugateGradientSolver.hpp | 87 + src/Algos/QPSolverAlgo/QPModelUtils.cpp | 486 ++ src/Algos/QPSolverAlgo/QPModelUtils.hpp | 134 + src/Algos/QPSolverAlgo/QPSolverAlgo.cpp | 14 +- src/Algos/QPSolverAlgo/QPSolverAlgo.hpp | 6 +- .../QPSolverAlgo/QPSolverAlgoIteration.hpp | 6 +- .../QPSolverAlgoMegaIteration.hpp | 6 +- .../QPSolverAlgo/QPSolverAlgoSinglePass.cpp | 2 +- .../QPSolverAlgo/QPSolverAlgoSinglePass.hpp | 6 +- src/Algos/QPSolverAlgo/QPSolverOptimize.cpp | 4178 +++++++++++------ src/Algos/QPSolverAlgo/QPSolverOptimize.hpp | 263 +- src/Algos/QPSolverAlgo/TRIPMSolver.cpp | 1690 +++++++ src/Algos/QPSolverAlgo/TRIPMSolver.hpp | 187 + src/Algos/QuadModel/QuadModelAlgo.cpp | 8 +- src/Algos/QuadModel/QuadModelAlgo.hpp | 6 +- src/Algos/QuadModel/QuadModelEvaluator.cpp | 24 +- src/Algos/QuadModel/QuadModelEvaluator.hpp | 6 +- .../QuadModel/QuadModelInitialization.cpp | 6 +- .../QuadModel/QuadModelInitialization.hpp | 6 +- src/Algos/QuadModel/QuadModelIteration.cpp | 12 +- src/Algos/QuadModel/QuadModelIteration.hpp | 19 +- .../QuadModel/QuadModelIterationUtils.hpp | 6 +- .../QuadModel/QuadModelMegaIteration.hpp | 6 +- src/Algos/QuadModel/QuadModelOptimize.cpp | 68 +- src/Algos/QuadModel/QuadModelOptimize.hpp | 16 +- src/Algos/QuadModel/QuadModelSinglePass.cpp | 10 +- src/Algos/QuadModel/QuadModelSinglePass.hpp | 16 +- src/Algos/QuadModel/QuadModelUpdate.cpp | 277 +- src/Algos/QuadModel/QuadModelUpdate.hpp | 16 +- src/Algos/SSDMads/SSDMadsMegaIteration.cpp | 365 -- src/Algos/SgtelibModel/SgtelibModel.cpp | 11 +- src/Algos/SgtelibModel/SgtelibModel.hpp | 10 +- .../SgtelibModel/SgtelibModelEvaluator.cpp | 33 +- .../SgtelibModel/SgtelibModelEvaluator.hpp | 6 +- .../SgtelibModel/SgtelibModelFilterCache.cpp | 23 +- .../SgtelibModel/SgtelibModelFilterCache.hpp | 10 +- .../SgtelibModelInitialization.cpp | 14 +- .../SgtelibModelInitialization.hpp | 6 +- .../SgtelibModel/SgtelibModelIteration.hpp | 6 +- .../SgtelibModelMegaIteration.cpp | 2 +- .../SgtelibModelMegaIteration.hpp | 6 +- .../SgtelibModel/SgtelibModelOptimize.cpp | 26 +- .../SgtelibModel/SgtelibModelOptimize.hpp | 6 +- src/Algos/SgtelibModel/SgtelibModelUpdate.cpp | 29 +- src/Algos/SgtelibModel/SgtelibModelUpdate.hpp | 6 +- .../SimpleLineSearch/SimpleLineSearch.hpp | 14 +- .../SimpleLineSearchMegaIteration.cpp | 34 +- .../SimpleLineSearchMegaIteration.hpp | 6 +- .../SimpleEvalPoint.cpp} | 62 +- src/Algos/SimpleMads/SimpleEvalPoint.hpp | 147 + src/Algos/SimpleMads/SimpleMads.cpp | 234 + src/Algos/SimpleMads/SimpleMads.hpp | 152 + src/Algos/SimpleMads/SimplePoll.cpp | 593 +++ src/Algos/SimpleMads/SimplePoll.hpp | 189 + .../SimpleMads/SimpleProgressiveBarrier.cpp | 771 +++ .../SimpleMads/SimpleProgressiveBarrier.hpp | 182 + src/Algos/Step.cpp | 61 +- src/Algos/Step.hpp | 18 +- src/Algos/Subproblem.cpp | 13 +- src/Algos/Subproblem.hpp | 10 +- src/Algos/SubproblemManager.cpp | 6 +- src/Algos/SubproblemManager.hpp | 11 +- src/Algos/SurrogateEvaluation.cpp | 23 +- src/Algos/SurrogateEvaluation.hpp | 6 +- src/Algos/SurrogateEvaluator.hpp | 6 +- src/Algos/TemplateAlgo/TemplateAlgo.cpp | 4 +- src/Algos/TemplateAlgo/TemplateAlgo.hpp | 8 +- .../TemplateAlgoInitialization.cpp | 20 +- .../TemplateAlgoInitialization.hpp | 6 +- .../TemplateAlgo/TemplateAlgoIteration.cpp | 5 +- .../TemplateAlgo/TemplateAlgoIteration.hpp | 6 +- .../TemplateAlgoMegaIteration.hpp | 6 +- src/Algos/TemplateAlgo/TemplateAlgoRandom.cpp | 5 +- src/Algos/TemplateAlgo/TemplateAlgoRandom.hpp | 8 +- .../TemplateAlgo/TemplateAlgoSinglePass.cpp | 2 +- .../TemplateAlgo/TemplateAlgoSinglePass.hpp | 6 +- src/Algos/TemplateAlgo/TemplateAlgoUpdate.hpp | 6 +- src/Algos/Termination.cpp | 10 +- src/Algos/Termination.hpp | 8 +- src/Algos/TrialPointStats.cpp | 26 +- src/Algos/TrialPointStats.hpp | 12 +- src/Algos/VNSMads/VNS.cpp | 6 +- src/Algos/VNSMads/VNS.hpp | 12 +- .../WriteAttributeDefinitionFile.cpp | 29 +- .../deprecatedAttributesDefinition.txt | 26 +- src/Attribute/evalAttributesDefinition.txt | 10 +- .../evaluatorControlAttributesDefinition.txt | 29 +- ...uatorControlGlobalAttributesDefinition.txt | 16 + src/Attribute/runAttributesDefinition.txt | 166 +- src/Attribute/runAttributesDefinitionCOOP.txt | 97 + .../runAttributesDefinitionDMulti.txt | 219 + .../runAttributesDefinitionPSDSSD.txt | 106 +- .../runAttributesDefinitionQPSolver.txt | 39 +- .../runAttributesDefinitionQuadModel.txt | 30 +- src/CMakeLists.txt | 105 +- src/CMakeListsLibs.txt | 10 +- src/CMakeListsLibsStatic.txt | 8 +- src/Cache/CacheBase.cpp | 2 +- src/Cache/CacheBase.hpp | 90 +- src/Cache/CacheSet.cpp | 220 +- src/Cache/CacheSet.hpp | 106 +- src/Eval/BBInput.cpp | 2 +- src/Eval/BBInput.hpp | 6 +- src/Eval/BBOutput.cpp | 22 +- src/Eval/BBOutput.hpp | 15 +- src/Eval/BarrierBase.cpp | 53 +- src/Eval/BarrierBase.hpp | 54 +- src/Eval/ComparePriority.cpp | 36 +- src/Eval/ComparePriority.hpp | 34 +- src/Eval/ComputeSuccessType.cpp | 239 +- src/Eval/ComputeSuccessType.hpp | 82 +- src/Eval/Eval.cpp | 323 +- src/Eval/Eval.hpp | 121 +- src/Eval/EvalPoint.cpp | 259 +- src/Eval/EvalPoint.hpp | 87 +- src/Eval/EvalQueuePoint.hpp | 8 +- src/Eval/Evaluator.cpp | 370 +- src/Eval/Evaluator.hpp | 15 +- src/Eval/EvaluatorControl.cpp | 1202 +++-- src/Eval/EvaluatorControl.hpp | 231 +- src/Eval/EvcMainThreadInfo.cpp | 24 +- src/Eval/EvcMainThreadInfo.hpp | 42 +- src/Eval/MeshBase.cpp | 9 +- src/Eval/MeshBase.hpp | 14 +- src/Eval/ProgressiveBarrier.cpp | 176 +- src/Eval/ProgressiveBarrier.hpp | 47 +- src/Eval/SuccessStats.cpp | 29 +- src/Eval/SuccessStats.hpp | 6 +- src/Math/ArrayOfDouble.cpp | 39 +- src/Math/ArrayOfDouble.hpp | 25 +- src/Math/ArrayOfPoint.cpp | 4 +- src/Math/ArrayOfPoint.hpp | 6 +- src/Math/Direction.cpp | 26 +- src/Math/Direction.hpp | 31 +- src/Math/Double.cpp | 95 +- src/Math/Double.hpp | 54 +- src/Math/LHS.cpp | 1 + src/Math/LHS.hpp | 10 +- .../SSDMads.cpp => Math/MathUtils.cpp} | 104 +- src/Math/MathUtils.hpp | 76 + src/Math/MatrixUtils.cpp | 746 ++- src/Math/MatrixUtils.hpp | 141 +- src/Math/Point.cpp | 4 +- src/Math/Point.hpp | 8 +- src/Math/RNG.cpp | 102 +- src/Math/RNG.hpp | 90 +- src/Math/RandomPickup.hpp | 6 +- src/Nomad/nomad.cpp | 2 +- src/Nomad/nomad.hpp | 6 +- src/Output/OutputDirectToFile.cpp | 4 +- src/Output/OutputDirectToFile.hpp | 6 +- src/Output/OutputInfo.hpp | 6 +- src/Output/OutputQueue.cpp | 16 +- src/Output/OutputQueue.hpp | 13 +- src/Output/StatsInfo.cpp | 4 +- src/Output/StatsInfo.hpp | 24 +- src/Param/AllParameters.cpp | 2 +- src/Param/AllParameters.hpp | 28 +- src/Param/Attribute.hpp | 8 +- src/Param/AttributeFactory.hpp | 10 +- src/Param/CacheParameters.cpp | 4 +- src/Param/CacheParameters.hpp | 8 +- src/Param/DeprecatedParameters.hpp | 8 +- src/Param/DisplayParameters.cpp | 4 +- src/Param/DisplayParameters.hpp | 6 +- src/Param/EvalParameters.cpp | 22 +- src/Param/EvalParameters.hpp | 7 +- .../EvaluatorControlGlobalParameters.cpp | 74 +- .../EvaluatorControlGlobalParameters.hpp | 8 +- src/Param/EvaluatorControlParameters.cpp | 5 - src/Param/EvaluatorControlParameters.hpp | 6 +- src/Param/ParameterEntries.cpp | 12 +- src/Param/ParameterEntries.hpp | 10 +- src/Param/ParameterEntry.cpp | 16 +- src/Param/ParameterEntry.hpp | 12 +- src/Param/Parameters.cpp | 174 +- src/Param/Parameters.hpp | 42 +- src/Param/ParametersNomad3.cpp | 14 +- src/Param/ParametersNomad3.hpp | 20 +- src/Param/PbParameters.cpp | 25 +- src/Param/PbParameters.hpp | 6 +- src/Param/RunParameters.cpp | 302 +- src/Param/RunParameters.hpp | 19 +- src/Param/TypeAttribute.hpp | 12 +- src/Type/BBInputType.cpp | 6 +- src/Type/BBInputType.hpp | 8 +- src/Type/BBOutputType.cpp | 18 +- src/Type/BBOutputType.hpp | 11 +- src/Type/CallbackType.hpp | 18 +- src/Type/CompareType.hpp | 6 +- src/Type/ComputeType.cpp | 60 + src/Type/ComputeType.hpp | 79 +- src/Type/DMultiMadsSearchStrategyType.cpp | 136 + src/Type/DMultiMadsSearchStrategyType.hpp | 96 + src/Type/DirectionType.cpp | 66 +- src/Type/DirectionType.hpp | 9 +- src/Type/EvalSortType.cpp | 9 +- src/Type/EvalSortType.hpp | 9 +- src/Type/EvalType.hpp | 6 +- src/Type/LHSearchType.cpp | 4 +- src/Type/LHSearchType.hpp | 6 +- src/Type/ListOfVariableGroup.cpp | 2 +- src/Type/ListOfVariableGroup.hpp | 6 +- src/Type/SgtelibModelFeasibilityType.hpp | 6 +- src/Type/SgtelibModelFormulationType.hpp | 6 +- src/Type/StepType.cpp | 17 +- src/Type/StepType.hpp | 18 +- src/Util/AllStopReasons.cpp | 2 +- src/Util/AllStopReasons.hpp | 8 +- src/Util/ArrayOfString.cpp | 6 +- src/Util/ArrayOfString.hpp | 10 +- src/Util/Clock.hpp | 6 +- src/Util/Exception.cpp | 2 +- src/Util/Exception.hpp | 6 +- src/Util/MicroSleep.hpp | 6 +- src/Util/StopReason.cpp | 91 +- src/Util/StopReason.hpp | 31 +- src/Util/Uncopyable.hpp | 6 +- src/Util/defines.hpp | 13 +- src/Util/fileutils.cpp | 22 +- src/Util/fileutils.hpp | 6 +- src/Util/utils.cpp | 32 +- src/Util/utils.hpp | 6 +- src/nomad_version.hpp | 4 +- 385 files changed, 25037 insertions(+), 7905 deletions(-) create mode 100644 src/Algos/COOPMads/COOPMads.cpp create mode 100644 src/Algos/COOPMads/COOPMads.hpp create mode 100644 src/Algos/COOPMads/CacheSearchMethod.cpp rename src/Algos/{Mads/TemplateSimpleSearchMethod.hpp => COOPMads/CacheSearchMethod.hpp} (80%) create mode 100644 src/Algos/DMultiMads/DMultiMadsExpansionIntLineSearchMethod.cpp create mode 100644 src/Algos/DMultiMads/DMultiMadsExpansionIntLineSearchMethod.hpp create mode 100644 src/Algos/DMultiMads/DMultiMadsMiddlePointSearchMethod.cpp create mode 100644 src/Algos/DMultiMads/DMultiMadsMiddlePointSearchMethod.hpp create mode 100644 src/Algos/DMultiMads/DMultiMadsNMSearchMethod.cpp create mode 100644 src/Algos/DMultiMads/DMultiMadsNMSearchMethod.hpp create mode 100644 src/Algos/DMultiMads/DMultiMadsQuadDMSSearchMethod.cpp create mode 100644 src/Algos/DMultiMads/DMultiMadsQuadDMSSearchMethod.hpp create mode 100644 src/Algos/DMultiMads/DMultiMadsQuadModSearchMethod.cpp create mode 100644 src/Algos/DMultiMads/DMultiMadsQuadModSearchMethod.hpp create mode 100644 src/Algos/Mads/QR2NPollMethod.cpp rename src/Algos/{SSDMads/SSDMads.hpp => Mads/QR2NPollMethod.hpp} (79%) create mode 100644 src/Algos/Mads/UserPollMethod.cpp create mode 100644 src/Algos/Mads/UserPollMethod.hpp create mode 100644 src/Algos/PSDMads/PSDMadsMegaIteration_prev.cpp rename src/Algos/{SSDMads/SSDMadsMegaIteration.hpp => PSDMads/PSDMadsMegaIteration_prev.hpp} (74%) create mode 100644 src/Algos/Projection.cpp create mode 100644 src/Algos/Projection.hpp create mode 100644 src/Algos/QPSolverAlgo/DoglegTRSolver.cpp create mode 100644 src/Algos/QPSolverAlgo/DoglegTRSolver.hpp create mode 100644 src/Algos/QPSolverAlgo/L1AugLagSolver.cpp create mode 100644 src/Algos/QPSolverAlgo/L1AugLagSolver.hpp create mode 100644 src/Algos/QPSolverAlgo/LevenbergMarquardtSolver.cpp create mode 100644 src/Algos/QPSolverAlgo/LevenbergMarquardtSolver.hpp create mode 100644 src/Algos/QPSolverAlgo/ProjectedConjugateGradientSolver.cpp create mode 100644 src/Algos/QPSolverAlgo/ProjectedConjugateGradientSolver.hpp create mode 100644 src/Algos/QPSolverAlgo/QPModelUtils.cpp create mode 100644 src/Algos/QPSolverAlgo/QPModelUtils.hpp create mode 100644 src/Algos/QPSolverAlgo/TRIPMSolver.cpp create mode 100644 src/Algos/QPSolverAlgo/TRIPMSolver.hpp delete mode 100644 src/Algos/SSDMads/SSDMadsMegaIteration.cpp rename src/Algos/{Mads/TemplateSimpleSearchMethod.cpp => SimpleMads/SimpleEvalPoint.cpp} (66%) create mode 100644 src/Algos/SimpleMads/SimpleEvalPoint.hpp create mode 100644 src/Algos/SimpleMads/SimpleMads.cpp create mode 100644 src/Algos/SimpleMads/SimpleMads.hpp create mode 100644 src/Algos/SimpleMads/SimplePoll.cpp create mode 100644 src/Algos/SimpleMads/SimplePoll.hpp create mode 100644 src/Algos/SimpleMads/SimpleProgressiveBarrier.cpp create mode 100644 src/Algos/SimpleMads/SimpleProgressiveBarrier.hpp create mode 100644 src/Attribute/runAttributesDefinitionCOOP.txt create mode 100644 src/Attribute/runAttributesDefinitionDMulti.txt rename src/{Algos/SSDMads/SSDMads.cpp => Math/MathUtils.cpp} (69%) create mode 100644 src/Math/MathUtils.hpp create mode 100644 src/Type/DMultiMadsSearchStrategyType.cpp create mode 100644 src/Type/DMultiMadsSearchStrategyType.hpp diff --git a/src/Algos/AlgoStopReasons.hpp b/src/Algos/AlgoStopReasons.hpp index f47b2eda..6c58c112 100644 --- a/src/Algos/AlgoStopReasons.hpp +++ b/src/Algos/AlgoStopReasons.hpp @@ -44,8 +44,8 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_ALGOSTOPREASONS__ -#define __NOMAD_4_4_ALGOSTOPREASONS__ +#ifndef __NOMAD_4_5_ALGOSTOPREASONS__ +#define __NOMAD_4_5_ALGOSTOPREASONS__ #include // for shared_ptr #include "../Algos/EvcInterface.hpp" // For access to EvalMainThreadStopType @@ -161,4 +161,4 @@ class AlgoStopReasons : public AllStopReasons #include "../nomad_nsend.hpp" -#endif // __NOMAD_4_4_ALGOSTOPREASONS__ +#endif // __NOMAD_4_5_ALGOSTOPREASONS__ diff --git a/src/Algos/Algorithm.cpp b/src/Algos/Algorithm.cpp index 238268af..85d3d72a 100644 --- a/src/Algos/Algorithm.cpp +++ b/src/Algos/Algorithm.cpp @@ -89,7 +89,7 @@ void NOMAD::Algorithm::init() { _isSubAlgo = true; } - + // Check pbParams if needed, ex. if a copy of PbParameters was given to the Algorithm constructor. _pbParams->checkAndComply(); @@ -105,17 +105,24 @@ void NOMAD::Algorithm::init() NOMAD::SubproblemManager::getInstance()->addSubproblem(this, subproblem); _pbParams = subproblem.getPbParams(); _pbParams->checkAndComply(); + + // Set some compute type and h norm type in evaluator control only if not sub algo + // otherwise it is inherited. + // Compute type in evaluator control can be used to initialized barrier compute type + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + if (! _isSubAlgo && nullptr != evc) + { + auto hNormType = _runParams->getAttributeValue("H_NORM"); + auto computeType = NOMAD::ComputeType::STANDARD; // Default compute type is set here. Override only by PhaseOne algo. + evc->setHNormType(hNormType); + evc->setComputeType(computeType); + } /** Step::userInterrupt() will be called if CTRL-C is pressed. * Currently, the main thread will wait for all evaluations to be complete. - * \todo Propage interruption to all threads, for all parallel evaluations of blackbox. */ signal(SIGINT, userInterrupt); - // This signal handling is problematic with Matlab. - // Let's test without it. - // signal(SIGSEGV, debugSegFault); - } @@ -134,16 +141,16 @@ void NOMAD::Algorithm::startImp() _startTime = NOMAD::Clock::getCPUTime(); } #endif // TIME_STATS - - // Reset the current counters. The total counters are not reset (done only once when algo constructor is called. + + // Reset the current counters. The total counters are not reset (done only once when algo constructor is called). _trialPointStats.resetCurrentStats(); - - + + // All stop reasons are reset. _stopReasons->setStarted(); // Default success is reset - // Success type is initialized in Step::defautStart() + // Success type is initialized in Step::defaultStart() _algoSuccessful = false; if (isRootAlgo()) @@ -153,7 +160,7 @@ void NOMAD::Algorithm::startImp() NOMAD::CacheBase::getInstance()->setStopWaiting(false); } - // By default reset the lap counter for BbEval and set the lap maxBbEval to INF + // By default, reset the lap counter for BbEval and set the lap maxBbEval to INF NOMAD::EvcInterface::getEvaluatorControl()->resetLapBbEval(); NOMAD::EvcInterface::getEvaluatorControl()->setLapMaxBbEval( NOMAD::INF_SIZE_T ); NOMAD::EvcInterface::getEvaluatorControl()->resetModelEval(); @@ -194,10 +201,10 @@ void NOMAD::Algorithm::startImp() if (!bestPoints.empty()) { std::transform(bestPoints.begin(), bestPoints.end(), std::back_inserter(x0s), - [](NOMAD::EvalPoint evalPoint) -> NOMAD::EvalPoint { return evalPoint; }); + [](const NOMAD::EvalPoint& evalPoint) -> NOMAD::EvalPoint { return evalPoint; }); } - _pbParams->setAttributeValue("X0", x0s); + _pbParams->setAttributeValue("X0", std::move(x0s)); _pbParams->checkAndComply(); } } @@ -205,7 +212,7 @@ void NOMAD::Algorithm::startImp() void NOMAD::Algorithm::endImp() { - + if ( _endDisplay ) { displayBestSolutions(); @@ -219,23 +226,23 @@ void NOMAD::Algorithm::endImp() displayEvalCounts(); } - + // Update parent if it exists (can be Algo or IterationUtils) with this stats _trialPointStats.updateParentStats(); - + // Reset user algo stop reason if (_stopReasons->testIf(NOMAD::IterStopType::USER_ALGO_STOP)) { _stopReasons->set(NOMAD::IterStopType::STARTED); } - - + + // Update the parent success Step * parentStep = const_cast(_parentStep); parentStep->setSuccessType(_success); - - // By default reset the lap counter for BbEval and set the lap maxBbEval to INF + + // By default, reset the lap counter for BbEval and set the lap maxBbEval to INF NOMAD::EvcInterface::getEvaluatorControl()->resetLapBbEval(); NOMAD::EvcInterface::getEvaluatorControl()->setLapMaxBbEval( NOMAD::INF_SIZE_T ); @@ -281,7 +288,7 @@ void NOMAD::Algorithm::saveInformationForHotRestart() const // ignore initial values, only take latest values down the Parameter tree. // For now, using initial parameters. - // Cache file is treated independently from hot restart file. + // Cache file is treated independently of hot restart file. // As long as the cache file name is set, it is written. // This is the behavior of NOMAD 3. std::string cacheFile = NOMAD::CacheBase::getInstance()->getFileName(); @@ -301,15 +308,20 @@ void NOMAD::Algorithm::saveInformationForHotRestart() const void NOMAD::Algorithm::displayBestSolutions() const { std::vector evalPointList; - // Display best feasible solutions. + // Display the best feasible solutions. std::string sFeas; // Output level is very high if there are no parent algorithm // Output level is info if this algorithm is a sub part of another algorithm. NOMAD::OutputLevel outputLevel = _isSubAlgo ? NOMAD::OutputLevel::LEVEL_INFO : NOMAD::OutputLevel::LEVEL_VERY_HIGH; auto solFormat = NOMAD::OutputQueue::getInstance()->getSolFormat(); - auto computeType = NOMAD::EvcInterface::getEvaluatorControl()->getComputeType(); + + // Complete compute type + NOMAD::FHComputeTypeS computeType = NOMAD::EvcInterface::getEvaluatorControl()->getFHComputeTypeS(); auto evalType = NOMAD::EvcInterface::getEvaluatorControl()->getCurrentEvalType(); + //auto hNormType = NOMAD::EvcInterface::getEvaluatorControl()->getHNormType(); + NOMAD::FHComputeType completeComputeType = {evalType, computeType}; + auto surrogateAsBB = NOMAD::EvcInterface::getEvaluatorControl()->getSurrogateOptimization(); if (isRootAlgo()) { @@ -320,8 +332,8 @@ void NOMAD::Algorithm::displayBestSolutions() const sFeas = "Best feasible solution"; auto barrier = getMegaIterationBarrier(); - - // Let try to build a progressive barrier from the cache + + // Let's try to build a progressive barrier from the cache if (nullptr == barrier) { barrier = std::make_shared(NOMAD::INF, @@ -331,6 +343,7 @@ void NOMAD::Algorithm::displayBestSolutions() const } if (nullptr != barrier) { + barrier->checkForFHComputeType(completeComputeType); for (auto const & p : barrier->getAllXFeas()) { evalPointList.push_back(*p); @@ -348,17 +361,17 @@ void NOMAD::Algorithm::displayBestSolutions() const { sFeas += ": "; displaySolFeas.addMsg(sFeas + evalPointList[0].display(computeType, - solFormat, - NOMAD::DISPLAY_PRECISION_FULL, - surrogateAsBB)); + solFormat, + NOMAD::DISPLAY_PRECISION_FULL, + surrogateAsBB)); } else { sFeas += "s: "; displaySolFeas.addMsg(sFeas + evalPointList[0].display(computeType, - solFormat, - NOMAD::DISPLAY_PRECISION_FULL, - surrogateAsBB)); + solFormat, + NOMAD::DISPLAY_PRECISION_FULL, + surrogateAsBB)); } @@ -392,7 +405,7 @@ void NOMAD::Algorithm::displayBestSolutions() const evalPointList.clear(); - // Display best infeasible solutions. + // Display the best infeasible solutions. std::string sInf; NOMAD::OutputInfo displaySolInf(getName(), sInf, outputLevel); sInf = "Best infeasible solution"; @@ -415,17 +428,17 @@ void NOMAD::Algorithm::displayBestSolutions() const { sInf += ": "; displaySolInf.addMsg(sInf + evalPointList[0].display(computeType, - solFormat, - NOMAD::DISPLAY_PRECISION_FULL, - surrogateAsBB)); + solFormat, + NOMAD::DISPLAY_PRECISION_FULL, + surrogateAsBB)); } else { sInf += "s: "; displaySolInf.addMsg(sInf + evalPointList[0].display(computeType, - solFormat, - NOMAD::DISPLAY_PRECISION_FULL, - surrogateAsBB)); + solFormat, + NOMAD::DISPLAY_PRECISION_FULL, + surrogateAsBB)); } if (nbBestInf > 1) @@ -440,9 +453,9 @@ void NOMAD::Algorithm::displayBestSolutions() const continue; // First element already added } displaySolInf.addMsg(" " + it->display(computeType, - solFormat, - NOMAD::DISPLAY_PRECISION_FULL, - surrogateAsBB)); + solFormat, + NOMAD::DISPLAY_PRECISION_FULL, + surrogateAsBB)); if (solCount >= maxSolCount) { // We printed enough solutions already. @@ -461,7 +474,7 @@ void NOMAD::Algorithm::displayEvalCounts() const // Display evaluation information // _isSubAlgo is used to display or not certain values - + // Output levels will be modulated depending on the counts and on the Algorithm level. NOMAD::OutputLevel outputLevelHigh = _isSubAlgo ? NOMAD::OutputLevel::LEVEL_INFO : NOMAD::OutputLevel::LEVEL_HIGH; @@ -590,7 +603,7 @@ void NOMAD::Algorithm::displayEvalCounts() const { surrogateCost = evc->getEvaluatorControlGlobalParams()->getAttributeValue("EVAL_SURROGATE_COST"); } - + std::string sBbEval = "Blackbox evaluations: " + sFeedBbEval + NOMAD::itos(bbEval); std::string sBbEvalFromCacheForRerun = "Blackbox evaluations from cache (rerun): " + sFeedBbEvalFromCacheForRerun + NOMAD::itos(bbEvalFromCacheForRerun); std::string sLapBbEval = "Sub-optimization blackbox evaluations: " + sFeedLapBbEval + NOMAD::itos(lapBbEval); @@ -689,7 +702,7 @@ NOMAD::EvalPoint NOMAD::Algorithm::getBestSolution(bool bestFeas) const bestSol = bestSolPtr->makeFullSpacePointFromFixed(fixedVariable); } } - + return bestSol; } diff --git a/src/Algos/Algorithm.hpp b/src/Algos/Algorithm.hpp index 794e5c6e..557baa36 100644 --- a/src/Algos/Algorithm.hpp +++ b/src/Algos/Algorithm.hpp @@ -45,8 +45,8 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_ALGORITHM__ -#define __NOMAD_4_4_ALGORITHM__ +#ifndef __NOMAD_4_5_ALGORITHM__ +#define __NOMAD_4_5_ALGORITHM__ #include "../Algos/EvcInterface.hpp" #include "../Algos/Initialization.hpp" @@ -91,9 +91,9 @@ class Algorithm: public Step TrialPointStats _trialPointStats; ///< The trial point counters stats for algo execution - bool _useOnlyLocalFixedVariables ; ///< When this flag is true, we force an algo to use only local fixed variable. The original problem fixed variables are not considered. This is usefull when we change the design space like when doing quad model search. The evaluation of the quad model are only in the sub space and maybe there are some local fixed variables. + bool _useOnlyLocalFixedVariables ; ///< When this flag is true, we force an algo to use only local fixed variable. The original problem fixed variables are not considered. This is useful when we change the design space like when doing quad model search. The evaluation of the quad model are only in the sub space and maybe there are some local fixed variables. - bool _evalOpportunistic; ///< This flag is used to force non opportunistic eval for some algo. The evaluator control function setOpportunisticEval is called with this flag. The parameter EVAL_OPPORTUNISTIC can be temporarily superceeded (example, LH_EVAL + MADS) + bool _evalOpportunistic; ///< This flag is used to force non opportunistic eval for some algo. The evaluator control function setOpportunisticEval is called with this flag. The parameter EVAL_OPPORTUNISTIC can be temporarily superseded (example, LH_EVAL + MADS) public: @@ -209,7 +209,7 @@ class Algorithm: public Step virtual void display(std::ostream& os) const; /// Access to the best solution (can be undefined) - EvalPoint getBestSolution (bool bestFeas = false) const; + virtual EvalPoint getBestSolution (bool bestFeas = false) const; private: @@ -233,4 +233,4 @@ std::istream& operator>>(std::istream& is, Algorithm& algo); #include "../nomad_nsend.hpp" -#endif // __NOMAD_4_4_ALGORITHM__ +#endif // __NOMAD_4_5_ALGORITHM__ diff --git a/src/Algos/COOPMads/COOPMads.cpp b/src/Algos/COOPMads/COOPMads.cpp new file mode 100644 index 00000000..238effdb --- /dev/null +++ b/src/Algos/COOPMads/COOPMads.cpp @@ -0,0 +1,181 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ + + +#include "../../Algos/EvcInterface.hpp" +#include "../../Algos/Mads/Mads.hpp" +#include "../../Algos/Mads/MadsInitialization.hpp" +#include "../../Algos/Mads/MadsUpdate.hpp" +#include "../../Algos/COOPMads/COOPMads.hpp" +#include "../../Algos/COOPMads/CacheSearchMethod.hpp" +#include "../../Cache/CacheBase.hpp" +#include "../../Output/OutputQueue.hpp" +#include "../../Util/MicroSleep.hpp" + + +void NOMAD::COOPMads::init(const std::vector & evaluators, + const std::shared_ptr& evalContParams) +{ + + // This is important for nested parallel regions. A parallel region + // for evaluation queue (for) and parallel region for algos (see in runImp). + omp_set_nested(true); + omp_set_dynamic(false); // Not sure about this one! + + setStepType(NOMAD::StepType::ALGORITHM_COOP_MADS); + verifyParentNotNull(); + + auto blockSize = NOMAD::EvcInterface::getEvaluatorControl()->getEvaluatorControlGlobalParams()->getAttributeValue("BB_MAX_BLOCK_SIZE"); + if (blockSize > 1) + { + throw NOMAD::Exception(__FILE__, __LINE__, "COOP-Mads: eval points blocks are not supported."); + } + + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + + // Check the number of parallel evaluation handled by the evaluator control + OUTPUT_INFO_START + if (evc->getNbThreadsForParallelEval() != 1) + { + + std::string s = "Warning: In addition to threads used by COOP Mads, several threads are used for parallel evaluations of trial points. This option has not been fully tested!"; + AddOutputInfo(s); + } + OUTPUT_INFO_END + + // Instanciate MadsInitialization member (to comment) + _initialization = std::make_unique(this); + + // Initialize all the main threads (algo main threads) we will need. + // Add an evaluator for each thread and a default evaluator type. + // The main threads will be the ones with thread numbers 0-(nbMainThreads-1). + // Main thread 0 is already added to EvaluatorControl at its creation. + size_t nbMainThreads = _runParams->getAttributeValue("COOP_MADS_NB_PROBLEM"); + for (int mainThreadNum = 1; mainThreadNum < (int)nbMainThreads; mainThreadNum++) + { + auto problemEvalContParams = std::make_unique(*evalContParams); + problemEvalContParams->checkAndComply(); + + // add a main thread + evc->addMainThread(mainThreadNum, std::move(problemEvalContParams)); + // Add evaluators to the main thread + for (const auto & ev: evaluators ) + { + // The same evaluators are used by all mainThreads (no move(ev)). + evc->addEvaluator(ev,mainThreadNum); + } + // Select BB evaluator. Otherwise, the last one added is used. + evc->setCurrentEvaluatorType(NOMAD::EvalType::BB, mainThreadNum); + } +} + +bool NOMAD::COOPMads::runImp() +{ + + // Set parameters for problems + auto problemPbParams = std::make_shared(*_pbParams); + auto problemRunParams = std::make_shared(*_runParams); + problemPbParams->checkAndComply(); + + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + auto evcParams = evc->getEvaluatorControlGlobalParams(); + problemRunParams->checkAndComply(evcParams, problemPbParams); + + size_t t = _runParams->getAttributeValue("COOP_MADS_NB_PROBLEM"); +#pragma omp parallel num_threads(t) default(none) shared(problemRunParams,problemPbParams,evc) + { + auto madsStopReasons = std::make_shared>(); + NOMAD::Mads madsOnPb(this, madsStopReasons, problemRunParams, problemPbParams); + + + // Special cache search method for coop-mads. Insert at first position. + // The cache search is used to synchronize the best incumbents between + // the mads. + // During Search initialization, the extra search methods will be transferred from + // Mads to the Search. + auto cacheSearch = std::make_shared(this); + madsOnPb.insertSearchMethod(0,cacheSearch); + + int mainThreadNum = NOMAD::getThreadNum(); + + OUTPUT_INFO_START + std::string s = "Running " + madsOnPb.getName(); + s += " on thread " + NOMAD::itos(mainThreadNum); + AddOutputInfo(s); + OUTPUT_INFO_END + + madsOnPb.start(); + bool madsSuccessful = madsOnPb.run(); + madsOnPb.end(); + + OUTPUT_INFO_START + std::string s = "Done running " + madsOnPb.getName(); + s += " on thread " + NOMAD::itos(mainThreadNum) + ". "; + s += "Number of evaluations: " + NOMAD::itos(evc->getBbEvalInSubproblem()) + ". "; // Modify when ready for getBbEvalInProblem() + if (cacheSearch->isEnabled()) + { + s += "Number of cache search trial points generated (successes): " + NOMAD::itos(cacheSearch->getNbTrialPointsGenerated(NOMAD::EvalType::BB)); + + } + + AddOutputInfo(s); + OUTPUT_INFO_END + + // Done stop waiting in cache. + NOMAD::CacheBase::getInstance()->setStopWaiting(true); + } + + return true; +} + +void NOMAD::COOPMads::endImp() +{ + _termination->start(); + _termination->run(); + _termination->end(); + NOMAD::Algorithm::endImp(); +} diff --git a/src/Algos/COOPMads/COOPMads.hpp b/src/Algos/COOPMads/COOPMads.hpp new file mode 100644 index 00000000..2585a298 --- /dev/null +++ b/src/Algos/COOPMads/COOPMads.hpp @@ -0,0 +1,102 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#ifndef __NOMAD_4_5_COOPMADS__ +#define __NOMAD_4_5_COOPMADS__ + +#include "../../Algos/AlgoStopReasons.hpp" +#include "../../Algos/Algorithm.hpp" +#include "../../Eval/Evaluator.hpp" + +#include "../../nomad_nsbegin.hpp" + +// Class for COOP-Mads +class COOPMads: public Algorithm +{ +public: + /// Constructor + /** + \param parentStep The parent of this step -- \b IN. + \param evaluators The Evaluators to initialize all main threads -- \b IN. + \param evalContParams Parameters to initialize all main threads -- \b IN. + \param stopReasons The COOP Mads stop reasons -- \b IN/OUT. + \param runParams Parameters for algorithm -- \b IN. + \param refPbParams Parameters for original optimization problem. PSD-Mads use its own copy -- \b IN. + */ + explicit COOPMads(const Step* parentStep, + const std::vector& evaluators, + const std::shared_ptr& evalContParams, + std::shared_ptr> stopReasons, + const std::shared_ptr& runParams, + const std::shared_ptr& refPbParams) + : Algorithm(parentStep, stopReasons, runParams, std::make_shared(*refPbParams)) + { + init(evaluators, evalContParams); + } + + virtual ~COOPMads() + { + } + + virtual void startImp() override {}; + virtual bool runImp() override; + virtual void endImp() override; + + void readInformationForHotRestart() override {} + +private: + + /// Helper for constructor + void init(const std::vector& evaluators, + const std::shared_ptr& evalContParams); + + + +}; + +#include "../../nomad_nsend.hpp" + +#endif // __NOMAD_4_5_COOPMADS__ diff --git a/src/Algos/COOPMads/CacheSearchMethod.cpp b/src/Algos/COOPMads/CacheSearchMethod.cpp new file mode 100644 index 00000000..0774eecf --- /dev/null +++ b/src/Algos/COOPMads/CacheSearchMethod.cpp @@ -0,0 +1,188 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ + +#include "../../Cache/CacheBase.hpp" +#include "../../Algos/CacheInterface.hpp" +#include "../../Algos/COOPMads/CacheSearchMethod.hpp" +#include "../../Algos/Mads/MadsMegaIteration.hpp" +#include "../../Algos/SubproblemManager.hpp" +#include "../../Eval/ProgressiveBarrier.hpp" +#include "../../Algos/EvcInterface.hpp" + +void NOMAD::CacheSearchMethod::init() +{ + + setStepType(NOMAD::StepType::SEARCH_METHOD_CACHE); + + const auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + + if (evc->getCurrentEvalType() == NOMAD::EvalType::MODEL) + { + setEnabled(false); + return; + } + if (!evc->getUseCache()) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For COOP-Mads cache search, we need a cache."); + } + + const bool isEnabled = getRunParams()->getAttributeValue("COOP_MADS_OPTIMIZATION_CACHE_SEARCH"); + setEnabled(isEnabled); + +} + + +void NOMAD::CacheSearchMethod::generateTrialPointsFinal() +{ + + // Get the barrier. + if (nullptr == _megaIterAncestor) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For COOP-Mads cache search, we need a MegaIteration among the parents."); + } + auto barrier = _megaIterAncestor->getBarrier(); + if (nullptr == barrier) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For COOP-Mads cache search, we need a MegaIteration among the parents with a barrier."); + } + auto computeType = barrier->getFHComputeType(); + + // Look in the cache for the best feasible points + NOMAD::CacheInterface cacheInterface(this); + std::vector evalPointList; + cacheInterface.findBestFeas(evalPointList, computeType); + for (auto & ep: evalPointList) + { + // Test best points on barrier + if ( NOMAD::SuccessType::FULL_SUCCESS == barrier->getSuccessTypeOfPoints(std::make_shared(ep), nullptr)) + { + OUTPUT_INFO_START + std::string s = "Cache search found a point in cache that dominates the best feasible point in barrier: "; + s += ep.display(computeType.Short()) ; + AddOutputInfo(s); + OUTPUT_INFO_END + + // Update point from using current feasible incumbent + NOMAD::Point fixedVariable = NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(NOMAD::IterationUtils::_parentStep); + + ep.setPointFrom(barrier->getCurrentIncumbentFeas(), fixedVariable); + + insertTrialPoint(ep); + } + } + // Look in the cache for the best infeasible points + cacheInterface.findBestInf(evalPointList, barrier->getHMax(), computeType); + for (auto & ep: evalPointList) + { + if ( NOMAD::SuccessType::FULL_SUCCESS == barrier->getSuccessTypeOfPoints(std::make_shared(ep), nullptr)) + { + OUTPUT_INFO_START + std::string s = "Cache search found a point in cache that dominates one of the best infeasible point in barrier: "; + s += ep.display(computeType.Short()) ; + AddOutputInfo(s); + OUTPUT_INFO_END + + // Update point from using current feasible incumbent + NOMAD::Point fixedVariable = NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(NOMAD::IterationUtils::_parentStep); + + ep.setPointFrom(barrier->getCurrentIncumbentInf(), fixedVariable); + + insertTrialPoint(ep); + } + } + +} + +bool NOMAD::CacheSearchMethod::evalTrialPoints(const NOMAD::Step *step, + const size_t keepN, + NOMAD::StepType removeStepType) +{ + if (_trialPoints.size()==0) + { + return false; + } + + // Trial points should not be re-evaluated because + // they are already in cache. We consider it is a success. + NOMAD::EvcInterface evcInterface(step); + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + + if (!evc->getUseCache()) + { + throw NOMAD::Exception(__FILE__, __LINE__,"Must use cache to determine if trial points are success"); + } + + if ( evcInterface.countPointsThatNeedEval(_trialPoints) != 0) + { + throw NOMAD::Exception(__FILE__, __LINE__,"No trial point should need evaluation."); + } + + // After generation, the trial points have no eval avail. + // Let's update the trial points with evaluation from cache. + NOMAD::CacheInterface cacheInterface(this); + NOMAD::EvalPointSet evalPointSet; + for (const auto & tp: _trialPoints) + { + NOMAD::EvalPoint ep; + cacheInterface.find(*tp.getX(), ep); + evalPointSet.insert(ep); + } + _trialPoints.clear(); + _trialPoints = evalPointSet; + + + _trialPointsSuccess = NOMAD::SuccessType::FULL_SUCCESS; + + // Propagate trial points success type to generating method step (for example, poll and search) + setSuccessType(_trialPointsSuccess); + + // Update step success stats from evc success stats + updateStepSuccessStats(this); + + return true /* trial points are always considered as better */; +} + diff --git a/src/Algos/Mads/TemplateSimpleSearchMethod.hpp b/src/Algos/COOPMads/CacheSearchMethod.hpp similarity index 80% rename from src/Algos/Mads/TemplateSimpleSearchMethod.hpp rename to src/Algos/COOPMads/CacheSearchMethod.hpp index cda6de1a..11803fab 100644 --- a/src/Algos/Mads/TemplateSimpleSearchMethod.hpp +++ b/src/Algos/COOPMads/CacheSearchMethod.hpp @@ -44,45 +44,58 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_TEMPLATESIMPLESEARCHMETHOD__ -#define __NOMAD_4_4_TEMPLATESIMPLESEARCHMETHOD__ +#ifndef __NOMAD_4_5_CACHESEARCHMETHOD__ +#define __NOMAD_4_5_CACHESEARCHMETHOD__ +#include "../../Algos/AlgoStopReasons.hpp" #include "../../Algos/Mads/SearchMethodSimple.hpp" -#include "../../nomad_nsbegin.hpp" +#include "../../nomad_nsbegin.hpp" -/// Template example for simple search method. -/** -Called when RANDOM_SIMPLE_SEARCH is enabled. - - Can be used as a TEMPLATE for a new search method: copy and rename the file and the class name. Adapt the code to your needs. It is IMPORTANT to register the new search method in ../Algos/Mads/Search.cpp (NOMAD::Search::init()). - */ -class TemplateSimpleSearchMethod final : public SearchMethodSimple +/// Class to perform a Cache Search for COOP-Mads optimization algorithm. +class CacheSearchMethod final : public SearchMethodSimple { +private: + + public: /// Constructor /** - \param parentStep The parent of this search step -- \b IN. + /param parentStep The parent of this search step -- \b IN. */ - explicit TemplateSimpleSearchMethod(const Step* parentStep ) - : SearchMethodSimple( parentStep ) + explicit CacheSearchMethod(const Step* parentStep) + : SearchMethodSimple(parentStep) { init(); } + + virtual bool evalTrialPoints(const Step* step, + const size_t keepN = INF_SIZE_T, + StepType removeStepType = StepType::UNDEFINED) override; private: + + + + /// Helper for constructor. + /** + Test if the quad model search is enabled or not. + */ void init(); - /// Generate new points to evaluate + /// Generate new points (no evaluation) /** - \copydoc SearchMethodSimple::generateTrialPointsFinal \n - The search method generates random trial points around best incumbent . + \copydoc SearchMethodAlgo::generateTrialPointsFinal + Perform one quad model optimization to produce trial points. */ - void generateTrialPointsFinal() override; + virtual void generateTrialPointsFinal() override; + + }; #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_TEMPLATESIMPLESEARCHMETHOD__ +#endif // __NOMAD_4_5_CACHESEARCHMETHOD__ + diff --git a/src/Algos/CacheInterface.cpp b/src/Algos/CacheInterface.cpp index f7d38f55..b07657fa 100644 --- a/src/Algos/CacheInterface.cpp +++ b/src/Algos/CacheInterface.cpp @@ -83,13 +83,11 @@ size_t NOMAD::CacheInterface::find(const NOMAD::Point& x, size_t NOMAD::CacheInterface::findBestFeas(std::vector &evalPointList, - NOMAD::EvalType evalType, - NOMAD::ComputeType computeType) const + const NOMAD::FHComputeType& computeType) const { // Cache holds the full dimension points. // Return a list of sub dimension points. - NOMAD::CacheBase::getInstance()->findBestFeas(evalPointList, _fixedVariable, - evalType, computeType); + NOMAD::CacheBase::getInstance()->findBestFeas(evalPointList, _fixedVariable, computeType); NOMAD::convertPointListToSub(evalPointList, _fixedVariable); @@ -99,14 +97,12 @@ size_t NOMAD::CacheInterface::findBestFeas(std::vector &evalPo size_t NOMAD::CacheInterface::findBestInf(std::vector & evalPointList, const NOMAD::Double& hMax, - NOMAD::EvalType evalType, - NOMAD::ComputeType computeType) const + const NOMAD::FHComputeType& computeType) const { // Cache holds the full dimension points. // Return a list of sub dimension points. NOMAD::CacheBase::getInstance()->findBestInf(evalPointList, hMax, - _fixedVariable, evalType, - computeType); + _fixedVariable, computeType); NOMAD::convertPointListToSub(evalPointList, _fixedVariable); diff --git a/src/Algos/CacheInterface.hpp b/src/Algos/CacheInterface.hpp index a1caa6a5..0fbdf369 100644 --- a/src/Algos/CacheInterface.hpp +++ b/src/Algos/CacheInterface.hpp @@ -45,8 +45,8 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_CACHEINTERFACE__ -#define __NOMAD_4_4_CACHEINTERFACE__ +#ifndef __NOMAD_4_5_CACHEINTERFACE__ +#define __NOMAD_4_5_CACHEINTERFACE__ #include "Step.hpp" @@ -81,35 +81,31 @@ class CacheInterface /// Find best feasible point(s) in cache /** \param evalPointList The found evaluation points -- \b OUT. - \param evalType Criterion for EvalType -- \b IN. - \param computeType Criterion for ComputType -- \b IN. + \param computeType Which type of f, h computation (eval type, compute type and h norm type) -- \b IN. \return Number of points found */ size_t findBestFeas(std::vector &evalPointList, - EvalType evalType, - ComputeType computeType) const; + const FHComputeType& computeType) const; /// Find best infeasible points in cache with h<=hmax: - /// -> index 0 and above if doublons, least infeasible point with smallest f - /// -> last index and below if doublons, best f with smallest h - /// All best f points have the same bboutputs. Idem for the least infeasible points. + /// -> index 0 and above if duplicates, least infeasible point with smallest f + /// -> last index and below if duplicates, best f with smallest h + /// All best f points have the same blackbox outputs. Idem for the least infeasible points. /** \param evalPointList The found evaluation points -- \b OUT. \param hMax Points' h value must be under this value -- \b IN. - \param evalType Points' EvalType to look at -- \b IN. - \param computeType Points' ComputType to look at -- \b IN. + \param computeType Which type of f, h computation (eval type, compute type and h norm type) -- \b IN. \return Number of points found */ size_t findBestInf(std::vector &evalPointList, const Double& hMax, - EvalType evalType, - ComputeType computeType) const; + const FHComputeType& computeType) const; /// Interface for CacheBase::smartInsert. /** The full dimension point is reconstructed from step fixed variables information. \param evalPoint The point to insert -- \b IN. - \param maxNumberEval Maximun number of times this point may be evaluated -- \b IN. + \param maxNumberEval Maximum number of times this point may be evaluated -- \b IN. \param evalType Criteria for EvalType -- \b IN. \return \c True if the point may be sent for evaluation, \c false otherwise */ @@ -156,4 +152,4 @@ class CacheInterface #include "../nomad_nsend.hpp" -#endif // __NOMAD_4_4_CACHEINTERFACE__ +#endif // __NOMAD_4_5_CACHEINTERFACE__ diff --git a/src/Algos/CoordinateSearch/CS.cpp b/src/Algos/CoordinateSearch/CS.cpp index a0f62d4a..25a50a86 100644 --- a/src/Algos/CoordinateSearch/CS.cpp +++ b/src/Algos/CoordinateSearch/CS.cpp @@ -178,7 +178,7 @@ void NOMAD::CS::readInformationForHotRestart() { // Restart from where we were before. // For this, we need to read some files. - // Note: Cache file is treated independently from hot restart file. + // Note: Cache file is treated independently of hot restart file. if (_runParams->getAttributeValue("HOT_RESTART_READ_FILES")) { diff --git a/src/Algos/CoordinateSearch/CS.hpp b/src/Algos/CoordinateSearch/CS.hpp index 1ad3d630..673db49a 100644 --- a/src/Algos/CoordinateSearch/CS.hpp +++ b/src/Algos/CoordinateSearch/CS.hpp @@ -44,8 +44,8 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_CS__ -#define __NOMAD_4_4_CS__ +#ifndef __NOMAD_4_5_CS__ +#define __NOMAD_4_5_CS__ #include "../../Algos/Algorithm.hpp" #include "../../Algos/AlgoStopReasons.hpp" @@ -55,7 +55,6 @@ /// Class for Coordinate Search algorithm sampling. /** Generate the trial points using CS and evaluate them. CS is one of the historic ancestor of Mads. CS shares several steps with Mads. - \todo Complete documentation */ class CS: public Algorithm { @@ -103,4 +102,4 @@ class CS: public Algorithm #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_CS__ +#endif // __NOMAD_4_5_CS__ diff --git a/src/Algos/CoordinateSearch/CSInitialization.hpp b/src/Algos/CoordinateSearch/CSInitialization.hpp index 37d3e6a2..a088b5c3 100644 --- a/src/Algos/CoordinateSearch/CSInitialization.hpp +++ b/src/Algos/CoordinateSearch/CSInitialization.hpp @@ -45,8 +45,8 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_CSINITIALIZATION__ -#define __NOMAD_4_4_CSINITIALIZATION__ +#ifndef __NOMAD_4_5_CSINITIALIZATION__ +#define __NOMAD_4_5_CSINITIALIZATION__ #include "../../Algos/Mads/MadsInitialization.hpp" @@ -84,4 +84,4 @@ class CSInitialization final: public MadsInitialization #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_CSINITIALIZATION__ +#endif // __NOMAD_4_5_CSINITIALIZATION__ diff --git a/src/Algos/CoordinateSearch/CSIteration.hpp b/src/Algos/CoordinateSearch/CSIteration.hpp index ffdcf1f2..573f8e7d 100644 --- a/src/Algos/CoordinateSearch/CSIteration.hpp +++ b/src/Algos/CoordinateSearch/CSIteration.hpp @@ -44,8 +44,8 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_CSSITERATION__ -#define __NOMAD_4_4_CSSITERATION__ +#ifndef __NOMAD_4_5_CSSITERATION__ +#define __NOMAD_4_5_CSSITERATION__ #include "../../Algos/CoordinateSearch/CSPoll.hpp" #include "../../Algos/Iteration.hpp" @@ -66,6 +66,7 @@ class CSIteration: public Iteration std::unique_ptr _csPoll; + public: /// Constructor /** @@ -112,7 +113,7 @@ class CSIteration: public Iteration /// Implementation of the run tasks of CS algorithm. /** - Run a CS iteration: a sinle CS Poll step is performed. + Run a CS iteration: a single CS Poll step is performed. */ virtual bool runImp() override; @@ -123,4 +124,4 @@ class CSIteration: public Iteration #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_CSITERATION__ +#endif // __NOMAD_4_5_CSITERATION__ diff --git a/src/Algos/CoordinateSearch/CSMegaIteration.hpp b/src/Algos/CoordinateSearch/CSMegaIteration.hpp index a0845441..8e918bb5 100644 --- a/src/Algos/CoordinateSearch/CSMegaIteration.hpp +++ b/src/Algos/CoordinateSearch/CSMegaIteration.hpp @@ -45,8 +45,8 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_CSMEGAITERATION__ -#define __NOMAD_4_4_CSMEGAITERATION__ +#ifndef __NOMAD_4_5_CSMEGAITERATION__ +#define __NOMAD_4_5_CSMEGAITERATION__ #include "../../Algos/CoordinateSearch/CSIteration.hpp" #include "../../Algos/MegaIteration.hpp" @@ -129,5 +129,5 @@ std::istream& operator>>(std::istream& is, CSMegaIteration& megaIteration); #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_CSMEGAITERATION__ +#endif // __NOMAD_4_5_CSMEGAITERATION__ diff --git a/src/Algos/CoordinateSearch/CSMesh.cpp b/src/Algos/CoordinateSearch/CSMesh.cpp index ed7c2376..1be7e3a2 100644 --- a/src/Algos/CoordinateSearch/CSMesh.cpp +++ b/src/Algos/CoordinateSearch/CSMesh.cpp @@ -188,7 +188,7 @@ void NOMAD::CSMesh::refineDeltaFrameSize() void NOMAD::CSMesh::refineDeltaFrameSize(NOMAD::Double &frameSize, - const NOMAD::Double &granularity) const + const NOMAD::Double& /*granularity*/) const { frameSize *= 0.5; } @@ -262,7 +262,7 @@ NOMAD::Double NOMAD::CSMesh::getdeltaMeshSize(size_t i) const NOMAD::Double NOMAD::CSMesh::getdeltaMeshSize(const NOMAD::Double& frameSize, - const NOMAD::Double& granularity) const + const NOMAD::Double& /*granularity*/) const { NOMAD::Double delta = frameSize * 0.5; @@ -319,8 +319,8 @@ NOMAD::Double NOMAD::CSMesh::getDeltaFrameSizeCoarser(const size_t i) const // This method is used by the input operator>> void NOMAD::CSMesh::setDeltas(const size_t i, - const NOMAD::Double &deltaMeshSize, - const NOMAD::Double &deltaFrameSize) + const NOMAD::Double &deltaMeshSize, + const NOMAD::Double &deltaFrameSize) { // Value to use for granularity (division so default = 1.0) @@ -328,7 +328,7 @@ void NOMAD::CSMesh::setDeltas(const size_t i, NOMAD::Double gran = 1.0; if (0.0 < _granularity[i]) { - gran = _granularity[i]; + _granularity[i] = gran; } _frameSize[i] = deltaFrameSize; @@ -399,14 +399,14 @@ NOMAD::Point NOMAD::CSMesh::projectOnMesh(const NOMAD::Point& point, const NOMAD::Point& frameCenter) const { // Projection on the mesh - NOMAD::Point proj = point; + const NOMAD::Point& proj = point; auto delta = getdeltaMeshSize(); // To avoid running around in circles const size_t maxNbTry = 10; for (size_t i = 0; i < point.size(); ++i) { - const NOMAD::Double deltaI = delta[i]; + const NOMAD::Double& deltaI = delta[i]; bool frameCenterIsOnMesh = (frameCenter[i].isMultipleOf(deltaI)); NOMAD::Double diffProjFrameCenter = proj[i] - frameCenter[i]; @@ -482,7 +482,7 @@ NOMAD::Point NOMAD::CSMesh::projectOnMesh(const NOMAD::Point& point, if (nbTry >= maxNbTry && !verifValueI.isMultipleOf(deltaI)) { - // Some values are just ill-conditionned. + // Some values are just ill-conditioned. std::string s = "Warning: Could not project point (index " + std::to_string(i) + ") "; s += point.display() + " on mesh " + delta.display(); s += " with frame center " + frameCenter.display(); diff --git a/src/Algos/CoordinateSearch/CSMesh.hpp b/src/Algos/CoordinateSearch/CSMesh.hpp index 3737af2f..b8a5069c 100644 --- a/src/Algos/CoordinateSearch/CSMesh.hpp +++ b/src/Algos/CoordinateSearch/CSMesh.hpp @@ -46,8 +46,8 @@ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_CSMESH__ -#define __NOMAD_4_4_CSMESH__ +#ifndef __NOMAD_4_5_CSMESH__ +#define __NOMAD_4_5_CSMESH__ #include "../../Eval/MeshBase.hpp" @@ -60,6 +60,7 @@ The frame size for each variable is parameterized with one or two attributes: CSMesh::_frameSize, and CSMesh::_granularity (Delta = gran * frameSize). The first attribute is for variable having a specified minimal granularity (for example, integers have a minimal granularity of 1). This ensures that variables are always a multiple of the granularity if it is defined. The mesh size is delta = Delta/2. + Note: Possible refactoring. Maybe we could derive from GMesh to avoid rewriting some functions (projectOnMesh, scaleAndProjectOnMesh, maybe more). */ class CSMesh: public MeshBase @@ -142,7 +143,7 @@ class CSMesh: public MeshBase public: // - // The documentation of overriden function is provided in the base class. + // The documentation of override function is provided in the base class. // ArrayOfDouble getDeltaFrameSize() const override; @@ -195,5 +196,5 @@ class CSMesh: public MeshBase #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_GMESH__ +#endif // __NOMAD_4_5_GMESH__ diff --git a/src/Algos/CoordinateSearch/CSPoll.cpp b/src/Algos/CoordinateSearch/CSPoll.cpp index b15a1147..fe702b71 100644 --- a/src/Algos/CoordinateSearch/CSPoll.cpp +++ b/src/Algos/CoordinateSearch/CSPoll.cpp @@ -91,7 +91,7 @@ void NOMAD::CSPoll::startImp() } -void NOMAD::CSPoll::createPollMethods(const bool isPrimary, const EvalPointPtr frameCenter) +void NOMAD::CSPoll::createPollMethods(const bool isPrimary, const EvalPointPtr& frameCenter) { _frameCenters.push_back(frameCenter); auto pollMethod = std::make_shared(this, frameCenter); diff --git a/src/Algos/CoordinateSearch/CSPoll.hpp b/src/Algos/CoordinateSearch/CSPoll.hpp index 9dac91ad..8e014ff3 100644 --- a/src/Algos/CoordinateSearch/CSPoll.hpp +++ b/src/Algos/CoordinateSearch/CSPoll.hpp @@ -45,8 +45,8 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_CSPOLL__ -#define __NOMAD_4_4_CSPOLL__ +#ifndef __NOMAD_4_5_CSPOLL__ +#define __NOMAD_4_5_CSPOLL__ #include "../../Algos/Mads/Poll.hpp" @@ -78,7 +78,7 @@ class CSPoll final : public Poll protected: /// Helper for start: create CS poll method - void createPollMethods(const bool isPrimary, const EvalPointPtr frameCenter) override; + void createPollMethods(const bool isPrimary, const EvalPointPtr& frameCenter) override; virtual void setMeshPrecisionStopType() override; @@ -89,6 +89,6 @@ class CSPoll final : public Poll #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_CSPOLL__ +#endif // __NOMAD_4_5_CSPOLL__ diff --git a/src/Algos/CoordinateSearch/CSPollMethod.hpp b/src/Algos/CoordinateSearch/CSPollMethod.hpp index bae640ad..e0dbeb34 100644 --- a/src/Algos/CoordinateSearch/CSPollMethod.hpp +++ b/src/Algos/CoordinateSearch/CSPollMethod.hpp @@ -45,8 +45,8 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_CSPOLLMETHOD__ -#define __NOMAD_4_4_CSPOLLMETHOD__ +#ifndef __NOMAD_4_5_CSPOLLMETHOD__ +#define __NOMAD_4_5_CSPOLLMETHOD__ #include "../../Algos/Mads/PollMethodBase.hpp" @@ -54,7 +54,7 @@ /** Class to perform CS Poll: generate poll directions, create the trial points and perform evaluations. - The CS poll directions consists of unitary direction of each coordinate separetely, that is north, south, east and west directions in 2D. + The CS poll directions consists of unitary direction of each coordinate separately, that is north, south, east and west directions in 2D. Only the generation of poll directions is implemented in this class, the remaining tasks are performed by derived classes. */ class CSPollMethod final : public PollMethodBase @@ -91,4 +91,4 @@ class CSPollMethod final : public PollMethodBase #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_CSPOLLMETHOD__ +#endif // __NOMAD_4_5_CSPOLLMETHOD__ diff --git a/src/Algos/CoordinateSearch/CSUpdate.cpp b/src/Algos/CoordinateSearch/CSUpdate.cpp index 0ab1ba4f..e83e03aa 100644 --- a/src/Algos/CoordinateSearch/CSUpdate.cpp +++ b/src/Algos/CoordinateSearch/CSUpdate.cpp @@ -76,19 +76,18 @@ std::string NOMAD::CSUpdate::getName() const bool NOMAD::CSUpdate::runImp() { - auto evc = NOMAD::EvcInterface::getEvaluatorControl(); - NOMAD::EvalType evalType = NOMAD::EvalType::BB; - NOMAD::ComputeType computeType = NOMAD::ComputeType::STANDARD; - if (nullptr != evc) - { - evalType = evc->getCurrentEvalType(); - computeType = evc->getComputeType(); - } // megaIter barrier is already in subproblem. // So no need to convert refBestFeas and refBestInf // from full dimension to subproblem. auto megaIter = getParentOfType(); auto barrier = megaIter->getBarrier(); + + auto computeType = barrier->getFHComputeType(); + NOMAD::EvalType evalType = computeType.evalType; + NOMAD::FHComputeTypeS computeTypeS = computeType.fhComputeTypeS; + + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + auto mesh = megaIter->getMesh(); std::string s; // for output @@ -103,7 +102,7 @@ bool NOMAD::CSUpdate::runImp() OUTPUT_DEBUG_END // Barrier is already updated from previous steps. - // Get ref best feasible and infeasible, and then update + // Get the best feasible and infeasible reference points, and then update // reference values. auto refBestFeas = barrier->getRefBestFeas(); auto refBestInf = barrier->getRefBestInf(); @@ -118,7 +117,7 @@ bool NOMAD::CSUpdate::runImp() // Compute success // Get which of newBestFeas and newBestInf is improving // the solution. Check newBestFeas first. - NOMAD::ComputeSuccessType computeSuccess(evalType, computeType); + NOMAD::ComputeSuccessType computeSuccess(computeType); NOMAD::EvalPointPtr newBest; NOMAD::SuccessType success = computeSuccess(newBestFeas, refBestFeas); @@ -201,19 +200,19 @@ bool NOMAD::CSUpdate::runImp() s += ". Is different than computed success type: " + NOMAD::enumStr(success); if (refBestFeas) { - s += "\nRef best feasible: " + refBestFeas->displayAll(); + s += "\nRef best feasible: " + refBestFeas->displayAll(computeTypeS); } if (newBestFeas) { - s += "\nNew best feasible: " + newBestFeas->displayAll(); + s += "\nNew best feasible: " + newBestFeas->displayAll(computeTypeS); } if (refBestInf) { - s += "\nRef best infeasible: " + refBestInf->displayAll(); + s += "\nRef best infeasible: " + refBestInf->displayAll(computeTypeS); } if (newBestInf) { - s += "\nNew best infeasible: " + newBestInf->displayAll(); + s += "\nNew best infeasible: " + newBestInf->displayAll(computeTypeS); } AddOutputWarning(s); } diff --git a/src/Algos/CoordinateSearch/CSUpdate.hpp b/src/Algos/CoordinateSearch/CSUpdate.hpp index e86619b2..e838429e 100644 --- a/src/Algos/CoordinateSearch/CSUpdate.hpp +++ b/src/Algos/CoordinateSearch/CSUpdate.hpp @@ -45,8 +45,8 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_CSUPDATE__ -#define __NOMAD_4_4_CSUPDATE__ +#ifndef __NOMAD_4_5_CSUPDATE__ +#define __NOMAD_4_5_CSUPDATE__ #include "../../Algos/Step.hpp" @@ -85,7 +85,7 @@ class CSUpdate: public Step from the cache, and updates the MegaIteration's Barrier member with it. Compares new values of xFeas and xInf with previous ones - i.e., compute success or failure. - Enlarges or shrinks the delta (mesh size) ( à enlever) and Delta (frame size) + Enlarges or shrinks the delta (mesh size) ( to remove) and Delta (frame size) accordingly. */ virtual bool runImp() override; @@ -97,5 +97,5 @@ class CSUpdate: public Step #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_CSUPDATE__ +#endif // __NOMAD_4_5_CSUPDATE__ diff --git a/src/Algos/DMultiMads/DMultiMads.cpp b/src/Algos/DMultiMads/DMultiMads.cpp index 9c20769f..a2567a0d 100644 --- a/src/Algos/DMultiMads/DMultiMads.cpp +++ b/src/Algos/DMultiMads/DMultiMads.cpp @@ -63,7 +63,7 @@ void NOMAD::DMultiMads::init() // Instantiate algorithm Initialization class (Start function automatically called) // The Mads initialization manages Mesh and X0 _initialization = std::make_unique( this, true /*use Cache for barrier init*/, true /*initialization for DMultiMads*/ ); - + if (NOMAD::Algorithm::getNbObj() < 2) { throw NOMAD::InvalidParameter(__FILE__,__LINE__,"DMultiMads is intended to solve problems with more than one objective."); @@ -73,7 +73,7 @@ void NOMAD::DMultiMads::init() bool NOMAD::DMultiMads::runImp() { _algoSuccessful = false; - + if ( !_runParams->getAttributeValue("DMULTIMADS_OPTIMIZATION") ) { throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMads is a standalone optimization algo. Cannot be used as a Mads search method."); @@ -85,7 +85,7 @@ bool NOMAD::DMultiMads::runImp() // DMultiMadsBarrier created during Initialization (with X0). std::shared_ptr barrier = _initialization->getBarrier(); - + // Mesh created during Initialization NOMAD::MeshBasePtr initialMesh = dynamic_cast(_initialization.get())->getMesh(); @@ -98,20 +98,20 @@ bool NOMAD::DMultiMads::runImp() megaIteration.end(); k = megaIteration.getK(); - + if (!_algoSuccessful && megaIteration.getSuccessType() >= NOMAD::SuccessType::FULL_SUCCESS) { _algoSuccessful = true; } - + if (getUserInterrupt()) { throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMads does not currently support hot restart."); } } -// // _refMegaIteration is used for hot restart (read -// // and write), as well as to keep values used in Mads::end(). Update it here. + // _refMegaIteration is used for hot restart (read + // and write), as well as to keep values used in Mads::end(). Update it here. _refMegaIteration = std::make_shared(this, k, barrier, nullptr, _success); _termination->start(); diff --git a/src/Algos/DMultiMads/DMultiMads.hpp b/src/Algos/DMultiMads/DMultiMads.hpp index 1c297a32..7464eadd 100644 --- a/src/Algos/DMultiMads/DMultiMads.hpp +++ b/src/Algos/DMultiMads/DMultiMads.hpp @@ -44,8 +44,8 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_DMULTIMADS__ -#define __NOMAD_4_4_DMULTIMADS__ +#ifndef __NOMAD_4_5_DMULTIMADS__ +#define __NOMAD_4_5_DMULTIMADS__ #include "../../Algos/Algorithm.hpp" @@ -90,7 +90,7 @@ class DMultiMads: public Algorithm /** - Algorithm execution for single-objective. - Loop on DMultiMadsMegaIteration (start, run, end) until a stop reason to terminate is obtained. - - Update the succes type + - Update the success type - Perform Termination tasks (start, run, end) - Update the SearchMethod success type with best success found. \return \c true @@ -101,4 +101,4 @@ class DMultiMads: public Algorithm #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_DMULTIMADS__ +#endif // __NOMAD_4_5_DMULTIMADS__ diff --git a/src/Algos/DMultiMads/DMultiMadsBarrier.cpp b/src/Algos/DMultiMads/DMultiMadsBarrier.cpp index 54703a60..7aa6d053 100644 --- a/src/Algos/DMultiMads/DMultiMadsBarrier.cpp +++ b/src/Algos/DMultiMads/DMultiMadsBarrier.cpp @@ -54,11 +54,16 @@ // Initialization from cache void NOMAD::DMultiMadsBarrier::init(const NOMAD::Point& fixedVariables, - NOMAD::EvalType evalType, - NOMAD::ComputeType computeType, - bool barrierInitializedFromCache) + bool barrierInitializedFromCache) { std::vector cachePoints; + + + if (_computeType.evalType != NOMAD::EvalType::BB || _computeType.fhComputeTypeS.computeType != NOMAD::ComputeType::STANDARD ) + { + std::string s = "Error: Eval type must be BB and Compute Type must be standard"; + throw NOMAD::Exception(__FILE__,__LINE__,s); + } if (fixedVariables.isEmpty()) { @@ -69,13 +74,23 @@ void NOMAD::DMultiMadsBarrier::init(const NOMAD::Point& fixedVariables, { checkCache(); - - // Get best feasible and infeasible solutions from cache. + // Order lexicographically a set of non dominated points. + auto lexicographicallyObjOrder = [](const NOMAD::FHComputeType& computeType, + std::vector& xSet) + { + std::sort(xSet.begin(), xSet.end(), + [computeType](const EvalPointPtr& evalPoint1, const EvalPointPtr& evalPoint2)->bool + { + return evalPoint1->getFs(computeType).lexicographicalCmp(evalPoint2->getFs(computeType)); + }); + }; + + // Get the best feasible and infeasible solutions from cache. // Point from cache are in full dimension. // Convert them to subproblem dimension. // NB: all solutions (and not only the non dominated ones are considered) auto cache = CacheBase::getInstance().get(); - if (cache->findBestFeas(cachePoints, fixedVariables, evalType, computeType) > 0) + if (cache->findBestFeas(cachePoints, fixedVariables, _computeType) > 0) { for (const auto & evalPoint : cachePoints) { @@ -83,25 +98,27 @@ void NOMAD::DMultiMadsBarrier::init(const NOMAD::Point& fixedVariables, _xFeas.push_back(evalPointSub); } cachePoints.clear(); + lexicographicallyObjOrder(_computeType, _xFeas); } - if (cache->findFilterInf(cachePoints, _hMax, fixedVariables, evalType, computeType) > 0) + if (cache->findFilterInf(cachePoints, _hMax, fixedVariables, _computeType) > 0) { for (const auto &evalPoint : cachePoints) { // Consider points with h < INF. That is, points that are not excluded by extreme barrier constraints. - if (evalPoint.getH(evalType,computeType) < NOMAD::INF) + if (evalPoint.getH(_computeType) < NOMAD::INF) { NOMAD::EvalPointPtr evalPointSub = std::make_shared( evalPoint.makeSubSpacePointFromFixed(fixedVariables)); _xInf.push_back(evalPointSub); } } cachePoints.clear(); + lexicographicallyObjOrder(_computeType, _xInf); } // Get non dominated infeasible points from cache. // Points from cache are in full dimension. // Convert them to subproblem dimension. - if (cache->findFilterInf(cachePoints, _hMax, fixedVariables, evalType, computeType) > 0) + if (cache->findFilterInf(cachePoints, _hMax, fixedVariables, _computeType) > 0) { for (const auto & evalPoint : cachePoints) { @@ -109,10 +126,11 @@ void NOMAD::DMultiMadsBarrier::init(const NOMAD::Point& fixedVariables, _xFilterInf.push_back(evalPointSub); } cachePoints.clear(); + lexicographicallyObjOrder(_computeType, _xFilterInf); } } - if (_xFeas.size() > 0 || _xInf.size() > 0) + if (!_xFeas.empty() || !_xInf.empty()) { setN(); @@ -127,19 +145,15 @@ void NOMAD::DMultiMadsBarrier::init(const NOMAD::Point& fixedVariables, // Update the incumbents used by DMultiMads algo as frameCenter updateCurrentIncumbents(); - } } // And from the list of points given void NOMAD::DMultiMadsBarrier::init(const NOMAD::Point& fixedVariables, - NOMAD::EvalType evalType, - const std::vector& evalPointList, - NOMAD::ComputeType computeType) + const std::vector& evalPointList) { - - bool updated = updateWithPoints(evalPointList, evalType, computeType, true); // All points are considered. + bool updated = updateWithPoints(evalPointList, true); // All points are considered. if (! updated) return; @@ -150,6 +164,13 @@ void NOMAD::DMultiMadsBarrier::init(const NOMAD::Point& fixedVariables, { _bbInputsType = BBInputTypeList(_n, NOMAD::BBInputType::CONTINUOUS); } + + if (_computeType.evalType != NOMAD::EvalType::BB || _computeType.fhComputeTypeS.computeType != NOMAD::ComputeType::STANDARD ) + { + std::string s = "Error: Eval type must be BB and Compute Type must be standard"; + throw NOMAD::Exception(__FILE__,__LINE__,s); + } + if (_bbInputsType.size() != _n) { std::string s = "Error: Inputs dimensions of DMultiMadsBarrier do not match dimensions of provided input types."; @@ -157,21 +178,21 @@ void NOMAD::DMultiMadsBarrier::init(const NOMAD::Point& fixedVariables, } // Check: xFeas or xInf could be non-evaluated, but not both. - if ( (_xFeas.empty() || nullptr == _xFeas[0]->getEval(evalType)) - && (_xInf.empty() || nullptr == _xInf[0]->getEval(evalType))) + if ( (_xFeas.empty() || nullptr == _xFeas[0]->getEval(_computeType.evalType)) + && (_xInf.empty() || nullptr == _xInf[0]->getEval(_computeType.evalType))) { std::string s = "Barrier constructor: xFeas or xInf must be in the barrier.\n"; if (!_xFeas.empty()) { s += "There are " + std::to_string(_xFeas.size()) + " xFeas, the first one is:\n"; - s += _xFeas[0]->displayAll(); + s += _xFeas[0]->displayAll(NOMAD::defaultFHComputeTypeS); } if (!_xInf.empty()) { s += "There are " + std::to_string(_xInf.size()) + " xInf, the first one is:\n"; - s += _xInf[0]->displayAll(); + s += _xInf[0]->displayAll(NOMAD::defaultFHComputeTypeS); } - if (_xFeas.size() == 0 && _xInf.size() == 0) + if (_xFeas.empty() && _xInf.empty()) { s += "There are no xFeas and no xInf defined."; } @@ -179,6 +200,9 @@ void NOMAD::DMultiMadsBarrier::init(const NOMAD::Point& fixedVariables, } checkHMax(); + + // Update the incumbents used by DMultiMads algo as frame centers and bounds. + updateCurrentIncumbents(); } @@ -193,8 +217,10 @@ void NOMAD::DMultiMadsBarrier::setHMax(const NOMAD::Double &hMax) { updateXInfAndFilterInfAfterHMaxSet(); } - // Always update the current incumbent infeasible after changing hmax. + // Always update the current infeasible incumbents after changing hmax. + updateCurrentIncumbentInfMaxH(); updateCurrentIncumbentInf(); + updateCurrentIdealInf(); } @@ -248,47 +274,48 @@ void NOMAD::DMultiMadsBarrier::clearXFeas() { _xFeas.clear(); - // Update the current incumbents. Both the feasible and infeasible ones. + // Update the current incumbents. Both the feasible and infeasible ones. updateCurrentIncumbents(); - + updateCurrentIdealFeas(); } -void NOMAD::DMultiMadsBarrier::checkXFeasIsFeas(const NOMAD::EvalPoint &xFeas, - NOMAD::EvalType evalType, - NOMAD::ComputeType computeType) +void NOMAD::DMultiMadsBarrier::checkXFeasIsFeas(const NOMAD::EvalPoint &xFeas) { + const auto evalType = _computeType.evalType; + // If evalType is UNDEFINED, skip this check. - if (NOMAD::EvalType::UNDEFINED != evalType) + if (evalType == NOMAD::EvalType::UNDEFINED) + return; + + const auto eval = xFeas.getEval(evalType); + if (eval == nullptr || eval->getEvalStatus() != NOMAD::EvalStatusType::EVAL_OK) + return; + + const auto computeTypeS = _computeType.Short(); + const NOMAD::Double h = eval->getH(computeTypeS); + if (!h.isDefined() || 0.0 != h) { - auto eval = xFeas.getEval(evalType); - if (nullptr != eval && NOMAD::EvalStatusType::EVAL_OK == eval->getEvalStatus()) - { - NOMAD::Double h = eval->getH(computeType); - if (!h.isDefined() || 0.0 != h) - { - std::string err = "Error: DMultiMadsBarrier: xFeas' h value must be 0.0, got: " + h.display(); - throw NOMAD::Exception(__FILE__,__LINE__,err); - } - if (computeType == NOMAD::ComputeType::STANDARD && eval->getFs(computeType).size() != _nobj) - { - std::string err = "Error: DMultiMadsBarrier: xFeas' F must be of size " + std::to_string(_nobj); - err += ", got: F.size() = " + std::to_string(eval->getFs(computeType).size()); - err += " with following F values " + eval->getFs(computeType).display(); - throw NOMAD::Exception(__FILE__,__LINE__,err); - } - } + std::string err = "Error: DMultiMadsBarrier: xFeas' h value must be 0.0, got: " + h.display(); + throw NOMAD::Exception(__FILE__,__LINE__,err); + } + + if (computeTypeS.computeType == NOMAD::ComputeType::STANDARD && eval->getFs(computeTypeS).size() != _nobj) + { + std::string err = "Error: DMultiMadsBarrier: xFeas' F must be of size " + std::to_string(_nobj); + err += ", got: F.size() = " + std::to_string(eval->getFs(computeTypeS).size()); + err += " with following F values " + eval->getFs(computeTypeS).display(); + throw NOMAD::Exception(__FILE__,__LINE__,err); } } NOMAD::EvalPointPtr NOMAD::DMultiMadsBarrier::getFirstXIncInfNoXFeas() const { - NOMAD::EvalPointPtr xInf = nullptr; - if (_xFilterInf.size() == 0) + if (_xFilterInf.empty()) { - return xInf; + return nullptr; } // Select candidates @@ -308,9 +335,10 @@ NOMAD::EvalPointPtr NOMAD::DMultiMadsBarrier::getFirstXIncInfNoXFeas() const // The selection must always work if (nbSelectedCandidates == 0) { - xInf = _xInf[0]; + return _xInf[0]; } - else if (nbSelectedCandidates == 1) + + if (nbSelectedCandidates == 1) { auto it = std::find(canBeFrameCenter.begin(), canBeFrameCenter.end(), true); if (it == canBeFrameCenter.end()) @@ -318,156 +346,145 @@ NOMAD::EvalPointPtr NOMAD::DMultiMadsBarrier::getFirstXIncInfNoXFeas() const std::string s = "Error: DMultiMadsBarrier, should not reach this condition"; throw NOMAD::Exception(__FILE__,__LINE__,s); } - else - { - size_t selectedInd = std::distance(canBeFrameCenter.begin(), it); - xInf = _xInf[selectedInd]; - } + const size_t selectedInd = std::distance(canBeFrameCenter.begin(), it); + return _xInf[selectedInd]; } - else if ((nbSelectedCandidates == 2) && (_xInf.size() == 2)) + + if ((nbSelectedCandidates == 2) && (_xInf.size() == 2)) { - const NOMAD::Eval* eval1 = _xInf[0]->getEval(NOMAD::EvalType::BB); - const NOMAD::Eval* eval2 = _xInf[1]->getEval(NOMAD::EvalType::BB); - auto objv1 = eval1->getFs(); - auto objv2 = eval2->getFs(); - if (objv1.abs().max() > objv2.abs().max()) - { - xInf = _xInf[0]; - } - else - { - xInf = _xInf[1]; - } + const auto& objv1 = _xInf[0]->getFs(_computeType); + const auto& objv2 = _xInf[1]->getFs(_computeType); + const EvalPointPtr xInf = (objv1.abs().max() > objv2.abs().max()) ? _xInf[0] : _xInf[1]; + return xInf; } + // More than two points in the barrier. - else + // First case: biobjective optimization. Points are already ranked by lexicographic order. + if (_nobj == 2) { - // First case: biobjective optimization. Points are already ranked by lexicographic order. - if (_nobj == 2) + size_t currentBestInd = 0; + NOMAD::Double maxGap = -1.0; + NOMAD::Double currentGap; + for (size_t obj = 0; obj < _nobj; ++obj) { - size_t currentBestInd = 0; - NOMAD::Double maxGap = -1.0; - NOMAD::Double currentGap; - for (size_t obj = 0; obj < _nobj; ++obj) - { - // Get extreme values value according to one objective - NOMAD::Double fmin = _xInf[0]->getEval(NOMAD::EvalType::BB)->getFs()[obj]; - NOMAD::Double fmax = _xInf[_xInf.size()-1]->getEval(NOMAD::EvalType::BB)->getFs()[obj]; - - // In this case, it means all elements of _xInf are equal (return the first one) - if (fmin == fmax) - { - break; - } + // Get extreme values value according to one objective + const NOMAD::Double fmin = _xInf[0]->getFs(_computeType)[obj]; + const NOMAD::Double fmax = _xInf[_xInf.size()-1]->getFs(_computeType)[obj]; - // Intermediate points - for (size_t i = 1; i < _xInf.size()-1;++i) - { - currentGap = _xInf[i+1]->getEval(NOMAD::EvalType::BB)->getFs()[obj] - - _xInf[i-1]->getEval(NOMAD::EvalType::BB)->getFs()[obj]; - currentGap /= (fmax -fmin); - if (canBeFrameCenter[i] && currentGap >= maxGap) - { - maxGap = currentGap; - currentBestInd = i; - } - } + // In this case, it means all elements of _xInf are equal. + // We return the first one. + if (fmin == fmax) + { + return _xInf[0]; + } - // Extreme points - currentGap = 2 * (_xInf[_xInf.size() - 1]->getEval(NOMAD::EvalType::BB) ->getFs()[obj] - - _xInf[_xInf.size() - 2] ->getEval(NOMAD::EvalType::BB) ->getFs()[obj]); - currentGap /= (fmax - fmin); - if (canBeFrameCenter[_xInf.size() - 1] && currentGap > maxGap) - { - maxGap = currentGap; - currentBestInd = _xInf.size()-1; - } + // Intermediate points + for (size_t i = 1; i < _xInf.size()-1;++i) + { + if (!canBeFrameCenter[i]) + continue; - currentGap = 2 * (_xInf[1]->getEval(NOMAD::EvalType::BB)->getFs()[obj] - - _xInf[0]->getEval(NOMAD::EvalType::BB)->getFs()[obj]); + currentGap = _xInf[i+1]->getFs(_computeType)[obj] - + _xInf[i-1]->getFs(_computeType)[obj]; currentGap /= (fmax -fmin); - if (canBeFrameCenter[0] && currentGap > maxGap) + if (currentGap >= maxGap) { maxGap = currentGap; - currentBestInd = 0; + currentBestInd = i; } } - xInf = _xInf[currentBestInd]; - } - // More than 2 objectives - else - { - std::vector > tmpXInfPInd(_xInf.size()); - // Initialize it. - for (size_t i = 0; i < tmpXInfPInd.size(); ++i) + // Extreme points + currentGap = 2 * (_xInf[_xInf.size() - 1]->getFs(_computeType)[obj] - + _xInf[_xInf.size() - 2]->getFs(_computeType)[obj]); + currentGap /= (fmax - fmin); + if (canBeFrameCenter[_xInf.size() - 1] && currentGap > maxGap) { - tmpXInfPInd[i] = std::make_pair(*_xInf[i], i); + maxGap = currentGap; + currentBestInd = _xInf.size() - 1; } - size_t currentBestInd = 0; - NOMAD::Double maxGap = -1.0; - NOMAD::Double currentGap; - - for (size_t obj = 0; obj < _nobj; ++obj) + currentGap = 2 * (_xInf[1]->getFs(_computeType)[obj] - + _xInf[0]->getFs(_computeType)[obj]); + currentGap /= (fmax -fmin); + if (canBeFrameCenter[0] && currentGap > maxGap) { - // Sort elements of tmpXInfPInd according to objective obj (in ascending order) - std::sort(tmpXInfPInd.begin(), tmpXInfPInd.end(), - [obj](const std::pair& t1, const std::pair t2)->bool - { - const NOMAD::Eval* eval1 = t1.first.getEval(NOMAD::EvalType::BB); - const NOMAD::Eval* eval2 = t2.first.getEval(NOMAD::EvalType::BB); - return eval1->getFs()[obj] < eval2->getFs()[obj]; - }); - - // Get extreme values value according to one objective - NOMAD::Double fmin = tmpXInfPInd[0].first.getEval(NOMAD::EvalType::BB)->getFs()[obj]; - NOMAD::Double fmax = tmpXInfPInd[tmpXInfPInd.size()-1].first.getEval(NOMAD::EvalType::BB)->getFs()[obj]; - - // Can happen for exemple when we have several minima or for more than three objectives - if (fmin == fmax) - { - fmin = 0.0; - fmax = 1.0; - } + maxGap = currentGap; + currentBestInd = 0; + } + } + return _xInf[currentBestInd]; + } - // Intermediate points - for (size_t i = 1; i < tmpXInfPInd.size()-1;++i) - { - currentGap = tmpXInfPInd[i+1].first.getEval(NOMAD::EvalType::BB)->getFs()[obj] - - tmpXInfPInd[i-1].first.getEval(NOMAD::EvalType::BB)->getFs()[obj]; - currentGap /= (fmax -fmin); - if (canBeFrameCenter[tmpXInfPInd[i].second] && currentGap >= maxGap) - { - maxGap = currentGap; - currentBestInd = tmpXInfPInd[i].second; - } - } + // Case 2 : more than 2 objectives + std::vector > tmpXInfPInd(_xInf.size()); - // Extreme points - currentGap = 2 * (tmpXInfPInd[tmpXInfPInd.size() - 1].first.getEval(NOMAD::EvalType::BB) ->getFs()[obj] - - tmpXInfPInd[tmpXInfPInd.size() - 2].first.getEval(NOMAD::EvalType::BB) ->getFs()[obj]); - currentGap /= (fmax - fmin); - if (canBeFrameCenter[tmpXInfPInd[tmpXInfPInd.size()-1].second] && currentGap > maxGap) - { - maxGap = currentGap; - currentBestInd = tmpXInfPInd[tmpXInfPInd.size()-1].second; - } + // Initialize it. + for (size_t i = 0; i < tmpXInfPInd.size(); ++i) + { + tmpXInfPInd[i] = std::make_pair(_xInf[i], i); + } - currentGap = 2 * (tmpXInfPInd[1].first.getEval(NOMAD::EvalType::BB) ->getFs()[obj] - - tmpXInfPInd[0].first.getEval(NOMAD::EvalType::BB) ->getFs()[obj]); - currentGap /= (fmax -fmin); - if (canBeFrameCenter[tmpXInfPInd[0].second] && currentGap > maxGap) - { - maxGap = currentGap; - currentBestInd = tmpXInfPInd[0].second; - } + size_t currentBestInd = 0; + NOMAD::Double maxGap = -1.0; + NOMAD::Double currentGap; + + for (size_t obj = 0; obj < _nobj; ++obj) + { + // Sort elements of tmpXInfPInd according to objective obj (in ascending order) + std::sort(tmpXInfPInd.begin(), tmpXInfPInd.end(), + [obj, this](const std::pair& t1, const std::pair& t2)->bool + { + return t1.first->getFs(_computeType)[obj] < t2.first->getFs(_computeType)[obj]; + }); + + // Get extreme values value according to one objective + NOMAD::Double fmin = tmpXInfPInd[0].first->getFs(_computeType)[obj]; + NOMAD::Double fmax = tmpXInfPInd[tmpXInfPInd.size()-1].first->getFs(_computeType)[obj]; + + // Can happen for example when we have several minima or for more than three objectives + if (fmin == fmax) + { + fmin = 0.0; + fmax = 1.0; + } + + // Intermediate points + for (size_t i = 1; i < tmpXInfPInd.size()-1;++i) + { + if (!canBeFrameCenter[tmpXInfPInd[i].second]) + continue; + + currentGap = tmpXInfPInd[i+1].first->getFs(_computeType)[obj] - + tmpXInfPInd[i-1].first->getFs(_computeType)[obj]; + currentGap /= (fmax -fmin); + if (currentGap >= maxGap) + { + maxGap = currentGap; + currentBestInd = tmpXInfPInd[i].second; } - xInf = _xInf[currentBestInd]; } + // Extreme points + currentGap = 2 * (tmpXInfPInd[tmpXInfPInd.size() - 1].first->getFs(_computeType)[obj] - + tmpXInfPInd[tmpXInfPInd.size() - 2].first->getFs(_computeType)[obj]); + currentGap /= (fmax - fmin); + if (canBeFrameCenter[tmpXInfPInd[tmpXInfPInd.size()-1].second] && currentGap > maxGap) + { + maxGap = currentGap; + currentBestInd = tmpXInfPInd[tmpXInfPInd.size()-1].second; + } + + currentGap = 2 * (tmpXInfPInd[1].first->getFs(_computeType)[obj] - + tmpXInfPInd[0].first->getFs(_computeType)[obj]); + currentGap /= (fmax -fmin); + if (canBeFrameCenter[tmpXInfPInd[0].second] && currentGap > maxGap) + { + maxGap = currentGap; + currentBestInd = tmpXInfPInd[0].second; + } } - return xInf; + return _xInf[currentBestInd]; } @@ -478,8 +495,7 @@ NOMAD::EvalPointPtr NOMAD::DMultiMadsBarrier::getXInfMinH() const for (size_t i = 0; i < _xInf.size(); ++i) { - const NOMAD::Eval* eval = _xInf[i]->getEval(NOMAD::EvalType::BB); - NOMAD::Double h = eval->getH(); + const NOMAD::Double h = _xInf[i]->getH(_computeType); // By definition, all elements of _xInf or _xFilterInf have a well-defined // h value. So, no need to check. @@ -499,9 +515,10 @@ void NOMAD::DMultiMadsBarrier::clearXInf() _xInf.clear(); _xFilterInf.clear(); - // Update the current incumbent inf. Only the infeasible one depends on XInf (not the case for the feasible one). + // Update the current infeasible incumbents. + updateCurrentIncumbentInfMaxH(); updateCurrentIncumbentInf(); - + updateCurrentIdealInf(); } @@ -513,9 +530,7 @@ void NOMAD::DMultiMadsBarrier::updateRefBests() // The code is the very similar to what is in Barrier. Here we use current incumbents. NOMAD::SuccessType NOMAD::DMultiMadsBarrier::getSuccessTypeOfPoints(const EvalPointPtr xFeas, - const EvalPointPtr xInf, - EvalType evalType, - ComputeType computeType) + const EvalPointPtr xInf) { NOMAD::SuccessType successType = SuccessType::UNSUCCESSFUL; NOMAD::SuccessType successType2 = SuccessType::UNSUCCESSFUL; @@ -529,7 +544,7 @@ NOMAD::SuccessType NOMAD::DMultiMadsBarrier::getSuccessTypeOfPoints(const EvalPo // Compute success // Get which of newBestFeas and newBestInf is improving // the solution. Check newBestFeas first. - NOMAD::ComputeSuccessType computeSuccess(evalType, computeType); + NOMAD::ComputeSuccessType computeSuccess(_computeType); if (nullptr != _currentIncumbentFeas) { @@ -548,346 +563,372 @@ NOMAD::SuccessType NOMAD::DMultiMadsBarrier::getSuccessTypeOfPoints(const EvalPo } -bool NOMAD::DMultiMadsBarrier::updateFeasWithPoint(const EvalPoint & evalPoint, - EvalType evalType, - ComputeType computeType, - const bool keepAllPoints) +NOMAD::CompareType NOMAD::DMultiMadsBarrier::updateFeasWithPoint(const EvalPoint & evalPoint, + const bool keepAllPoints) { + // Dealing with Non Standard computing order + const auto computeTypeS = _computeType.Short(); + if (computeTypeS.computeType != ComputeType::STANDARD) + { + throw NOMAD::Exception(__FILE__, __LINE__, "Update using non standard compute type is not yet implemented"); + } + + const auto eval = evalPoint.getEval(_computeType.evalType); + if (!eval->isFeasible(computeTypeS)) + return NOMAD::CompareType::UNDEFINED; - bool updated = false; + std::string s; // for output info + + OUTPUT_DEBUG_START + s = "Point suggested to update DMultiMadsBarrier (feasible): " + evalPoint.display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + + if (eval->getFs(computeTypeS).size() != _nobj) + { + s = "DMultiMadsBarrier update: number of objectives is equal to " + std::to_string(_nobj); + s += ". Trying to add this point with number of objectives " + std::to_string(eval->getFs(computeTypeS).size()); + s += ": " + evalPoint.display(); + throw NOMAD::Exception(__FILE__, __LINE__, s); + } - auto eval = evalPoint.getEval(evalType); - if (eval->isFeasible(computeType)) + if (_xFeas.empty()) { - std::string s; // for output info - + _xFeas.push_back(std::make_shared(evalPoint)); OUTPUT_DEBUG_START - s = "Point suggested to update DMultiMadsBarrier (feasible): " + evalPoint.display(); + s = "New dominating xFeas: " + evalPoint.display(); NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); OUTPUT_DEBUG_END - - if (eval->getFs(computeType).size() != _nobj) - { - s = "DMultiMadsBarrier update: number of objectives is equal to " + std::to_string(_nobj); - s += ". Trying to add this point with number of objectives " + std::to_string(eval->getFs(computeType).size()); - s += ": " + evalPoint.display(); - throw NOMAD::Exception(__FILE__, __LINE__, s); - } - - // Ensure evalPoint is as good as previous points in xFeas - if (_xFeas.empty()) + return NOMAD::CompareType::DOMINATING; + } + + // Ensure evalPoint is as good as previous points in xFeas + std::vector keepInXFeas(_xFeas.size(), true); + int currentInd = 0; + auto compFlag = NOMAD::CompareType::INDIFFERENT; + for (const auto& xFeas: _xFeas) + { + const auto currentCompFlag = evalPoint.compMO(*xFeas, _computeType); + if (currentCompFlag == CompareType::DOMINATED) { - // New point is first point - _xFeas.push_back(std::make_shared(evalPoint)); - updated = true; OUTPUT_DEBUG_START - s = "New dominating xFeas: " + evalPoint.display(); + s = "evalPoint is dominated by " + xFeas->display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + s = "evalPoint is rejected"; NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); OUTPUT_DEBUG_END - - // Update new best feasible point. - _currentIncumbentFeas = _xFeas[0]; + return currentCompFlag; } - else + if (currentCompFlag == CompareType::EQUAL) { - // Dealing with Non Standard computing order - if (computeType != ComputeType::STANDARD) + if (!keepAllPoints) + return currentCompFlag; + + // If new point is not already there, add it + // One should never add two times the same point into the barrier. + if (findEvalPoint(_xFeas.begin(), _xFeas.end(), evalPoint) != _xFeas.end()) { - throw NOMAD::Exception(__FILE__, __LINE__, "Update using non standard compute type is not yet implemented"); + OUTPUT_DEBUG_START + s = "EvalPoint " + evalPoint.display() + "is already in xFeas"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + return NOMAD::CompareType::UNDEFINED; } - else - { - bool insert = true; - std::vector keepInXFeas(_xFeas.size(), true); - int currentInd = 0; - for (const auto& xFeas : _xFeas) - { - auto compFlag = evalPoint.compMO(*xFeas, evalType); - if (compFlag == CompareType::DOMINATED) - { - OUTPUT_DEBUG_START - s = "evalPoint is dominated by " + xFeas->display() + "\n"; - s += "evalPoint is rejected"; - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - OUTPUT_DEBUG_END - insert = false; - break; - } - else if (compFlag == CompareType::DOMINATING) - { - OUTPUT_DEBUG_START - s = "At least a point in xFeas is dominated by " + evalPoint.display(); - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - OUTPUT_DEBUG_END - updated = true; - keepInXFeas[currentInd] = false; - } - else if (compFlag == CompareType::EQUAL) - { - if (!keepAllPoints) - { - insert = false; - break; - } - - // If new point is not already there, add it - if (findEvalPoint(_xFeas.begin(), _xFeas.end(), evalPoint) != _xFeas.end()) - { - OUTPUT_DEBUG_START - s = "EvalPoint " + evalPoint.display() + "is already in xFeas"; - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - OUTPUT_DEBUG_END - insert = false; - } - else - { - updated = true; - } - break; - } - currentInd++; - } - if (insert) - { - // Remove all dominated elements. - currentInd = 0; - _xFeas.erase(std::remove_if(_xFeas.begin(), _xFeas.end(), - [¤tInd, &keepInXFeas](const EvalPointPtr evalPoint) - { - bool isRemoved = !keepInXFeas[currentInd]; - ++currentInd; - return isRemoved; - }), _xFeas.end()); - - // Update mesh and insert the new element. - OUTPUT_DEBUG_START - s = "Adding new non dominated eval point in xFeas: " + evalPoint.display(); - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - s = "Update the mesh of eval point to be added"; - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - OUTPUT_DEBUG_END - updated = true; - - // Update the mesh -> success - auto dir = evalPoint.getDirection(); - if (nullptr != dir) - { - evalPoint.getMesh()->enlargeDeltaFrameSize(*dir); - } - - // insert new element - _xFeas.push_back(std::make_shared(evalPoint)); + compFlag = NOMAD::CompareType::EQUAL; + } + if (currentCompFlag == CompareType::DOMINATING) + { + OUTPUT_DEBUG_START + s = "EvalPoint " + xFeas->display() + "in xFeas is dominated by " + evalPoint.display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + keepInXFeas[currentInd] = false; + compFlag = NOMAD::CompareType::DOMINATING; + } + currentInd++; + } + + // Remove all dominated elements. + currentInd = 0; + const size_t prevNbFeasElements = _xFeas.size(); + _xFeas.erase(std::remove_if(_xFeas.begin(), _xFeas.end(), + [¤tInd, &keepInXFeas](const EvalPointPtr& evalPoint) + { + const bool isRemoved = !keepInXFeas[currentInd]; + ++currentInd; + return isRemoved; + }), _xFeas.end()); + OUTPUT_DEBUG_START + s = "Removing " + std::to_string(std::max((int) prevNbFeasElements - (int)_xFeas.size(), 0)); + s += " dominating feasible eval points"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END - // Sort according to lexicographic order. - std::sort(_xFeas.begin(), _xFeas.end(), - [&evalType](const EvalPointPtr evalPoint1, const EvalPointPtr evalPoint2) - { - const NOMAD::Eval* eval1 = evalPoint1->getEval(evalType); - const NOMAD::Eval* eval2 = evalPoint2->getEval(evalType); - return eval1->getFs().lexicographicalCmp(eval2->getFs()); - }); - } + // Update mesh and insert the new element. + OUTPUT_DEBUG_START + s = "Adding new non dominated eval point in xFeas: " + evalPoint.display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + + const bool updateMesh = [&]() -> bool + { + if (compFlag == NOMAD::CompareType::DOMINATING) + return true; + + // Check if evalPoint extends the current Pareto front approximation. + bool extends = false; + for (size_t obj = 0; obj < _nobj; ++obj) + { + if (_currentIdealFeas[obj] > evalPoint.getFs(_computeType)[obj]) + { + extends = true; + _currentIdealFeas[obj] = evalPoint.getFs(_computeType)[obj]; } } + return extends; + }(); // IIFE + + // Update the mesh -> success + if (updateMesh) + { + const auto dir = evalPoint.getDirection(); + if (nullptr != dir) + { + OUTPUT_DEBUG_START + s = "Update the mesh of eval point to be added"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + + evalPoint.getMesh()->enlargeDeltaFrameSize(*dir); + } } - return updated; + + // Insert new element + _xFeas.push_back(std::make_shared(evalPoint)); + + return compFlag; } -bool NOMAD::DMultiMadsBarrier::updateInfWithPoint(const EvalPoint & evalPoint, - EvalType evalType, - ComputeType computeType, - const bool keepAllPoints, - const bool feasHasBeenUpdated) +NOMAD::CompareType NOMAD::DMultiMadsBarrier::updateInfWithPoint(const EvalPoint & evalPoint, + const bool keepAllPoints) { + const auto eval = evalPoint.getEval(_computeType.evalType); + const auto computeTypeS = _computeType.Short(); + if (eval->isFeasible(computeTypeS)) + return NOMAD::CompareType::UNDEFINED; + + std::string s; // for output info - bool updated = false; - - auto eval = evalPoint.getEval(evalType); - if (!eval->isFeasible(computeType)) + const NOMAD::Double h = eval->getH(computeTypeS); + if (!h.isDefined()) { - std::string s; // for output info - - - NOMAD::Double h = eval->getH(computeType); - if (!h.isDefined() || h == NOMAD::INF || - ((_hMax < NOMAD::INF) && (h > _hMax))) + OUTPUT_DEBUG_START + s = "H is undefined"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + return NOMAD::CompareType::UNDEFINED; + } + if (h == NOMAD::INF || ((_hMax < NOMAD::INF) && (h > _hMax))) + { + OUTPUT_DEBUG_START + s = "H is too large: "; + s += h.display(NOMAD::DISPLAY_PRECISION_FULL) + " > " + _hMax.display(NOMAD::DISPLAY_PRECISION_FULL) + ", continue."; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + return NOMAD::CompareType::UNDEFINED; + } + + if (_xInf.empty()) + { + // New point is first point + _xInf.push_back(std::make_shared(evalPoint)); + _xFilterInf.push_back(std::make_shared(evalPoint)); + OUTPUT_DEBUG_START + s = "New current incumbent infeasible: " + evalPoint.display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + return NOMAD::CompareType::DOMINATING; + } + + // Insertion into the two sets of infeasible non dominated points. + // 1- Try to insert into _xInfFilter. + std::vector isInXinfFilter(_xFilterInf.size(), true); + int currentInd = 0; + for (const auto& xFilterInf: _xFilterInf) + { + const auto currentCompFlag = evalPoint.compMO(*xFilterInf, _computeType); + if (currentCompFlag == CompareType::DOMINATED) { OUTPUT_DEBUG_START - if (h.isDefined()) - { - s = "H is too large: "; - s += h.display(NOMAD::DISPLAY_PRECISION_FULL) + " > " + _hMax.display(NOMAD::DISPLAY_PRECISION_FULL) + ", continue."; - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - } - else - { - s = "H is undefined"; - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - } + s = "evalPoint is dominated by " + xFilterInf->display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + s = "evalPoint is rejected"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); OUTPUT_DEBUG_END - return false; + return currentCompFlag; } - - if (_xInf.empty()) + if (currentCompFlag == CompareType::DOMINATING) { - // New point is first point - _xInf.push_back(std::make_shared(evalPoint)); - _xFilterInf.push_back(std::make_shared(evalPoint)); - _currentIncumbentInf = _xInf[0]; - updated = true; OUTPUT_DEBUG_START - s = "New current incumbent infeasible: " + evalPoint.display(); + s = "xInf dominates the filter element " + xFilterInf->display(); NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); OUTPUT_DEBUG_END + isInXinfFilter[currentInd] = false; } - // Insertion into the two sets of infeasible non dominated points. - else + if (currentCompFlag == CompareType::EQUAL) { - // Try to insert into _xInfFilter. - bool insert = true; - std::vector isInXinfFilter(_xFilterInf.size(), true); - int currentInd = 0; - - for (const auto& xFilterInf : _xFilterInf) + if (!keepAllPoints) + return NOMAD::CompareType::EQUAL; + + // If new point is not already there, add it. + // One should never insert several times the same point into the barrier. + if (findEvalPoint(_xFilterInf.begin(), _xFilterInf.end(), evalPoint) != _xFilterInf.end()) { - auto compFlag = evalPoint.compMO(*xFilterInf, evalType); - if (compFlag == CompareType::DOMINATED) - { - insert = false; - break; - } - else if (compFlag == CompareType::DOMINATING) - { - OUTPUT_DEBUG_START - s = "xInf dominates the filter element " + xFilterInf->display(); - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - OUTPUT_DEBUG_END - updated = true; - isInXinfFilter[currentInd] = false; - } - else if (compFlag == CompareType::EQUAL) - { - if (!keepAllPoints) - { - insert = false; - break; - } - - // If new point is not already there, add it. - if (findEvalPoint(_xFilterInf.begin(), _xFilterInf.end(), evalPoint) != _xFilterInf.end()) - { - OUTPUT_DEBUG_START - s = "xInf is already here: " + evalPoint.display(); - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - OUTPUT_DEBUG_END - insert = false; - } - else - { - updated = true; - break; - } - } - currentInd++; + OUTPUT_DEBUG_START + s = "xInf is already here: " + evalPoint.display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + return NOMAD::CompareType::UNDEFINED; } + } + currentInd++; + } - if (insert) + // Remove all dominated elements of _xFilterInf + currentInd = 0; + const size_t prevNbFilterInfElements = _xFilterInf.size(); + _xFilterInf.erase(std::remove_if(_xFilterInf.begin(), _xFilterInf.end(), + [¤tInd, &isInXinfFilter](const EvalPointPtr& ev) + { + bool isRemoved = !isInXinfFilter[currentInd]; + currentInd++; + return isRemoved; + }), _xFilterInf.end()); + OUTPUT_DEBUG_START + s = "Removing " + std::to_string(std::max((int) prevNbFilterInfElements - (int)_xFilterInf.size(), 0)); + s += " dominating filter infeasible eval points"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + + OUTPUT_DEBUG_START + s = "Adding new non dominated eval point in xFilterInf: " + evalPoint.display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + auto evalPointPtr = std::make_shared(evalPoint); + _xFilterInf.push_back(evalPointPtr); + + // 2- Try to insert the point into _xInf. + currentInd = 0; + std::vector isInXinf(_xInf.size(), true); + auto compFlag = NOMAD::CompareType::INDIFFERENT; + for (const auto& xInf: _xInf) + { + const auto currentCompFlag = evalPoint.compMO(*xInf, _computeType, true); + if (currentCompFlag == CompareType::DOMINATED) + { + + OUTPUT_DEBUG_START + s = "evalPoint is dominated by " + xInf->display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + s = "evalPoint is rejected"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + return currentCompFlag; + } + // The points could be only equal according to the f values + if ((currentCompFlag == CompareType::DOMINATING) || + (evalPoint.compMO(*xInf, _computeType) == CompareType::DOMINATING)) + { + OUTPUT_DEBUG_START + s = "xInf dominates the filter element " + xInf->display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + isInXinf[currentInd] = false; + compFlag = NOMAD::CompareType::DOMINATING; + } + currentInd++; + } + + // Remove all dominated elements of _xInf. + currentInd = 0; + const size_t prevNbInfElements = _xInf.size(); + _xInf.erase(std::remove_if(_xInf.begin(), _xInf.end(), + [¤tInd, &isInXinf](const EvalPointPtr& ev) + { + bool isRemoved = !isInXinf[currentInd]; + currentInd++; + return isRemoved; + }), _xInf.end()); + OUTPUT_DEBUG_START + s = "Removing " + std::to_string(std::max((int) prevNbInfElements - (int)_xInf.size(), 0)); + s += " non dominated infeasible eval points"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + + OUTPUT_DEBUG_START + s = "Adding new non dominated eval point in xInf: " + evalPoint.display(); + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + + // Update mesh and insert evalPoint into the set of infeasible solutions. + const bool updateMesh = [&]() -> bool + { + if (compFlag == NOMAD::CompareType::DOMINATING) + return true; + + // Check if evalPoint extends the current Pareto front approximation. + bool extends = false; + for (size_t obj = 0; obj < _nobj; ++obj) + { + if (_currentIdealInf[obj] > evalPoint.getFs(_computeType)[obj]) { - // Remove all dominated elements of _xInfFilter - currentInd = 0; - _xFilterInf.erase(std::remove_if(_xFilterInf.begin(), _xFilterInf.end(), - [¤tInd, &isInXinfFilter](const EvalPointPtr ev) - { - bool isRemoved = !isInXinfFilter[currentInd]; - currentInd++; - return isRemoved; - }), _xFilterInf.end()); - _xFilterInf.push_back(std::make_shared(evalPoint)); - - // Order by lexicographic ordering. - std::sort(_xFilterInf.begin(), _xFilterInf.end(), - [&evalType](const EvalPointPtr evalPoint1, const EvalPointPtr evalPoint2)->bool - { - const NOMAD::Eval* eval1 = evalPoint1->getEval(evalType); - const NOMAD::Eval* eval2 = evalPoint2->getEval(evalType); - return eval1->getFs().lexicographicalCmp(eval2->getFs()); - }); - - // Try to insert the point into _xInf. - insert = true; - - currentInd = 0; - std::vector isInXinf(_xInf.size(), true); - - for (const auto& xInf : _xInf) - { - auto compFlag = evalPoint.compMO(*xInf, evalType, true); - if (compFlag == CompareType::DOMINATED) - { - insert = false; - break; - } - // The points could be only equal according to the f values - else if ((compFlag == CompareType::DOMINATING) || - (evalPoint.compMO(*xInf, evalType) == CompareType::DOMINATING)) - { - OUTPUT_DEBUG_START - s = "xInf dominates the filter element " + xInf->display(); - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - OUTPUT_DEBUG_END - updated = true; - isInXinf[currentInd] = false; - } - currentInd++; - } - - if (insert) - { - // Remove all dominated elements of _xInf. - currentInd = 0; - _xInf.erase(std::remove_if(_xInf.begin(), _xInf.end(), - [¤tInd, &isInXinf](const EvalPointPtr ev) - { - bool isRemoved = !isInXinf[currentInd]; - currentInd++; - return isRemoved; - }), _xInf.end()); - updated = true; - _xInf.push_back(std::make_shared(evalPoint)); - - - std::sort(_xInf.begin(), _xInf.end(), - [&evalType](const EvalPointPtr evalPoint1, const EvalPointPtr evalPoint2)->bool - { - const NOMAD::Eval* eval1 = evalPoint1->getEval(evalType); - const NOMAD::Eval* eval2 = evalPoint2->getEval(evalType); - return eval1->getFs().lexicographicalCmp(eval2->getFs()); - }); - - } + extends = true; + _currentIdealInf[obj] = evalPoint.getFs(_computeType)[obj]; } } + return extends; + }(); // IIFE + + // Update the mesh -> success + if (updateMesh) + { + const auto dir = evalPoint.getDirection(); + if (nullptr != dir) + { + OUTPUT_DEBUG_START + s = "Update the mesh of eval point to be added"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + + evalPointPtr->getMesh()->enlargeDeltaFrameSize(*dir); + } } - return updated; - + + // Insert new element. + // NB: It is important that evalPoint be the same into xFilterInf and + // xInf; most specifically, it should have the same mesh in both sets. + _xInf.push_back(evalPointPtr); + + return compFlag; } // Update the barrier (feas and inf). Once done calls for update the current best feas and inf. bool NOMAD::DMultiMadsBarrier::updateWithPoints( const std::vector& evalPointList, - EvalType evalType, - ComputeType computeType, const bool keepAllPoints, - const bool updateInfeasibleIncumbentAndHmax) + const bool updateInfeasibleIncumbentsAndHmax) { - bool updated = false; bool updatedFeas = false; bool updatedInf = false; - std::string s; // for output info + bool updatedIncFeas = false; + bool updatedIncInf = false; + bool rejectInf = false; - // Temporary infeasible incumbent. For insertion of more than one improving/full success - NOMAD::EvalPoint xInfTmp; + const auto evalType = _computeType.evalType; + const auto computeTypeS = _computeType.Short(); + + std::string s; // for output info OUTPUT_DEBUG_START s = "Updating DMultiMadsBarrier (" + std::to_string(_nobj) + " objectives)"; @@ -895,23 +936,35 @@ bool NOMAD::DMultiMadsBarrier::updateWithPoints( NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); s = "Current barrier: "; NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - std::vector vs = display(4); - for (const auto & s: vs) + std::vector vs = display(4, false); + for (const auto& elt: vs) { - NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + NOMAD::OutputQueue::Add(elt, NOMAD::OutputLevel::LEVEL_DEBUG); } OUTPUT_DEBUG_END + // Order lexicographically a set of non dominated points. + auto lexicographicallyObjOrder = [](const NOMAD::FHComputeType& computeType, + std::vector& xSet) + { + std::sort(xSet.begin(), xSet.end(), + [computeType](const EvalPointPtr& evalPoint1, const EvalPointPtr& evalPoint2)->bool + { + return evalPoint1->getFs(computeType).lexicographicalCmp(evalPoint2->getFs(computeType)); + }); + }; + // do separate loop on evalPointList // First loop update the bestFeasible. - // If a point is a full success setupdatedFeas = true. - // This flag is used in the second loop. + // The flag below is set to update the barrier threshold in a second pass. + NOMAD::SuccessType feasSuccessType = NOMAD::SuccessType::UNSUCCESSFUL; + size_t nbFeasiblePts = 0; for (const auto & evalPoint : evalPointList) { // All points must have mesh parameters defined. checkMeshParameters(evalPoint); - auto eval = evalPoint.getEval(evalType); + const auto eval = evalPoint.getEval(evalType); if (nullptr == eval || NOMAD::EvalStatusType::EVAL_OK != eval->getEvalStatus()) { OUTPUT_DEBUG_START @@ -932,51 +985,203 @@ bool NOMAD::DMultiMadsBarrier::updateWithPoints( continue; } - if (computeType == ComputeType::STANDARD && eval->getFs(computeType).size() != _nobj) + if (computeTypeS.computeType == ComputeType::STANDARD && eval->getFs(computeTypeS).size() != _nobj) { s = "DMultiMadsBarrier update: number of objectives is equal to " + std::to_string(_nobj); - s += ". Trying to add this point with number of objectives " + std::to_string(eval->getFs(computeType).size()); + s += ". Trying to add this point with number of objectives " + std::to_string(eval->getFs(computeTypeS).size()); s += ": " + evalPoint.display(); throw NOMAD::Exception(__FILE__, __LINE__, s); } - - updatedFeas = updateFeasWithPoint(evalPoint,evalType, computeType, keepAllPoints) || updatedFeas ; + if (!eval->isFeasible(computeTypeS)) + continue; + + nbFeasiblePts += 1; + + // Add feasible point into the barrier. + const auto FkCompFlag = updateFeasWithPoint(evalPoint, keepAllPoints); + const bool insertEqual = (FkCompFlag == NOMAD::CompareType::EQUAL) && !keepAllPoints; + updatedFeas = ((FkCompFlag != NOMAD::CompareType::UNDEFINED) && !insertEqual) || updatedFeas; + + updatedIncFeas = (FkCompFlag == NOMAD::CompareType::INDIFFERENT) || + (FkCompFlag == NOMAD::CompareType::DOMINATING) || + ((FkCompFlag == NOMAD::CompareType::EQUAL) && keepAllPoints) || + updatedIncFeas; + + // Set the success type according to the current infeasible incumbent. + if (feasSuccessType == NOMAD::SuccessType::FULL_SUCCESS) + continue; + + // If the set of feasible incumbents is empty, we follow the same approach as for the + // progressive barrier. The iteration is then considered as a success. + if (_currentIncumbentFeas == nullptr) + { + feasSuccessType = NOMAD::SuccessType::FULL_SUCCESS; + continue; + } + + const auto compFlag = evalPoint.compMO(*_currentIncumbentFeas, _computeType); + if (compFlag == NOMAD::CompareType::DOMINATING) + feasSuccessType = NOMAD::SuccessType::FULL_SUCCESS; } + // Lexicographically order the set of feasible non-dominated solutions. + if (updatedIncFeas) + lexicographicallyObjOrder(_computeType, _xFeas); + // Do separate loop on evalPointList // Second loop update the bestInfeasible. - // Use the flag oneFeasEvalFullSuccess. - // If the flag is true hmax will not change. A point improving the best infeasible should not replace it. - + // The flag below is set to update the barrier threshold in a second pass. + NOMAD::SuccessType infSuccessType = NOMAD::SuccessType::UNSUCCESSFUL; + const bool areAllFeasible = nbFeasiblePts == evalPointList.size(); for (const auto & evalPoint : evalPointList) { - auto eval = evalPoint.getEval(evalType); + // No need to continue. + if (areAllFeasible) + break; + const auto eval = evalPoint.getEval(evalType); if (nullptr == eval || NOMAD::EvalStatusType::EVAL_OK != eval->getEvalStatus()) { // Suggested point is not good. continue; } - - updatedInf = updateInfWithPoint(evalPoint, evalType, computeType, keepAllPoints, updatedFeas) || updatedInf ; + if (eval->isFeasible(computeTypeS)) + continue; + + const NOMAD::Double h = eval->getH(computeTypeS); + if (!h.isDefined() || (h == NOMAD::INF) || + ((_hMax < NOMAD::INF) && (h > _hMax))) + { + OUTPUT_DEBUG_START + s = !h.isDefined() ? "H is undefined" : "H is too large: "; + if (h.isDefined()) + { + s += h.display(NOMAD::DISPLAY_PRECISION_FULL) + " > " + _hMax.display(NOMAD::DISPLAY_PRECISION_FULL) + ", continue."; + } + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + rejectInf = true; + continue; + } + + // Add infeasible point into the barrier. + const auto IkCompFlag = updateInfWithPoint(evalPoint, keepAllPoints); + const bool insertEqual = (IkCompFlag == NOMAD::CompareType::EQUAL) && !keepAllPoints; + updatedInf = ((IkCompFlag != NOMAD::CompareType::UNDEFINED) && !insertEqual) || updatedInf; + + updatedIncInf = (IkCompFlag == NOMAD::CompareType::INDIFFERENT) || + (IkCompFlag == NOMAD::CompareType::DOMINATING) || + ((IkCompFlag == NOMAD::CompareType::EQUAL) && keepAllPoints) || + updatedIncInf; + + // Set the success type according to the current infeasible incumbent. + if (feasSuccessType == NOMAD::SuccessType::FULL_SUCCESS || + infSuccessType == NOMAD::SuccessType::FULL_SUCCESS) + continue; + + // If the set of infeasible incumbents is empty, we follow the same approach as for the + // progressive barrier. The iteration is then considered as a success. + if (_currentIncumbentInf == nullptr) + { + infSuccessType = NOMAD::SuccessType::FULL_SUCCESS; + continue; + } + + const auto compFlag = evalPoint.compMO(*_currentIncumbentInf, _computeType); + if (compFlag == NOMAD::CompareType::DOMINATING) + { + infSuccessType = NOMAD::SuccessType::FULL_SUCCESS; + continue; + } + + const NOMAD::Double hXInf = _currentIncumbentInf->getH(_computeType); + if (h.isDefined() && h < hXInf) + infSuccessType = NOMAD::SuccessType::PARTIAL_SUCCESS; } - updated = updated || updatedFeas || updatedInf; - - if (updated) + // Lexicographically order the set of filter points and infeasible points. + if (updatedInf) + { + lexicographicallyObjOrder(_computeType, _xFilterInf); + lexicographicallyObjOrder(_computeType, _xInf); + } + + const bool incumbentsAndHMaxUpToDate = ! (updatedFeas || updatedInf); + + // Update hMax: when some infeasible points are rejected, the iteration is considered + // as a failure. We still update hMax. + NOMAD::Double hMaxPrev = _hMax; + NOMAD::Double hMax = _hMax; + if (updateInfeasibleIncumbentsAndHmax && (!incumbentsAndHMaxUpToDate || rejectInf)) + { + if (infSuccessType == NOMAD::SuccessType::PARTIAL_SUCCESS && + feasSuccessType < NOMAD::SuccessType::FULL_SUCCESS) + { + // hMax <- max_{x \in Uk+1} {h(x) : h(x) < h(xinf)} + // Note : An improving point (with respect to the infeasible incumbent) + // must have been generated. + hMax = 0.0; + const NOMAD::Double hCurrentXInf = _currentIncumbentInf->getH(_computeType); + for (const auto& xFilterInf: _xFilterInf) + { + const auto eval = xFilterInf->getEval(_computeType.evalType); + const NOMAD::Double h = eval->getH(_computeType.Short()); + if (h < hCurrentXInf) + hMax = std::max(hMax, h); + } + + OUTPUT_DEBUG_START + s = "Partial success"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + } + else + { + OUTPUT_DEBUG_START + s = ((feasSuccessType == NOMAD::SuccessType::FULL_SUCCESS) || + (infSuccessType == NOMAD::SuccessType::FULL_SUCCESS)) ? "Full success" : "no success"; + NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); + OUTPUT_DEBUG_END + + if (!_xInf.empty()) + { + // hMax <- max_{x \in Uk+1} {h(x) : h(xinf) <= h(x) < max_{x in Ik} h(x)} + // When _currentIncumbentInfHmaxH does not exist, set hMax to + // hMax := max_{x in Ik+1} h(x). + const NOMAD::Double hMaxLimSup = + _currentIncumbentInfMaxH == nullptr ? hMaxPrev + : _currentIncumbentInfMaxH->getH(_computeType); + hMax = _currentIncumbentInf == nullptr ? 0.0 : _currentIncumbentInf->getH(_computeType); + for (const auto& xFilterInf: _xFilterInf) + { + const auto eval = xFilterInf->getEval(_computeType.evalType); + const NOMAD::Double h = eval->getH(_computeType.Short()); + if (h < hMaxLimSup) + hMax = std::max(hMax, h); + } + } + } + // If there is a problem, reset it to hMaxPrev; + if (hMax == 0) + hMax = hMaxPrev; + + // Set hMax and remove infeasible points above the threshold. + if (hMax != hMaxPrev) + { + setHMax(hMax); + } + } + + // Set n and check that all points have the same dimension + const bool updatedInc = updatedIncFeas || updatedIncInf; + if (updatedInc) { - // Set n and check that all points have the same dimension setN(); - - // Update incumbents - updateCurrentIncumbents(); - } - - + const bool updated = updatedFeas || updatedInf; OUTPUT_DEBUG_START if (updated) { @@ -1005,21 +1210,36 @@ bool NOMAD::DMultiMadsBarrier::updateWithPoints( } +void NOMAD::DMultiMadsBarrier::updateCurrentIncumbentInfMaxH() +{ + _currentIncumbentInfMaxH = nullptr; + NOMAD::Double currentHMax = 0.0; + for (const auto& xInf: _xInf) + { + const NOMAD::Double h = xInf->getH(_computeType); + if (h.isDefined() && h > currentHMax) + { + currentHMax = h; + _currentIncumbentInfMaxH = xInf; + } + } +} + + void NOMAD::DMultiMadsBarrier::updateXInfAndFilterInfAfterHMaxSet() { - if (_xInf.size() == 0) + if (_xInf.empty()) { return; } size_t currentInd = 0; - - // Remove all infeasible incumbent solutions below the threshold _hMax. + + // Remove all infeasible incumbent solutions above the threshold _hMax. std::vector isInXInf(_xInf.size(), true); - for (const auto& xInf : _xInf) + for (const auto& xInf: _xInf) { - const NOMAD::Eval* eval = xInf->getEval(NOMAD::EvalType::BB); - NOMAD::Double h = eval->getH(); + const NOMAD::Double h = xInf->getH(_computeType); if (h > _hMax) { @@ -1031,20 +1251,19 @@ void NOMAD::DMultiMadsBarrier::updateXInfAndFilterInfAfterHMaxSet() currentInd = 0; _xInf.erase(std::remove_if(_xInf.begin(), _xInf.end(), - [¤tInd, &isInXInf](const EvalPointPtr evalPoint) + [¤tInd, &isInXInf](const EvalPointPtr& evalPoint) { bool isRemoved = !isInXInf[currentInd]; ++currentInd; return isRemoved; }), _xInf.end()); + // Remove all infeasible non dominated solutions above the threshold _hMax. currentInd = 0; - // Remove all infeasible non dominated solutions below the threshold _hMax. std::vector isInXFilterInf(_xFilterInf.size(), true); - for (const auto& xFilterInf : _xFilterInf) + for (const auto& xFilterInf: _xFilterInf) { - const NOMAD::Eval* eval = xFilterInf->getEval(NOMAD::EvalType::BB); - NOMAD::Double h = eval->getH(); + const NOMAD::Double h = xFilterInf->getH(_computeType); if (h > _hMax) { @@ -1056,7 +1275,7 @@ void NOMAD::DMultiMadsBarrier::updateXInfAndFilterInfAfterHMaxSet() currentInd = 0; _xFilterInf.erase(std::remove_if(_xFilterInf.begin(), _xFilterInf.end(), - [¤tInd, &isInXFilterInf](const EvalPointPtr evalPoint) + [¤tInd, &isInXFilterInf](const EvalPointPtr& evalPoint) { bool isRemoved = !isInXFilterInf[currentInd]; ++currentInd; @@ -1064,43 +1283,47 @@ void NOMAD::DMultiMadsBarrier::updateXInfAndFilterInfAfterHMaxSet() }), _xFilterInf.end()); std::sort(_xFilterInf.begin(), _xFilterInf.end(), - [](const EvalPointPtr evalPoint1, const EvalPointPtr evalPoint2) -> bool + [this](const EvalPointPtr& evalPoint1, const EvalPointPtr& evalPoint2) -> bool { - const NOMAD::Eval* eval1 = evalPoint1->getEval(NOMAD::EvalType::BB); - const NOMAD::Eval* eval2 = evalPoint2->getEval(NOMAD::EvalType::BB); - return eval1->getFs().lexicographicalCmp(eval2->getFs()); + return evalPoint1->getFs(_computeType).lexicographicalCmp(evalPoint2->getFs(_computeType)); }); // And reinsert potential infeasible non dominated points into the set of infeasible // solutions. currentInd = 0; isInXInf = std::vector(_xFilterInf.size(), false); - for (const auto& evalPoint : _xFilterInf) + for (const auto& evalPoint: _xFilterInf) { + if (findEvalPoint(_xInf.begin(), _xInf.end(), *evalPoint) != _xInf.end()) + { + currentInd++; + continue; + } + // If new point is not in _xInf, check if it is not dominated - if (findEvalPoint(_xInf.begin(), _xInf.end(), *evalPoint) == _xInf.end()) + size_t currentIndTmp = 0; + bool insert = true; + for (const auto& evalPointInf: _xFilterInf) { - size_t currentIndTmp = 0; - bool insert = true; - for (const auto& evalPointInf : _xFilterInf) + if (currentIndTmp == currentInd) { - if (currentIndTmp != currentInd) - { - auto compFlag = evalPoint->compMO(*evalPointInf, NOMAD::EvalType::BB, true); - if (compFlag == CompareType::DOMINATED) - { - insert = false; - break; - } - else if (compFlag == CompareType::DOMINATING) - { - isInXInf[currentIndTmp] = false; - } - } currentIndTmp++; + continue; + } + + const auto compFlag = evalPoint->compMO(*evalPointInf, _computeType, true); + if (compFlag == CompareType::DOMINATED) + { + insert = false; + break; + } + if (compFlag == CompareType::DOMINATING) + { + isInXInf[currentIndTmp] = false; } - isInXInf[currentInd] = insert; + currentIndTmp++; } + isInXInf[currentInd] = insert; currentInd++; } @@ -1113,18 +1336,15 @@ void NOMAD::DMultiMadsBarrier::updateXInfAndFilterInfAfterHMaxSet() } std::sort(_xInf.begin(), _xInf.end(), - [](const EvalPointPtr evalPoint1, const EvalPointPtr evalPoint2) -> bool + [this](const EvalPointPtr& evalPoint1, const EvalPointPtr& evalPoint2) -> bool { - const NOMAD::Eval* eval1 = evalPoint1->getEval(NOMAD::EvalType::BB); - const NOMAD::Eval* eval2 = evalPoint2->getEval(NOMAD::EvalType::BB); - return eval1->getFs().lexicographicalCmp(eval2->getFs()); + return evalPoint1->getFs(_computeType).lexicographicalCmp(evalPoint2->getFs(_computeType)); }); - return; } // Nice formatting display. -std::vector NOMAD::DMultiMadsBarrier::display(const size_t max) const +std::vector NOMAD::DMultiMadsBarrier::display(const size_t max, const bool displayMeshes) const { std::vector vs; @@ -1134,7 +1354,13 @@ std::vector NOMAD::DMultiMadsBarrier::display(const size_t max) con for (const auto & xFeas : _xFeas) { - vs.push_back("X_FEAS " + xFeas->displayAll()); + vs.push_back("X_FEAS " + xFeas->displayAll(NOMAD::defaultFHComputeTypeS)); + if (displayMeshes) + { + const auto mesh = xFeas->getMesh(); + vs.push_back("delta mesh size = " + mesh->getdeltaMeshSize().display()); + vs.push_back("Delta mesh size = " + mesh->getDeltaFrameSize().display()); + } nbXFeas++; if (nbXFeas >= max && _xFeas.size() > max) { @@ -1144,7 +1370,13 @@ std::vector NOMAD::DMultiMadsBarrier::display(const size_t max) con } for (const auto &xInf : _xInf) { - vs.push_back("X_INF " + xInf->displayAll() ); + vs.push_back("X_INF " + xInf->displayAll(NOMAD::defaultFHComputeTypeS) ); + if (displayMeshes) + { + const auto mesh = xInf->getMesh(); + vs.push_back("delta mesh size = " + mesh->getdeltaMeshSize().display()); + vs.push_back("Delta mesh size = " + mesh->getDeltaFrameSize().display()); + } nbXInf++; if (nbXInf >= max && _xInf.size() > max) @@ -1155,7 +1387,13 @@ std::vector NOMAD::DMultiMadsBarrier::display(const size_t max) con } for (const auto &xFilterInf: _xFilterInf) { - vs.push_back("X_FILTER" + xFilterInf->displayAll()); + vs.push_back("X_FILTER" + xFilterInf->displayAll(NOMAD::defaultFHComputeTypeS)); + if (displayMeshes) + { + const auto mesh = xFilterInf->getMesh(); + vs.push_back("delta mesh size = " + mesh->getdeltaMeshSize().display()); + vs.push_back("Delta mesh size = " + mesh->getDeltaFrameSize().display()); + } nbXFilterInf++; if (nbXFilterInf >= max && _xFilterInf.size() > max) @@ -1166,15 +1404,15 @@ std::vector NOMAD::DMultiMadsBarrier::display(const size_t max) con } vs.push_back("H_MAX " + getHMax().display(NOMAD::DISPLAY_PRECISION_FULL)); - vs.push_back("Ref Best Feasible: " + (_refBestFeas ? _refBestFeas->displayAll() : "NULL") ); - vs.push_back("Ref Best Infeasible: " + (_refBestInf ? _refBestInf->displayAll() : "NULL")); + vs.push_back("Ref Best Feasible: " + (_refBestFeas ? _refBestFeas->displayAll(NOMAD::defaultFHComputeTypeS) : "NULL") ); + vs.push_back("Ref Best Infeasible: " + (_refBestInf ? _refBestInf->displayAll(NOMAD::defaultFHComputeTypeS) : "NULL")); return vs; } -NOMAD::Double NOMAD::DMultiMadsBarrier::getMeshMaxFrameSize(const NOMAD::EvalPointPtr pt) const +NOMAD::Double NOMAD::DMultiMadsBarrier::getMeshMaxFrameSize(const NOMAD::EvalPointPtr& pt) const { NOMAD::Double maxRealVal = -1.0; NOMAD::Double maxIntegerVal = -1.0; @@ -1226,111 +1464,99 @@ NOMAD::Double NOMAD::DMultiMadsBarrier::getMeshMaxFrameSize(const NOMAD::EvalPoi void NOMAD::DMultiMadsBarrier::updateCurrentIncumbentInf() { _currentIncumbentInf = nullptr; - if (_xFeas.size() > 0 && _xInf.size() > 0) + if (_xFeas.empty() || _xInf.empty()) { - // Get the infeasible solution with maximum dominance move below the _hMax threshold, - // according to the set of best feasible incumbent solutions. - size_t currentInd = 0; - double maxDomMove = -NOMAD::INF; + _currentIncumbentInf = getFirstXIncInfNoXFeas(); + return; + } - for (size_t j = 0; j < _xInf.size(); ++j) - { - // Compute dominance move - // = min \sum_{1}^m max(fi(y) - fi(x), 0) - // y \in Fk - double tmpDomMove = NOMAD::INF; - const NOMAD::Eval* evalInf = _xInf[j]->getEval(NOMAD::EvalType::BB); - NOMAD::Double h = evalInf->getH(); + const auto evalType = _computeType.evalType; + const auto computeTypeS = _computeType.fhComputeTypeS; - if (h.isDefined() && h <= _hMax) + auto computeDomMove = [evalType, computeTypeS](const size_t nobj, + const EvalPointPtr& xInf, + const std::vector& xFeasElems, + const bool domXFeasElems) -> double + { + double minDomMove = std::numeric_limits::infinity(); + for (const auto& xFeas: xFeasElems) + { + const NOMAD::Eval* evalFeas = xFeas->getEval(evalType); + const NOMAD::Eval* evalInf = xInf->getEval(evalType); + double domMove = 0.0; + for (size_t i = 0; i < nobj; ++i) { - for (const auto &xFeas : _xFeas) - { - - double sumVal = 0.0; - const NOMAD::Eval *evalFeas = xFeas->getEval(NOMAD::EvalType::BB); - - // Compute \sum_{1}^m max (fi(y) - fi(x), 0) - for (size_t i = 0; i < _nobj; i++) - { - sumVal += std::max(evalFeas->getFs()[i].todouble() - - evalInf->getFs()[i].todouble(), - 0.0); - } - if (tmpDomMove > sumVal) - { - tmpDomMove = sumVal; - } - } - - // Get the maximum dominance move index - if (maxDomMove < tmpDomMove) { - maxDomMove = tmpDomMove; - currentInd = j; - } + const double fFeasVal = evalFeas->getFs(computeTypeS)[i].todouble(); + const double fInfVal = evalInf->getFs(computeTypeS)[i].todouble(); + const double diffVal = domXFeasElems ? fFeasVal - fInfVal + : fInfVal - fFeasVal; + domMove += std::max(diffVal, 0.0); } + minDomMove = std::min(minDomMove, domMove); } + return minDomMove; + }; - // In this case, all infeasible solutions are "dominated" in terms of fvalues - // by at least one element of Fk - if (NOMAD::Double(maxDomMove) == 0.0) - { - // In this case, get the infeasible solution below the _hMax threshold which has - // minimal dominance move, when considered a maximization problem. - double minDomMove = NOMAD::INF; - currentInd = 0; + // Get the infeasible solution with maximum dominance move below the _hMax threshold, + // according to the set of best feasible incumbent solutions. + size_t currentInd = 0; + double maxDomMove = -NOMAD::INF; + for (size_t j = 0; j < _xInf.size(); ++j) + { + const NOMAD::Eval* evalInf = _xInf[j]->getEval(evalType); + const NOMAD::Double h = evalInf->getH(computeTypeS); + if (!h.isDefined() || h > _hMax) + continue; - for (size_t j = 0; j < _xInf.size(); ++j) - { - // Compute dominance move - // = min \sum_{1}^m max(fi(x) - fi(y), 0) - // y \in Fk - double tmpDomMove = NOMAD::INF; - const NOMAD::Eval* evalInf = _xInf[j]->getEval(NOMAD::EvalType::BB); - - NOMAD::Double h = evalInf->getH(); - if (h.isDefined() && h <= _hMax) - { - for (const auto& xFeas : _xFeas) - { - - double sumVal = 0.0; - const NOMAD::Eval* evalFeas = xFeas->getEval(NOMAD::EvalType::BB); - - // Compute \sum_{1}^m max (fi(x) - fi(y), 0) - for (size_t i = 0; i < _nobj; i++) - { - sumVal += std::max(evalInf->getFs()[i].todouble() - - evalFeas->getFs()[i].todouble(), 0.0); - } - if (tmpDomMove > sumVal) - { - tmpDomMove = sumVal; - } - } - - // Get the minimal dominance move index - if (minDomMove > tmpDomMove) - { - minDomMove = tmpDomMove; - currentInd = j; - } - } - } + // Compute dominance move + // = min \sum_{1}^m max(fi(y) - fi(x), 0) + // y \in Fk + const double domMove = computeDomMove(_nobj, _xInf[j], _xFeas, true /*domXFeasElems*/); + + // Get the maximum dominance move index + if (maxDomMove < domMove) { + maxDomMove = domMove; + currentInd = j; } - _currentIncumbentInf = _xInf[currentInd]; } - else + if (NOMAD::Double(maxDomMove) > 0.0) { - _currentIncumbentInf = getFirstXIncInfNoXFeas(); + _currentIncumbentInf = _xInf[currentInd]; + return; } + // In this case, all infeasible solutions are "dominated" in terms of fvalues + // by at least one element of Fk. Get the infeasible solution below the _hMax + // threshold which has minimal dominance move, when considered a maximization + // problem. + double minDomMove = NOMAD::INF; + currentInd = 0; + for (size_t j = 0; j < _xInf.size(); ++j) + { + const NOMAD::Eval* evalInf = _xInf[j]->getEval(evalType); + const NOMAD::Double h = evalInf->getH(computeTypeS); + if (!h.isDefined() || h > _hMax) + continue; + + // Compute dominance move + // = min \sum_{1}^m max(fi(x) - fi(y), 0) + // y \in Fk + const double domMove = computeDomMove(_nobj, _xInf[j], _xFeas, false /*domXFeasElems*/); + + // Get the minimal dominance move index + if (minDomMove > domMove) + { + minDomMove = domMove; + currentInd = j; + } + } + _currentIncumbentInf = _xInf[currentInd]; } void NOMAD::DMultiMadsBarrier::updateCurrentIncumbentFeas() { - if (_xFeas.size() == 0) + if (_xFeas.empty()) { _currentIncumbentFeas = nullptr; return; @@ -1339,8 +1565,7 @@ void NOMAD::DMultiMadsBarrier::updateCurrentIncumbentFeas() if (_xFeas.size() == 1) { _currentIncumbentFeas =_xFeas[0]; - return ; - + return; } // Set max frame size of all elements @@ -1354,11 +1579,11 @@ void NOMAD::DMultiMadsBarrier::updateCurrentIncumbentFeas() std::vector canBeFrameCenter(_xFeas.size(), false); size_t nbSelectedCandidates = 0; - // see article DMultiMads Algorithm 4. + // See article DMultiMads Algorithm 4. for (size_t i = 0; i < _xFeas.size(); ++i) { - NOMAD::Double maxFrameSizeElt = getMeshMaxFrameSize(_xFeas[i]); + const NOMAD::Double maxFrameSizeElt = getMeshMaxFrameSize(_xFeas[i]); // Casting is required to avoid an integer overflow. if ((std::pow(10.0, -(double)_incumbentSelectionParam) * maxFrameSizeFeasElts <= maxFrameSizeElt) ) @@ -1379,154 +1604,177 @@ void NOMAD::DMultiMadsBarrier::updateCurrentIncumbentFeas() } else { - size_t selectedInd = std::distance(canBeFrameCenter.begin(), it); + const size_t selectedInd = std::distance(canBeFrameCenter.begin(), it); _currentIncumbentFeas =_xFeas[selectedInd]; } + return; } + // Only two points in the barrier. - else if ((nbSelectedCandidates == 2) && (_xFeas.size() == 2)) + if ((nbSelectedCandidates == 2) && (_xFeas.size() == 2)) { - const NOMAD::Eval* eval1 = _xFeas[0]->getEval(NOMAD::EvalType::BB); - const NOMAD::Eval* eval2 = _xFeas[1]->getEval(NOMAD::EvalType::BB); - auto objv1 = eval1->getFs(); - auto objv2 = eval2->getFs(); - if (objv1.abs().max() > objv2.abs().max()) - { - _currentIncumbentFeas =_xFeas[0]; - } - else - { - _currentIncumbentFeas =_xFeas[1]; - } + const auto objv1 = _xFeas[0]->getFs(_computeType); + const auto objv2 = _xFeas[1]->getFs(_computeType); + _currentIncumbentFeas = (objv1.abs().max() > objv2.abs().max()) ? _xFeas[0] : _xFeas[1]; + return; } + // More than three points in the barrier. - else + // First case: biobjective optimization. Points are already ranked by lexicographic order. + if (_nobj == 2) { - // First case: biobjective optimization. Points are already ranked by lexicographic order. - if (_nobj == 2) + size_t currentBestInd = 0; + NOMAD::Double maxGap = -1.0; + NOMAD::Double currentGap; + for (size_t obj = 0; obj < _nobj; ++obj) { - size_t currentBestInd = 0; - NOMAD::Double maxGap = -1.0; - NOMAD::Double currentGap; - for (size_t obj = 0; obj < _nobj; ++obj) - { - // Get extreme values value according to one objective - NOMAD::Double fmin = _xFeas[0]->getEval(NOMAD::EvalType::BB)->getFs()[obj]; - NOMAD::Double fmax = _xFeas[_xFeas.size()-1]->getEval(NOMAD::EvalType::BB)->getFs()[obj]; - - // In this case, it means all elements of _xFeas are equal (return the first one) - if (fmin == fmax) - { - break; - } - - // Intermediate points - for (size_t i = 1; i < _xFeas.size()-1;++i) - { - currentGap = _xFeas[i+1]->getEval(NOMAD::EvalType::BB)->getFs()[obj] - - _xFeas[i-1]->getEval(NOMAD::EvalType::BB)->getFs()[obj]; - currentGap /= (fmax -fmin); - if (canBeFrameCenter[i] && currentGap >= maxGap) - { - maxGap = currentGap; - currentBestInd = i; - } - } + // Get extreme values value according to one objective + const NOMAD::Double fmin = _xFeas[0]->getFs(_computeType)[obj]; + const NOMAD::Double fmax = _xFeas[_xFeas.size()-1]->getFs(_computeType)[obj]; - // Extreme points - currentGap = 2 * (_xFeas[_xFeas.size() - 1]->getEval(NOMAD::EvalType::BB) ->getFs()[obj] - - _xFeas[_xFeas.size() - 2] ->getEval(NOMAD::EvalType::BB) ->getFs()[obj]); - currentGap /= (fmax - fmin); - if (canBeFrameCenter[_xFeas.size()-1] && currentGap > maxGap) - { - maxGap = currentGap; - currentBestInd = _xFeas.size()-1; - } + // For biobjective optimization, it means all elements of _xFeas are equal. + // We return the first one. + if (fmin == fmax) + { + _currentIncumbentFeas =_xFeas[currentBestInd]; + return; + } - currentGap = 2 * (_xFeas[1]->getEval(NOMAD::EvalType::BB)->getFs()[obj] - - _xFeas[0]->getEval(NOMAD::EvalType::BB)->getFs()[obj]); + // Intermediate points + for (size_t i = 1; i < _xFeas.size()-1;++i) + { + if (!canBeFrameCenter[i]) + continue; + + currentGap = _xFeas[i+1]->getFs(_computeType)[obj] - + _xFeas[i-1]->getFs(_computeType)[obj]; currentGap /= (fmax -fmin); - if (canBeFrameCenter[0] && currentGap > maxGap) + if (currentGap >= maxGap) { maxGap = currentGap; - currentBestInd = 0; + currentBestInd = i; } } - _currentIncumbentFeas =_xFeas[currentBestInd]; - } - // More than 2 objectives - else - { - std::vector > tmpXFeasPInd(_xFeas.size()); - - // Initialize it. - for (size_t i = 0; i < tmpXFeasPInd.size(); ++i) + + // Extreme points + currentGap = 2 * (_xFeas[_xFeas.size() - 1]->getFs(_computeType)[obj] - + _xFeas[_xFeas.size() - 2]->getFs(_computeType)[obj]); + currentGap /= (fmax - fmin); + if (canBeFrameCenter[_xFeas.size()-1] && currentGap > maxGap) + { + maxGap = currentGap; + currentBestInd = _xFeas.size()-1; + } + + currentGap = 2 * (_xFeas[1]->getFs(_computeType)[obj] - + _xFeas[0]->getFs(_computeType)[obj]); + currentGap /= (fmax -fmin); + if (canBeFrameCenter[0] && currentGap > maxGap) { - tmpXFeasPInd[i] = std::make_pair(*_xFeas[i], i); + maxGap = currentGap; + currentBestInd = 0; } + } + _currentIncumbentFeas =_xFeas[currentBestInd]; + return; + } - size_t currentBestInd = 0; - NOMAD::Double maxGap = -1.0; - NOMAD::Double currentGap; + // Second case: more than 2 objectives + std::vector > tmpXFeasPInd(_xFeas.size()); - for (size_t obj = 0; obj < _nobj; ++obj) - { - // Sort elements of tmpXFeasPInd according to objective obj (in ascending order) - std::sort(tmpXFeasPInd.begin(), tmpXFeasPInd.end(), - [obj](const std::pair& t1, const std::pair t2)->bool - { - const NOMAD::Eval* eval1 = t1.first.getEval(NOMAD::EvalType::BB); - const NOMAD::Eval* eval2 = t2.first.getEval(NOMAD::EvalType::BB); - return eval1->getFs()[obj] < eval2->getFs()[obj]; - }); + // Initialize it. + for (size_t i = 0; i < tmpXFeasPInd.size(); ++i) + { + tmpXFeasPInd[i] = std::make_pair(_xFeas[i], i); + } + + size_t currentBestInd = 0; + NOMAD::Double maxGap = -1.0; + NOMAD::Double currentGap; + + for (size_t obj = 0; obj < _nobj; ++obj) + { + // Sort elements of tmpXFeasPInd according to objective obj (in ascending order) + std::sort(tmpXFeasPInd.begin(), tmpXFeasPInd.end(), + [obj,this](const std::pair& t1, const std::pair& t2)->bool + { + return t1.first->getFs(_computeType)[obj] < t2.first->getFs(_computeType)[obj]; + }); - // Get extreme values value according to one objective - NOMAD::Double fmin = tmpXFeasPInd[0].first.getEval(NOMAD::EvalType::BB)->getFs()[obj]; - NOMAD::Double fmax = tmpXFeasPInd[tmpXFeasPInd.size()-1].first.getEval(NOMAD::EvalType::BB)->getFs()[obj]; + // Get extreme values value according to one objective + NOMAD::Double fmin = tmpXFeasPInd[0].first->getFs(_computeType)[obj]; + NOMAD::Double fmax = tmpXFeasPInd[tmpXFeasPInd.size()-1].first->getFs(_computeType)[obj]; - // Can happen for exemple when we have several minima or for more than three objectives - if (fmin == fmax) - { - fmin = 0.0; - fmax = 1.0; - } + // Can happen for example when we have several minima or for more than three objectives + if (fmin == fmax) + { + fmin = 0.0; + fmax = 1.0; + } - // Intermediate points - for (size_t i = 1; i < tmpXFeasPInd.size()-1;++i) - { - currentGap = tmpXFeasPInd[i+1].first.getEval(NOMAD::EvalType::BB)->getFs()[obj] - - tmpXFeasPInd[i-1].first.getEval(NOMAD::EvalType::BB)->getFs()[obj]; - currentGap /= (fmax -fmin); - if (canBeFrameCenter[tmpXFeasPInd[i].second] && currentGap >= maxGap) - { - maxGap = currentGap; - currentBestInd = tmpXFeasPInd[i].second; - } - } + // Intermediate points + for (size_t i = 1; i < tmpXFeasPInd.size()-1;++i) + { + if (!canBeFrameCenter[tmpXFeasPInd[i].second]) + continue; + + currentGap = tmpXFeasPInd[i+1].first->getFs(_computeType)[obj] - + tmpXFeasPInd[i-1].first->getFs(_computeType)[obj]; + currentGap /= (fmax -fmin); + if (currentGap >= maxGap) + { + maxGap = currentGap; + currentBestInd = tmpXFeasPInd[i].second; + } + } - // Extreme points - currentGap = 2 * (tmpXFeasPInd[tmpXFeasPInd.size() - 1].first.getEval(NOMAD::EvalType::BB) ->getFs()[obj] - - tmpXFeasPInd[tmpXFeasPInd.size() - 2].first.getEval(NOMAD::EvalType::BB) ->getFs()[obj]); - currentGap /= (fmax - fmin); - if (canBeFrameCenter[tmpXFeasPInd[tmpXFeasPInd.size()-1].second] && currentGap > maxGap) - { - maxGap = currentGap; - currentBestInd = tmpXFeasPInd[tmpXFeasPInd.size()-1].second; - } + // Extreme points + currentGap = 2 * (tmpXFeasPInd[tmpXFeasPInd.size() - 1].first->getFs(_computeType)[obj] - + tmpXFeasPInd[tmpXFeasPInd.size() - 2].first->getFs(_computeType)[obj]); + currentGap /= (fmax - fmin); + if (canBeFrameCenter[tmpXFeasPInd[tmpXFeasPInd.size()-1].second] && currentGap > maxGap) + { + maxGap = currentGap; + currentBestInd = tmpXFeasPInd[tmpXFeasPInd.size()-1].second; + } - currentGap = 2 * (tmpXFeasPInd[1].first.getEval(NOMAD::EvalType::BB) ->getFs()[obj] - - tmpXFeasPInd[0].first.getEval(NOMAD::EvalType::BB) ->getFs()[obj]); - currentGap /= (fmax -fmin); - if (canBeFrameCenter[tmpXFeasPInd[0].second] && currentGap > maxGap) - { - maxGap = currentGap; - currentBestInd = tmpXFeasPInd[0].second; - } - } - _currentIncumbentFeas = _xFeas[currentBestInd]; + currentGap = 2 * (tmpXFeasPInd[1].first->getFs(_computeType)[obj] - + tmpXFeasPInd[0].first->getFs(_computeType)[obj]); + currentGap /= (fmax -fmin); + if (canBeFrameCenter[tmpXFeasPInd[0].second] && currentGap > maxGap) + { + maxGap = currentGap; + currentBestInd = tmpXFeasPInd[0].second; + } + } + _currentIncumbentFeas = _xFeas[currentBestInd]; +} + + +void NOMAD::DMultiMadsBarrier::updateCurrentIdealFeas() +{ + _currentIdealFeas = std::vector(_nobj, NOMAD::INF); + for (const auto& xFeas: _xFeas) + { + for (size_t obj = 0; obj < _nobj; ++obj) + { + if (_currentIdealFeas[obj] > xFeas->getFs(_computeType)[obj]) + _currentIdealFeas[obj] = xFeas->getFs(_computeType)[obj]; + } + } +} + + +void NOMAD::DMultiMadsBarrier::updateCurrentIdealInf() +{ + _currentIdealInf = std::vector(_nobj, NOMAD::INF); + for (const auto& xInf: _xInf) + { + const auto& fvaluesXinf = xInf->getFs(_computeType); + for (size_t obj = 0; obj < _nobj; ++obj) + { + if (_currentIdealInf[obj] > fvaluesXinf[obj]) + _currentIdealInf[obj] = xInf->getFs(_computeType)[obj]; } - } - - } diff --git a/src/Algos/DMultiMads/DMultiMadsBarrier.hpp b/src/Algos/DMultiMads/DMultiMadsBarrier.hpp index d7e47145..70f7d26b 100644 --- a/src/Algos/DMultiMads/DMultiMadsBarrier.hpp +++ b/src/Algos/DMultiMads/DMultiMadsBarrier.hpp @@ -44,8 +44,8 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_DMULTIMADSBARRIER -#define __NOMAD_4_4_DMULTIMADSBARRIER +#ifndef __NOMAD_4_5_DMULTIMADSBARRIER +#define __NOMAD_4_5_DMULTIMADSBARRIER #include "../../Eval/BarrierBase.hpp" #include "../../Eval/EvalPoint.hpp" @@ -63,10 +63,17 @@ class DMultiMadsBarrier : public BarrierBase // The points of interest are not necessarily the incumbents defined in BarrierBase: _xIncFeas[0] and _xIncInf[0] EvalPointPtr _currentIncumbentFeas; ///< current feasible of interest for DmultiMads EvalPointPtr _currentIncumbentInf; ///< current infeasible of interest for DMultiMads + EvalPointPtr _currentIncumbentInfMaxH; ///< current infeasible among the best infeasible with max h value. - ArrayOfDouble _fixedVariables; ///< The fixed variables. Use the fixed variables if the mesh and barrier points do not have the same dimension. The fixed variables are used to access the frame size for unfixed variables. This situation occurs for the EvaluatorControl barrier with fixed variables. + ArrayOfDouble _fixedVariables; ///< The fixed variables. Use the fixed variables if the mesh and barrier points do + /// not have the same dimension. + /// The fixed variables are used to access the frame size for unfixed variables. + /// This situation occurs for the EvaluatorControl barrier with fixed variables. - std::vector _xFilterInf; ///< Stores current non dominated infeasible solutions. Can hold a copy of EvalPoint in xFeas and XInf. + std::vector _xFilterInf; ///< Stores current non dominated infeasible solutions. Can hold a copy of EvalPoint in xInf. + + std::vector _currentIdealFeas; ///< The current ideal objective vector of the set of feasible solutions. + std::vector _currentIdealInf; ///< The current ideal objective vector of the set of infeasible solutions. /// Dimension of the objective vectors in the barrier. /** @@ -97,17 +104,20 @@ class DMultiMadsBarrier : public BarrierBase */ DMultiMadsBarrier(size_t nbObj, const Double& hMax = INF, - const size_t incumbentSelectionParam = 1, - const Point& fixedVariables = Point(), - EvalType evalType = EvalType::BB, - ComputeType computeType = ComputeType::STANDARD, - const std::vector& evalPointList = std::vector(), - bool barrierInitializedFromCache= true, - const BBInputTypeList bbInputsType= std::vector()) - : BarrierBase(hMax), + const size_t incumbentSelectionParam = 1, + const Point& fixedVariables = Point(), + EvalType evalType = EvalType::BB, + FHComputeTypeS computeType = defaultFHComputeTypeS, + const std::vector& evalPointList = std::vector(), + bool barrierInitializedFromCache= true, + const BBInputTypeList bbInputsType= std::vector()) + : BarrierBase(evalType, computeType, hMax), _nobj(nbObj), _currentIncumbentFeas(nullptr), _currentIncumbentInf(nullptr), + _currentIncumbentInfMaxH(nullptr), + _currentIdealFeas(nbObj, NOMAD::INF), + _currentIdealInf(nbObj, NOMAD::INF), _fixedVariables(fixedVariables), _bbInputsType(bbInputsType), _incumbentSelectionParam(incumbentSelectionParam) @@ -115,10 +125,10 @@ class DMultiMadsBarrier : public BarrierBase checkHMax(); // The number of objectives is initialized via the call to the cache. - init(fixedVariables, evalType, computeType, barrierInitializedFromCache); // Initialize with cache (if flag is true) - init(fixedVariables, evalType, evalPointList, computeType); // Initializae with a list of points + init(fixedVariables, barrierInitializedFromCache); // Initialize with cache (if flag is true) + init(fixedVariables, evalPointList); // Initialize with a list of points - if (computeType == NOMAD::ComputeType::STANDARD && _nobj == 1) + if (computeType.computeType == NOMAD::ComputeType::STANDARD && _nobj == 1) { std::string s = "Error: Construction of a DMultiMadsBarrier with number of objectives equal to 1. "; s += "In this case, use Barrier"; @@ -126,7 +136,7 @@ class DMultiMadsBarrier : public BarrierBase } } - DMultiMadsBarrier(const DMultiMadsBarrier & b) + DMultiMadsBarrier(const DMultiMadsBarrier & b) : BarrierBase(b) { // Do not copy the barrier points _nobj = b._nobj; @@ -139,6 +149,11 @@ class DMultiMadsBarrier : public BarrierBase return std::make_shared(*this); } + size_t getNbObj() const + { + return _nobj; + } + /// Update ref best feasible and ref best infeasible values. /// Not used. Triggers an exception void updateRefBests() override ; @@ -198,6 +213,23 @@ class DMultiMadsBarrier : public BarrierBase return *_xInf[i]; } + /// Get the i non dominated infeasible incumbent. + /** + * If there is no infeasible point or index i is superior to the + * number of infeasible incumbents, raise an exception. + \return A single infeasible eval point. + */ + EvalPoint& getXFilterInf(size_t i) + { + if (i >= _xFilterInf.size()) + { + std::string s = "Error: try to get access to " + std::to_string(i) + " element of "; + s += "DMultiMadsBarrier but number of infeasible elements is " + std::to_string(_xFilterInf.size()) + "."; + throw NOMAD::Exception(__FILE__,__LINE__,s); + } + return *_xFilterInf[i]; + } + size_t nbXFilterInf() { return _xFilterInf.size(); @@ -208,8 +240,7 @@ class DMultiMadsBarrier : public BarrierBase return _xFilterInf; } - - + /*---------------*/ /* Other methods */ /*---------------*/ @@ -227,32 +258,28 @@ class DMultiMadsBarrier : public BarrierBase * \note Input EvalPoints are already in subproblem dimention */ SuccessType getSuccessTypeOfPoints(const EvalPointPtr xFeas, - const EvalPointPtr xInf, - EvalType evalType, - ComputeType computeType) override; + const EvalPointPtr xInf) override; /// Update xFeas and xInf according to given points. /* \param evalPointList vector of EvalPoints -- \b IN. - * \param keepAllPoints keep all good points, or keep just one point as in NOMAD 3 -- \b IN. - * \return true if the Barrier was updated, false otherwise - * \note Input EvalPoints are already in subproblem dimention - * \note After calling this function, all xInf elements of the MO Barrier - * are below _hMax. + * \param keepAllPoints keep all good points, or keep just non-dominated (and non-equal) solutions as in NOMAD 3 -- \b IN. + * \param updateInfeasibleIncumbentsAndHmax update hMax threshold and consequently the set of infeasible incumbents. + * \return true if the Barrier was updated, false otherwise. + * \note Input EvalPoints are already in subproblem dimension + * \note All xInf elements of the MO Barrier are always below _hMax. */ bool updateWithPoints(const std::vector& evalPointList, - EvalType evalType, - ComputeType computeType, const bool keepAllPoints = false, - const bool updateInfeasibleIncumbentAndHmax = false /* Not used here*/) override; - + const bool updateInfeasibleIncumbentsAndHmax = false) override; /// Update current feas and infeas incumbents. Called by DMultiMadsUpdate and when updating the barrier void updateCurrentIncumbents() { updateCurrentIncumbentFeas(); updateCurrentIncumbentInf(); + updateCurrentIncumbentInfMaxH(); } - + /// Return the barrier as a string. /* May be used for information, or for saving a barrier. In the former case, @@ -261,8 +288,21 @@ class DMultiMadsBarrier : public BarrierBase * \param max Maximum number of feasible and infeasible points to display * \return A vector of string describing the barrier */ - std::vector display(const size_t max = INF_SIZE_T) const override; - + std::vector display(const size_t max = INF_SIZE_T) const override + { + return display(max, false); + } + + /// Return the barrier as a string. + /* May be used for information, or for saving a barrier. In the former case, + * it may be useful to set parameter max to a small value (e.g., 4). In the + * latter case, INF_SIZE_T should be used so that all points are saved. + * \param max Maximum number of feasible and infeasible points to display + * \param displayMeshes Whether to display meshes associated to the points. + * \return A vector of string describing the barrier + */ + std::vector display(const size_t max = INF_SIZE_T, const bool displayMeshes = false) const; + private: /** @@ -270,13 +310,9 @@ class DMultiMadsBarrier : public BarrierBase * * Will throw exceptions or output error messages if something is wrong. Will remain silent otherwise. \param fixedVariables The fixed variables have a fixed value -- \b IN. - \param evalType Which eval (Blackbox or Model) to use to verify feasibility -- \b IN. - \param computeType Which compute type (standard, phase-one or user) must be available to find in cache -- \b IN. \param barrierInitializedFromCache Flag to initialize barrier from cache or not. -- \b IN. */ void init(const Point& fixedVariables, - EvalType evalType, - ComputeType computeType, bool barrierInitializedFromCache) override; /** @@ -284,14 +320,10 @@ class DMultiMadsBarrier : public BarrierBase * * Will throw exceptions or output error messages if something is wrong. Will remain silent otherwise. \param fixedVariables The fixed variables have a fixed value -- \b IN. - \param evalType Which eval (Blackbox or Model) to use to verify feasibility -- \b IN. \param evalPointList Additional points to consider to construct barrier. -- \b IN. - \param computeType Which compute type (standard, phase-one or user) must be available to find in cache -- \b IN. */ void init(const Point& fixedVariables, - EvalType evalType, - const std::vector& evalPointList, - ComputeType computeType); + const std::vector& evalPointList); /** * \brief Helper function for insertion. @@ -307,9 +339,7 @@ class DMultiMadsBarrier : public BarrierBase * * Will throw exceptions or output error messages if something is wrong. Will remain silent otherwise. */ - void checkXFeasIsFeas(const EvalPoint &xFeas, - EvalType evalType, - ComputeType computeType = ComputeType::STANDARD) override; + void checkXFeasIsFeas(const EvalPoint &xFeas) override; /** * \brief Helper function for infeasible point candidate search. @@ -323,33 +353,37 @@ class DMultiMadsBarrier : public BarrierBase /** * \brief Filter infeasible incumbent solutions when hMax is set. - * */ void updateXInfAndFilterInfAfterHMaxSet(); - NOMAD::Double getMeshMaxFrameSize(const NOMAD::EvalPointPtr pt) const; + NOMAD::Double getMeshMaxFrameSize(const NOMAD::EvalPointPtr& pt) const; /// Helper for updateWithPoints - bool updateFeasWithPoint(const EvalPoint& evalPoint, - EvalType evalType, - ComputeType computeType, - const bool keepAllPoints ); + NOMAD::CompareType updateFeasWithPoint(const EvalPoint& evalPoint, + const bool keepAllPoints); /// Helper for updateWithPoints - bool updateInfWithPoint(const EvalPoint& evalPoint, - EvalType evalType, - ComputeType computeType, - const bool keepAllPoints, - const bool feasHasBeenUpdated); - + NOMAD::CompareType updateInfWithPoint(const EvalPoint& evalPoint, + const bool keepAllPoints); + /// Helper for updateCurrentIncumbents void updateCurrentIncumbentFeas(); /// Helper for updateCurrentIncumbents void updateCurrentIncumbentInf(); - - + /// Helper for updateCurrentIncumbents + void updateCurrentIncumbentInfMaxH(); + + /** + * \brief Helper function to update the feasible ideal objective vector. + */ + void updateCurrentIdealFeas(); + + /** + * \brief Helper function to update the infeasible ideal objective vector. + */ + void updateCurrentIdealInf(); }; /// Display useful values so that a new Barrier could be constructed using these values. @@ -360,4 +394,4 @@ std::istream& operator>>(std::istream& is, DMultiMadsBarrier& barrier); #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_DMULTIMADSBARRIER__ +#endif // __NOMAD_4_5_DMULTIMADSBARRIER__ diff --git a/src/Algos/DMultiMads/DMultiMadsExpansionIntLineSearchMethod.cpp b/src/Algos/DMultiMads/DMultiMadsExpansionIntLineSearchMethod.cpp new file mode 100644 index 00000000..2ca9709c --- /dev/null +++ b/src/Algos/DMultiMads/DMultiMadsExpansionIntLineSearchMethod.cpp @@ -0,0 +1,418 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#include + +#include "../../Cache/CacheBase.hpp" +#include "../../Algos/CacheInterface.hpp" +#include "../../Algos/DMultiMads/DMultiMadsBarrier.hpp" +#include "../../Algos/DMultiMads/DMultiMadsIteration.hpp" +#include "../../Algos/DMultiMads/DMultiMadsMegaIteration.hpp" +#include "../../Algos/DMultiMads/DMultiMadsExpansionIntLineSearchMethod.hpp" +#include "../../Algos/SubproblemManager.hpp" +#include "../../Eval/ProgressiveBarrier.hpp" + +void NOMAD::DMultiMadsExpansionIntLineSearchMethod::init() +{ + if (nullptr == getParentOfType()) + { + throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMadsExpansionIntLineSearchMethod only works for DMultiMads"); + } + + setStepType(NOMAD::StepType::SEARCH_METHOD_DMULTIMADS_EXPANSIONINT_LINESEARCH); + + _bbInputTypes = _pbParams->getAttributeValue("BB_INPUT_TYPE"); + const bool hasIntegerVariables = !_bbInputTypes.empty() && std::any_of(_bbInputTypes.cbegin(), _bbInputTypes.cend(), + [](const NOMAD::BBInputType bbi) + { + return bbi == NOMAD::BBInputType::INTEGER; + }); + + const bool runExpansionLinesearch = _runParams->getAttributeValue("DMULTIMADS_EXPANSIONINT_LINESEARCH"); + const bool isEnabled = runExpansionLinesearch && hasIntegerVariables; + setEnabled(isEnabled); + + // Save lower and upper bounds + _lb = getPbParams()->getAttributeValue("LOWER_BOUND"); + _ub = getPbParams()->getAttributeValue("UPPER_BOUND"); + + // Deactivate the projection on the mesh for this search, as we only change integer variables. + _projectOnMesh = false; +} + +void NOMAD::DMultiMadsExpansionIntLineSearchMethod::preRunValidations() +{ + std::shared_ptr barrier = nullptr; + + const auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + const auto refComputeType = evc->getComputeType(); + + if (NOMAD::ComputeType::STANDARD != refComputeType) + { + NOMAD::Exception(__FILE__,__LINE__,"Cannot do expansion integer linesearch for DMultiMads on ComputeType other than STANDARD."); + } + + // Get barrier from upper MegaIteration, if available. + const auto megaIter = getParentOfType(false); + if (megaIter != nullptr) + { + barrier = megaIter->getBarrier(); + } + + if (nullptr == barrier || nullptr == std::dynamic_pointer_cast(barrier)) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads using expansion integer linesearch, we need a DMultiMadsBarrier."); + } + + if (evc->getCurrentEvalType() == NOMAD::EvalType::MODEL) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do expansion integer linesearch for DMultiMads on EvalType::MODEL."); + } + + // Keep a reference to the DMultiMads barrier. + _ref_dmads_barrier = barrier; +} + +NOMAD::Direction NOMAD::DMultiMadsExpansionIntLineSearchMethod::computePrimitiveDirection(const NOMAD::Point& frameCenter, + const NOMAD::Point& pointFrom, + int& initStepSize) const +{ + // Compute the generative direction for integer variables + bool hasRealDirCoordinates = false; + auto dir = NOMAD::Point::vectorize(pointFrom, frameCenter); + for (size_t i = 0; i < dir.size(); ++i) + { + if (_bbInputTypes[i] != NOMAD::BBInputType::INTEGER) + { + if (dir[i] != 0) + { + hasRealDirCoordinates = true; // The point was generated from non-integer coordinates + } + dir[i] = 0; // We will not move along these coordinates + } + else + { + dir[i] = dir[i].round(); // Be sure to round to the nearest integer + } + } + + auto gcd = [](int a, int b) + { + a = std::abs(a); + b = std::abs(b); + if (a == 0 || b == 0) + { + return std::max(a, b); + } + + while (b != 0) + { + int t = b; + b = a % b; + a = t; + } + return a; + }; + + // Extract the gcd of all dir coordinates + int gDivisor = dir[0].round(); + for (size_t i = 1; i < dir.size(); ++i) + { + gDivisor = gcd(gDivisor, dir[i].round()); + } + + // The frame center has been generated from a direction composed only of non-integer directions + if (gDivisor == 0) + { + dir *= gDivisor; + return dir; + } + + // Save the initStepSize: it is equal to gcd if gcd is a multiple of 2 and the frame center has been generated + // from integer directions; otherwise -1. + // NB: an explanation for this black-magic code can be found here: + // https://stackoverflow.com/questions/57025836/how-to-check-if-a-given-number-is-a-power-of-two + const bool isPowerOf2 = (gDivisor > 0) && ((gDivisor & (gDivisor-1)) == 0); + initStepSize = !hasRealDirCoordinates && isPowerOf2 ? gDivisor : -1; + + // Compute the primitive direction + for (size_t i = 0; i < dir.size(); ++i) + { + dir[i] = dir[i].round() / gDivisor; + } + + return dir; +} + +int NOMAD::DMultiMadsExpansionIntLineSearchMethod::computeMaxStepSize(const NOMAD::Point &frameCenter, + const NOMAD::Direction& dir, + const NOMAD::ArrayOfDouble &lb, + const NOMAD::ArrayOfDouble &ub) const +{ + // Compute maximal step size to reach bounds + int stepSize = std::numeric_limits::max(); + for (size_t i = 0; i < dir.size(); ++i) + { + if (dir[i] == 0) + { + continue; + } + + // We will never reach bounds according to these coordinates + if (dir[i] > 0 && (!ub[i].isDefined() || ub[i] == NOMAD::INF)) + { + continue; + } + if (dir[i] < 0 && (!lb[i].isDefined() || lb[i] == NOMAD::M_INF)) + { + continue; + } + + const NOMAD::Double xi = frameCenter[i]; + if (dir[i] > 0) + { + const NOMAD::Double ubmx = ub[i] - xi; + stepSize = std::min(stepSize, ubmx.round() / std::abs(dir[i].round())); + continue; + } + + if (dir[i] < 0) + { + const NOMAD::Double lbmx = xi - lb[i]; + stepSize = std::min(stepSize, lbmx.round() / std::abs(dir[i].round())); + } + } + + // No bound is defined. We affect a stepsize value equal to 10 + if (stepSize == std::numeric_limits::max()) + { + stepSize = 10; + } + return stepSize; +} + +bool NOMAD::DMultiMadsExpansionIntLineSearchMethod::isInBarrier(const NOMAD::Point& x) const +{ + const auto dMadsBarrier = std::dynamic_pointer_cast(_ref_dmads_barrier); + for (size_t i = 0; i < dMadsBarrier->nbXFeas(); ++i) + { + if (*dMadsBarrier->getXFeas(i).getX() == x) + { + return true; + } + } + + for (size_t i = 0; i < dMadsBarrier->nbXFilterInf(); ++i) + { + if (*dMadsBarrier->getXFilterInf(i).getX() == x) + { + return true; + } + } + return false; +} + +void NOMAD::DMultiMadsExpansionIntLineSearchMethod::generateTrialPointsFinal() +{ + preRunValidations(); + + const auto dMadsBarrier = std::dynamic_pointer_cast(_ref_dmads_barrier); + + const auto currentFrameCenter = dMadsBarrier->getCurrentIncumbentFeas() != nullptr ? + dMadsBarrier->getCurrentIncumbentFeas() : dMadsBarrier->getCurrentIncumbentInf(); + if (currentFrameCenter == nullptr) + { + return; + } + + const auto pointFrom = currentFrameCenter->getPointFrom(NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); + if (nullptr == pointFrom || *pointFrom == *currentFrameCenter) + { + OUTPUT_INFO_START + AddOutputInfo("No available direction: stop"); + OUTPUT_INFO_END + return; + } + + // Compute the primitive direction + int initStepSize = -1; + auto dir = computePrimitiveDirection(*currentFrameCenter, *pointFrom, initStepSize); + if (dir.norm() == 0) + { + OUTPUT_INFO_START + AddOutputInfo("No available primitive direction: stop"); + OUTPUT_INFO_END + return; + } + + OUTPUT_INFO_START + const auto initDir = NOMAD::Point::vectorize(*pointFrom, *currentFrameCenter); + AddOutputInfo("Frame center: " + currentFrameCenter->display()); + AddOutputInfo("Initial direction: " + initDir.display()); + AddOutputInfo("Primitive direction: " + dir.display()); + OUTPUT_INFO_END + + // Compute the maximum step size parameter to reach problem integer bounds. + const int maxStepSize = computeMaxStepSize(*currentFrameCenter, dir, _lb, _ub); + + // We have already reach one of the problem bounds + if (maxStepSize == 0) + { + OUTPUT_INFO_START + AddOutputInfo("Max step size parameter value is 0: stop"); + OUTPUT_INFO_END + return; + } + + // Obtain cache. + const auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + const bool useCache = evc->getUseCache(); + + // We try to guess if the frame center has already been generated from a primitive direction multiplied by + // some scalar, i.e. initStepSize, which must be superior to 1 if it is the case; and is equal to -1 otherwise. + // If the frame center has been generated from a primitive direction, we start a search with a step size parameter + // equal to 2 * initStepSize; but we must stay in bounds. + int stepSize = std::min(std::max(1, 2 * initStepSize), maxStepSize); + auto scaledDir = dir; + scaledDir *= stepSize; + + OUTPUT_INFO_START + AddOutputInfo("Step size parameter: " + std::to_string(stepSize)); + AddOutputInfo("Scaled direction: " + scaledDir.display()); + OUTPUT_INFO_END + + // First candidate tentative + auto ev1 = NOMAD::EvalPoint(*currentFrameCenter->getX() + scaledDir); + ev1.setPointFrom(std::make_shared(*currentFrameCenter), + NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); + ev1.addGenStep(getStepType()); + snapPointToBoundsAndProjectOnMesh(ev1, _lb, _ub); + + const bool inBarrier1 = isInBarrier(*ev1.getX()); + + // In this case, the candidate has never been evaluated. + if (!useCache && !inBarrier1) + { + insertTrialPoint(ev1); + return; + } + + if (useCache) + { + NOMAD::CacheInterface cacheInterface(this); + NOMAD::EvalPoint foundEvalPoint; + + // The point has not been evaluated. Generate it. + if (!cacheInterface.find(*ev1.getX(), foundEvalPoint)) + { + insertTrialPoint(ev1); + return; + } + } + + // At this point, the candidate is already in the cache. + OUTPUT_INFO_START + std::string s = "Search candidate "; + s += ev1.getX()->display(); + s += " already in cache"; + AddOutputInfo(s); + OUTPUT_INFO_END + + // We cannot further decrease the step size parameter. + if (stepSize == 1) + { + OUTPUT_INFO_START + AddOutputInfo("Step size parameter has reached 0: stop"); + OUTPUT_INFO_END + return; + } + + // Divide the stepsize by 2 and retry. + stepSize = std::max(1, stepSize / 2); + scaledDir = dir; + scaledDir *= stepSize; + + OUTPUT_INFO_START + AddOutputInfo("New tentative"); + AddOutputInfo("Step size parameter: " + std::to_string(stepSize)); + AddOutputInfo("Scaled direction: " + scaledDir.display()); + OUTPUT_INFO_END + + auto ev2 = NOMAD::EvalPoint(*currentFrameCenter->getX() + scaledDir); + + ev2.setPointFrom(std::make_shared(*currentFrameCenter), + NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); + ev2.addGenStep(getStepType()); + snapPointToBoundsAndProjectOnMesh(ev2, _lb, _ub); + + const bool inBarrier2 = isInBarrier(*ev2.getX()); + + if (!useCache && !inBarrier2) + { + insertTrialPoint(ev2); + return; + } + + if (useCache) + { + NOMAD::CacheInterface cacheInterface(this); + NOMAD::EvalPoint foundEvalPoint; + + // The point has not been evaluated. Generate it. + if (!cacheInterface.find(*ev2.getX(), foundEvalPoint)) + { + insertTrialPoint(ev2); + return; + } + } + + OUTPUT_INFO_START + std::string s = "Search candidate n2 "; + s += ev1.getX()->display(); + s += " already in cache: stop."; + AddOutputInfo(s); + OUTPUT_INFO_END +} diff --git a/src/Algos/DMultiMads/DMultiMadsExpansionIntLineSearchMethod.hpp b/src/Algos/DMultiMads/DMultiMadsExpansionIntLineSearchMethod.hpp new file mode 100644 index 00000000..05d39b7c --- /dev/null +++ b/src/Algos/DMultiMads/DMultiMadsExpansionIntLineSearchMethod.hpp @@ -0,0 +1,114 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#ifndef __NOMAD_4_5_DMULTIMADSEXPANSIONINTLINESEARCHMETHOD__ +#define __NOMAD_4_5_DMULTIMADSEXPANSIONINTLINESEARCHMETHOD__ + +#include "../../Algos/AlgoStopReasons.hpp" +#include "../../Algos/Mads/SearchMethodSimple.hpp" +#include "../../Algos/DMultiMads/DMultiMadsBarrier.hpp" + +#include "../../nomad_nsbegin.hpp" + +/// Expansion integer linesearch method for DMultiMads +/** + The expansion integer linesearch method is a backtracking linesearch method. + It tries to expand the current set of solutions by exploring along a direction + for integer variables only. + */ +class DMultiMadsExpansionIntLineSearchMethod final : public SearchMethodSimple +{ +private: + std::shared_ptr _ref_dmads_barrier; + + NOMAD::ArrayOfDouble _lb; + NOMAD::ArrayOfDouble _ub; + std::vector _bbInputTypes; + +public: + /// Constructor + /** + /param parentStep The parent of this search step -- \b IN. + */ + explicit DMultiMadsExpansionIntLineSearchMethod(const NOMAD::Step* parentStep) + : SearchMethodSimple(parentStep) + { + init(); + } + +private: + + /// Helper for constructor. + /** + Test if the DmultiMads expansion integer linesearch is enabled or not. + */ + void init(); + + void preRunValidations(); + + NOMAD::Direction computePrimitiveDirection(const NOMAD::Point& frameCenter, + const NOMAD::Point& pointFrom, + int& initStepSize) const; + + int computeMaxStepSize(const NOMAD::Point& frameCenter, + const NOMAD::Direction& dir, + const NOMAD::ArrayOfDouble& lb, + const NOMAD::ArrayOfDouble& ub) const; + + bool isInBarrier(const NOMAD::Point& x) const; + + /// Generate new points (no evaluation) + /** + \copydoc SearchMethodAlgo::generateTrialPointsFinal + The expansion integer linesearch method generates points along a direction + for integer variables only. + */ + void generateTrialPointsFinal() override; +}; + +#include "../../nomad_nsend.hpp" + +#endif // __NOMAD_4_5_DMULTIMADSEXPANSIONINTLINESEARCHMETHOD__ diff --git a/src/Algos/DMultiMads/DMultiMadsIteration.cpp b/src/Algos/DMultiMads/DMultiMadsIteration.cpp index 190e7e19..0648b30e 100644 --- a/src/Algos/DMultiMads/DMultiMadsIteration.cpp +++ b/src/Algos/DMultiMads/DMultiMadsIteration.cpp @@ -44,13 +44,18 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ - #include // For std::merge and std::unique #include "../../nomad_platform.hpp" #include "../../Algos/AlgoStopReasons.hpp" +#include "../../Algos/DMultiMads/DMultiMadsExpansionIntLineSearchMethod.hpp" #include "../../Algos/DMultiMads/DMultiMadsIteration.hpp" #include "../../Algos/DMultiMads/DMultiMadsMegaIteration.hpp" +#include "../../Algos/DMultiMads/DMultiMadsMiddlePointSearchMethod.hpp" +#include "../../Algos/DMultiMads/DMultiMadsNMSearchMethod.hpp" +#include "../../Algos/DMultiMads/DMultiMadsQuadDMSSearchMethod.hpp" +#include "../../Algos/DMultiMads/DMultiMadsQuadModSearchMethod.hpp" + void NOMAD::DMultiMadsIteration::init() { @@ -60,34 +65,56 @@ void NOMAD::DMultiMadsIteration::init() _poll = std::make_unique(this); _search = std::make_unique(this); - + // 1- First (at position 10), quad model search method for DMultiMads + auto quadDMSSearch = std::make_shared(this); + _search->insertSearchMethod(10, quadDMSSearch); + auto qmSearch = std::make_shared(this); + _search->insertSearchMethod(11, qmSearch); + + // 2- Nelder-Mead (NM) search for DMultiMads (at position 12) + auto nmSearch = std::make_shared(this); + _search->insertSearchMethod(12,nmSearch); + + // 3- Special Middle Point search method for DMultiMads (at position 13) + auto middlePtSearch = std::make_shared(this); + _search->insertSearchMethod(13, middlePtSearch); + + // 4- Special line search method for DMultiMads. + auto expansionLinesearch = std::make_shared(this); + _search->insertSearchMethod(13, expansionLinesearch); } void NOMAD::DMultiMadsIteration::startImp() { - // Update the center point (best feasible or best infeasible) around which the trial points are generated. + // Update the center point (the best feasible or best infeasible) around which the trial points are generated. _DMultiMadsAlgoUpdate->start(); bool updateSuccess = _DMultiMadsAlgoUpdate->run(); _DMultiMadsAlgoUpdate->end(); + if ( ! updateSuccess ) + { + auto stopReason = NOMAD::AlgoStopReasons::get ( getAllStopReasons() ); + + // The update is not a success. If the global stop reason is not set to terminate we set a default stop reason for initialization. + if ( !_stopReasons->checkTerminate() ) + stopReason->set( NOMAD::MadsStopType::UPDATE_FAILED); + } + + // Verify mesh stop conditions. // For DMultiMads, the mesh associated to a frame center is used by poll and search // Note: Mads keeps a single mesh - // Note: The mesh could be updated when calling setFrameCenter but it is more clear to do it explicitely. + // Note: The mesh could be updated when calling setFrameCenter, but it is clearer to do it explicitly. auto frameCenterMesh = _frameCenter->getMesh(); if ( nullptr != frameCenterMesh) { _mesh = frameCenterMesh; } + _mesh->checkMeshForStopping(_stopReasons); - if ( ! updateSuccess ) - { - auto stopReason = NOMAD::AlgoStopReasons::get ( getAllStopReasons() ); - - // The update is not a success. If the global stop reason is not set to terminate we set a default stop reason for initialization. - if ( !_stopReasons->checkTerminate() ) - stopReason->set( NOMAD::RandomAlgoStopType::UPDATE_FAILED); - } + OUTPUT_DEBUG_START + AddOutputDebug("Mesh Stop Reason: " + _stopReasons->getStopReasonAsString()); + OUTPUT_DEBUG_END } @@ -101,11 +128,7 @@ bool NOMAD::DMultiMadsIteration::runImp() // 1. Search if ( nullptr != _search && ! _stopReasons->checkTerminate() ) { - - _search->start(); - iterationSuccess = _search->run(); - _search->end(); - + if (iterationSuccess) { // If success, update MegaIteration best success type with success found. No poll will be performed. @@ -121,6 +144,7 @@ bool NOMAD::DMultiMadsIteration::runImp() { if (! iterationSuccess) { + // 2. Poll _poll->start(); @@ -139,6 +163,8 @@ bool NOMAD::DMultiMadsIteration::runImp() } } + + // End of the iteration: iterationSuccess is true if we have a partial or full success. return iterationSuccess; diff --git a/src/Algos/DMultiMads/DMultiMadsIteration.hpp b/src/Algos/DMultiMads/DMultiMadsIteration.hpp index b3f58095..8ad70c12 100644 --- a/src/Algos/DMultiMads/DMultiMadsIteration.hpp +++ b/src/Algos/DMultiMads/DMultiMadsIteration.hpp @@ -44,8 +44,8 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_DMULTIMADSITERATION__ -#define __NOMAD_4_4_DMULTIMADSITERATION__ +#ifndef __NOMAD_4_5_DMULTIMADSITERATION__ +#define __NOMAD_4_5_DMULTIMADSITERATION__ #include "../../Algos/Iteration.hpp" #include "../../Algos/DMultiMads/DMultiMadsUpdate.hpp" @@ -138,4 +138,4 @@ class DMultiMadsIteration: public Iteration #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_DMULTIMADSITERATION__ +#endif // __NOMAD_4_5_DMULTIMADSITERATION__ diff --git a/src/Algos/DMultiMads/DMultiMadsMegaIteration.cpp b/src/Algos/DMultiMads/DMultiMadsMegaIteration.cpp index 532cf5e6..5ea49fc5 100644 --- a/src/Algos/DMultiMads/DMultiMadsMegaIteration.cpp +++ b/src/Algos/DMultiMads/DMultiMadsMegaIteration.cpp @@ -144,7 +144,7 @@ void NOMAD::DMultiMadsMegaIteration::display( std::ostream& os ) const void NOMAD::DMultiMadsMegaIteration::read( std::istream& is ) { - throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMadsMegationIteration is not yet available."); + throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMadsMegaIteration is not yet available."); // // Set up structures to gather member info // size_t k=0; // // Read line by line diff --git a/src/Algos/DMultiMads/DMultiMadsMegaIteration.hpp b/src/Algos/DMultiMads/DMultiMadsMegaIteration.hpp index 923754c2..88ca26db 100644 --- a/src/Algos/DMultiMads/DMultiMadsMegaIteration.hpp +++ b/src/Algos/DMultiMads/DMultiMadsMegaIteration.hpp @@ -44,8 +44,8 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_DMULTIMADSMEGAITERATION__ -#define __NOMAD_4_4_DMULTIMADSMEGAITERATION__ +#ifndef __NOMAD_4_5_DMULTIMADSMEGAITERATION__ +#define __NOMAD_4_5_DMULTIMADSMEGAITERATION__ #include "../../Algos/MegaIteration.hpp" #include "../../Algos/DMultiMads/DMultiMadsIteration.hpp" @@ -135,4 +135,4 @@ std::istream& operator>>(std::istream& is, DMultiMadsMegaIteration& megaIteratio #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_DMULTIMADSMEGAITERATION__ +#endif // __NOMAD_4_5_DMULTIMADSMEGAITERATION__ diff --git a/src/Algos/DMultiMads/DMultiMadsMiddlePointSearchMethod.cpp b/src/Algos/DMultiMads/DMultiMadsMiddlePointSearchMethod.cpp new file mode 100644 index 00000000..fe795ae0 --- /dev/null +++ b/src/Algos/DMultiMads/DMultiMadsMiddlePointSearchMethod.cpp @@ -0,0 +1,262 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#include "../../Cache/CacheBase.hpp" +#include "../../Algos/CacheInterface.hpp" +#include "../../Algos/DMultiMads/DMultiMadsBarrier.hpp" +#include "../../Algos/DMultiMads/DMultiMadsIteration.hpp" +#include "../../Algos/DMultiMads/DMultiMadsMegaIteration.hpp" +#include "../../Algos/DMultiMads/DMultiMadsMiddlePointSearchMethod.hpp" +#include "../../Algos/SubproblemManager.hpp" +#include "../../Eval/ProgressiveBarrier.hpp" + +void NOMAD::DMultiMadsMiddlePointSearchMethod::init() +{ + if (nullptr == getParentOfType()) + { + throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMadsMiddlePointSearchMethod only works for DMultiMads"); + } + + setStepType(NOMAD::StepType::SEARCH_METHOD_DMULTIMADS_MIDDLEPOINT); + + const bool isEnabled = _runParams->getAttributeValue("DMULTIMADS_MIDDLEPOINT_SEARCH"); + setEnabled(isEnabled); +} + +void NOMAD::DMultiMadsMiddlePointSearchMethod::preRunValidations() +{ + std::shared_ptr barrier = nullptr; + + const auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + const auto refComputeType = evc->getComputeType(); + + if (NOMAD::ComputeType::STANDARD != refComputeType) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do Middle Point Search for DMultiMads on ComputeType other than STANDARD."); + } + + // Get barrier from upper MegaIteration, if available. + const auto megaIter = getParentOfType(false); + if (megaIter != nullptr) + { + barrier = megaIter->getBarrier(); + } + + if (nullptr == barrier || nullptr == std::dynamic_pointer_cast(barrier)) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads using Middle Point search, we need a DMultiMadsBarrier."); + } + + if (evc->getCurrentEvalType() == NOMAD::EvalType::MODEL) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do Middle Point search for DMultiMads on EvalType::MODEL."); + } + + // Keep a reference to the DMultiMads barrier. + _ref_dmads_barrier = barrier; +} + +void NOMAD::DMultiMadsMiddlePointSearchMethod::generateTrialPointsFinal() +{ + preRunValidations(); + + const auto dMadsBarrier = std::dynamic_pointer_cast(_ref_dmads_barrier); + + // Get all the points available in the Pareto front approximation. + auto getCurrentParetoFrontApproximation = []( + const NOMAD::DMultiMadsBarrier &barrier) -> std::vector + { + if (barrier.getCurrentIncumbentFeas() != nullptr) + { + return barrier.getAllXFeas(); + } + else + { + return barrier.getAllXInf(); + } + }; + std::vector evalPointList = getCurrentParetoFrontApproximation(*dMadsBarrier); + + if (evalPointList.size() == 1) + { + OUTPUT_INFO_START + AddOutputInfo("Only one point in the set of solutions. Stop Middle Point search step."); + OUTPUT_INFO_END + + return; + } + + const auto currentFrameCenter = dMadsBarrier->getCurrentIncumbentFeas() != nullptr ? + dMadsBarrier->getCurrentIncumbentFeas() : dMadsBarrier->getCurrentIncumbentInf(); + + if (evalPointList.size() == 2) + { + OUTPUT_INFO_START + AddOutputInfo("Two points in the set of solutions. Take the middle point."); + OUTPUT_INFO_END + + NOMAD::Point xcandidate(*evalPointList[0]->getX() + *evalPointList[1]->getX()); + xcandidate /= 2.0; + + // Generate candidate: no need to check if it exists in cache. We are ready to pay + // the potential cache hit. + auto evalPoint = NOMAD::EvalPoint(xcandidate); + evalPoint.setPointFrom(std::make_shared(*currentFrameCenter), + NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); + evalPoint.addGenStep(getStepType()); + insertTrialPoint(evalPoint); + + return; + } + + // Obtain cache. + const auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + const bool useCache = evc->getUseCache(); + const NOMAD::ArrayOfDouble lb = getPbParams()->getAttributeValue("LOWER_BOUND"); + const NOMAD::ArrayOfDouble ub = getPbParams()->getAttributeValue("UPPER_BOUND"); + + const size_t nbMaxCacheSearchPerObj = getRunParams()->getAttributeValue("DMULTIMADS_MIDDLEPOINT_SEARCH_CACHE_MAX"); + + const size_t nbObj = dMadsBarrier->getNbObj(); + const NOMAD::FHComputeType initFHComputeType = dMadsBarrier->getFHComputeType(); + for (size_t obj = 0; obj < nbObj; ++obj) + { + std::sort(evalPointList.begin(), evalPointList.end(), + [&initFHComputeType, obj](const NOMAD::EvalPointPtr& ev1, const EvalPointPtr& ev2) -> bool + { + return ev1->getFs(initFHComputeType)[obj] < ev2->getFs(initFHComputeType)[obj]; + }); + + // Order points from largest to smallest gap according to the current objective. + std::vector> gapValues( + evalPointList.size() - 1); + for (size_t i = 0; i < evalPointList.size() - 1; ++i) + { + const auto& evPrev = evalPointList[i]; + const auto& evNext = evalPointList[i + 1]; + const NOMAD::Double curGap = evNext->getFs(initFHComputeType)[obj] - + evPrev->getFs(initFHComputeType)[obj]; + gapValues[i] = std::make_tuple(curGap, evPrev, evNext); + } + std::sort(gapValues.begin(), gapValues.end(), + [](const std::tuple &evt1, + const std::tuple &evt2) -> bool + { + return get<0>(evt1) > get<0>(evt2); + }); + + if (get<0>(gapValues[0]) == 0) + { + OUTPUT_INFO_START + AddOutputInfo("Maximal gap value for " + std::to_string(obj + 1) + " is zero: continue"); + OUTPUT_INFO_END + + continue; + } + + // Starting from the largest gap, try to compute a middle point + for (size_t i = 0; i < gapValues.size(); ++i) + { + if (i == nbMaxCacheSearchPerObj) + { + OUTPUT_INFO_START + std::string s = "Middle Point search has reached the maximum number of cache search trials allowed for objective f"; + s += std::to_string(obj + 1); + AddOutputInfo(s); + OUTPUT_INFO_END + break; + } + + const auto& gapElt = gapValues[i]; + const auto gapValue = get<0>(gapElt); + const auto evPrev = get<1>(gapElt); + const auto evNext = get<2>(gapElt); + + NOMAD::Point xcandidate(*evPrev->getX() + *evNext->getX()); + xcandidate /= 2.0; + + OUTPUT_INFO_START + AddOutputInfo("Middle Point search has generated the following point for objective f" + std::to_string(obj+1) + ":"); + std::string s = xcandidate.display(); + s += " from " + evPrev->getX()->display(); + s += " and " + evNext->getX()->display(); + s += " with gap in objective space " + gapValue.display(); + AddOutputInfo(s); + OUTPUT_INFO_END + + // Generate a middle point candidate + auto evalPoint = NOMAD::EvalPoint(xcandidate); + evalPoint.setPointFrom(std::make_shared(*currentFrameCenter), + NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); + evalPoint.addGenStep(getStepType()); + + snapPointToBoundsAndProjectOnMesh(evalPoint, lb, ub); + + // When there is no cache, no need to continue the procedure. + if (!useCache) + { + insertTrialPoint(evalPoint); + break; + } + + NOMAD::CacheInterface cacheInterface(this); + NOMAD::EvalPoint foundEvalPoint; + if (cacheInterface.find(*evalPoint.getX(), foundEvalPoint)) + { + OUTPUT_INFO_START + std::string s = "Middle point search candidate "; + s += evalPoint.getX()->display(); + s += " already in cache: continue"; + AddOutputInfo(s); + OUTPUT_INFO_END + continue; + } + + insertTrialPoint(evalPoint); + break; + } + } +} diff --git a/src/Algos/DMultiMads/DMultiMadsMiddlePointSearchMethod.hpp b/src/Algos/DMultiMads/DMultiMadsMiddlePointSearchMethod.hpp new file mode 100644 index 00000000..5af0d8ac --- /dev/null +++ b/src/Algos/DMultiMads/DMultiMadsMiddlePointSearchMethod.hpp @@ -0,0 +1,99 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#ifndef __NOMAD_4_5_DMULTIMADSMIDDLEPOINTSEARCHMETHOD__ +#define __NOMAD_4_5_DMULTIMADSMIDDLEPOINTSEARCHMETHOD__ + +#include "../../Algos/AlgoStopReasons.hpp" +#include "../../Algos/Mads/SearchMethodSimple.hpp" +#include "../../Algos/DMultiMads/DMultiMadsBarrier.hpp" + +#include "../../nomad_nsbegin.hpp" + +/// Middle point search method for DMultiMads +/** + The middle point search method consists in trying to fill gaps in the set of current solutions + by generating candidates in the (potentially) largest zones in the objective space. + */ +class DMultiMadsMiddlePointSearchMethod final : public SearchMethodSimple +{ +private: + std::shared_ptr _ref_dmads_barrier; + +public: + /// Constructor + /** + /param parentStep The parent of this search step -- \b IN. + */ + explicit DMultiMadsMiddlePointSearchMethod(const NOMAD::Step* parentStep) + : SearchMethodSimple(parentStep) + { + init(); + } + +private: + + /// Helper for constructor. + /** + Test if the DmultiMads Middle Point Search is enabled or not. Set the maximum number of tentatives to propose + points. + */ + void init(); + + /// Helper for generateTrialPoints + void preRunValidations(); + + /// Generate new points (no evaluation) + /** + \copydoc SearchMethodAlgo::generateTrialPointsFinal + The middle point search generates points to fill gaps in the current set of solutions. + */ + void generateTrialPointsFinal() override; +}; + +#include "../../nomad_nsend.hpp" + +#endif // __NOMAD_4_5_DMULTIMADSMIDDLEPOINTSEARCHMETHOD__ diff --git a/src/Algos/DMultiMads/DMultiMadsNMSearchMethod.cpp b/src/Algos/DMultiMads/DMultiMadsNMSearchMethod.cpp new file mode 100644 index 00000000..6a30bd0f --- /dev/null +++ b/src/Algos/DMultiMads/DMultiMadsNMSearchMethod.cpp @@ -0,0 +1,725 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#include "../../Cache/CacheBase.hpp" +#include "../../Algos/CacheInterface.hpp" +#include "../../Algos/DMultiMads/DMultiMadsBarrier.hpp" +#include "../../Algos/DMultiMads/DMultiMadsIteration.hpp" +#include "../../Algos/DMultiMads/DMultiMadsMegaIteration.hpp" +#include "../../Algos/DMultiMads/DMultiMadsNMSearchMethod.hpp" +#include "../../Algos/SubproblemManager.hpp" +#include "../../Eval/ProgressiveBarrier.hpp" +#include "../../Algos/EvcInterface.hpp" +#include "../../Algos/NelderMead/NMAllReflective.hpp" +#include "../../Type/DMultiMadsSearchStrategyType.hpp" + +void NOMAD::DMultiMadsNMSearchMethod::init() +{ + if (nullptr == getParentOfType()) + { + throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMadsNMSearch only works for DMultiMads"); + } + + const bool isEnabled = getRunParams()->getAttributeValue("NM_SEARCH"); + setEnabled(isEnabled); + + if (isEnabled) + { + // Set the lap counter + const auto nmFactor = _runParams->getAttributeValue("NM_SEARCH_MAX_TRIAL_PTS_NFACTOR"); + const auto dim = _pbParams->getAttributeValue("DIMENSION"); + if (nmFactor < NOMAD::INF_SIZE_T) + { + NOMAD::EvcInterface::getEvaluatorControl()->setLapMaxBbEval( dim*nmFactor ); + } + + // NM is an algorithm with its own stop reasons. + _nmStopReasons = std::make_shared>(); + + // Create the NM algorithm with its own stop reason + _nm = std::make_unique(this, + _nmStopReasons , + _runParams, + _pbParams); + + } + + setStepType(NOMAD::StepType::SEARCH_METHOD_NM); + + const auto nmStrategy = getRunParams()->getAttributeValue("DMULTIMADS_NM_STRATEGY"); + + _use_dom_strategy = nmStrategy == NOMAD::DMultiMadsNMSearchType::DOM; +} + +void NOMAD::DMultiMadsNMSearchMethod::preRunValidations() +{ + std::shared_ptr barrier = nullptr; + + const auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + _ref_compute_type = evc->getComputeType(); + + if (NOMAD::ComputeType::STANDARD != _ref_compute_type) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do NM search for DMultiMads on ComputeType other than STANDARD."); + } + + // Get barrier from upper MegaIteration, if available. + const auto megaIter = getParentOfType(false); + if (megaIter != nullptr) + { + barrier = megaIter->getBarrier(); + } + + if (nullptr == barrier || nullptr == std::dynamic_pointer_cast(barrier)) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads using NM search, we need a DMultiMadsBarrier."); + } + + if (evc->getCurrentEvalType() == NOMAD::EvalType::MODEL) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do NM search for DMultiMads on EvalType::MODEL."); + } + if (!evc->getUseCache()) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads using NM search, we need a cache."); + } + + // Keep a reference to the DMultiMads barrier. + _ref_dmads_barrier = barrier; + + // And to the compute type. + _ref_compute_type = evc->getComputeType(); +} + +bool NOMAD::DMultiMadsNMSearchMethod::runImp() +{ + // Basic checks before running Nelder-Mead search. + preRunValidations(); + + if (_use_dom_strategy) + { + OUTPUT_DEBUG_START + AddOutputDebug("Start DoM strategy"); + OUTPUT_DEBUG_END + + bool success = runDoMStrategy(); + return success; + } + + OUTPUT_DEBUG_START + AddOutputDebug("Start MultiMads strategy"); + OUTPUT_DEBUG_END + + bool success = runMultiMadsStrategy(); + return success; +} + +bool NOMAD::DMultiMadsNMSearchMethod::runDoMStrategy() +{ + auto dMadsBarrier = std::dynamic_pointer_cast(_ref_dmads_barrier); + + // Get current frame center + const auto currentFrameCenter = dMadsBarrier->getCurrentIncumbentFeas() != nullptr + ? dMadsBarrier->getCurrentIncumbentFeas() : dMadsBarrier->getCurrentIncumbentInf(); + + // Get all the points available in the Pareto front approximation. + auto getCurrentParetoFrontApproximation = [](const DMultiMadsBarrier& barrier) -> std::vector + { + if (barrier.getCurrentIncumbentFeas() != nullptr) + { + return barrier.getAllXFeas(); + } + else + { + return barrier.getAllXInf(); + } + }; + std::vector paretoElements = getCurrentParetoFrontApproximation(*dMadsBarrier); + + // Compute reference vector. + // It is a vector of size: + // (lk - 1) * nobj, if lk > 1; + // nobj otherwise + // where lk is the number of elements in the Pareto front approximation and nobj the number of objectives. + const size_t nbParetoElements = paretoElements.size(); + const size_t nbObj = dMadsBarrier->getNbObj(); + + OUTPUT_DEBUG_START + AddOutputDebug("Nb current Pareto elements: " + std::to_string(nbParetoElements)); + AddOutputDebug("Number of objectives: " + std::to_string(nbObj)); + AddOutputDebug("Current frame center is: " + currentFrameCenter->display()); + OUTPUT_DEBUG_END + + // NB: As this criterion is computationally intensive, we limit the use of NOMAD::Double + // and work directly with std::double. + std::vector ref; + ref.reserve(std::max((int)nbParetoElements - 1, 1) * nbObj); + + // It contains all elements of the Pareto front approximation minus the objective vector of the current frame + // center if the Pareto front approximation is not composed of 1 element + const FHComputeType& initFHComputeType = dMadsBarrier->getFHComputeType(); + if (nbParetoElements == 1) + { + const NOMAD::ArrayOfDouble& fvalues = currentFrameCenter->getFs(initFHComputeType); + for (size_t i = 0; i < nbObj; ++i) + { + const NOMAD::Double fi = fvalues[i]; + ref.push_back(fi.todouble()); + } + } + else + { + for (size_t j = 0; j < nbParetoElements; ++j) + { + const auto& paretoElt = paretoElements[j]; + if (currentFrameCenter == paretoElt) + { + continue; + } + const auto& fvalues = paretoElt->getFs(initFHComputeType); + for (size_t i = 0; i < nbObj; ++i) + { + ref.push_back(fvalues[i].todouble()); + } + } + } + + OUTPUT_DEBUG_START + // NB: The reference vector is costly to print + AddOutputDebug("Reference vector of dimensions " + std::to_string(ref.size() / nbObj) + " x " + std::to_string(nbObj)); + for (size_t j = 0; j < ref.size() / nbObj; ++j) + { + std::string s; + for (size_t i = 0; i < nbObj; ++i) + { + s += " " + std::to_string(ref[j * nbObj + i]); + } + AddOutputDebug(s); + } + OUTPUT_DEBUG_END + + + // We also allocate a vector that will contain the values of objective function. + // These values can be loaded in processor cache, allowing for faster calculus + std::vector fvalues(nbObj); + + // Compute single-objective function for NM. + NOMAD::singleOutputComputeFType singleObjCompute = [&ref, &fvalues, nbObj](const BBOutputTypeList& bbOutputTypeList, + const BBOutput& bbOutput) -> NOMAD::Double + { + if (!bbOutput.getEvalOk() || bbOutputTypeList.empty()) + { + return NOMAD::INF; + } + + if (!bbOutput.checkSizeMatch(bbOutputTypeList)) + { + return NOMAD::INF; + } + + const size_t nbParetoElements = ref.size() / nbObj; + + const auto& objValues = bbOutput.getObjectives(bbOutputTypeList); + for (int i = 0; i < nbObj; ++i) + { + fvalues[i] = objValues[i].todouble(); + } + + // The single-objective function is defined by: + // psi(x) = - min_{y in R} sum_{i = 1}^nbObj max(0, yi - fi(x)) if fi(x) is not dominated by any element + // of R + // min_{y in R} sum_{i = 1}^nbObj max(0, fi(x) - yi) otherwise. + + // First pass: detect if the point is dominated. + // Compute doMValue = - min_{y in R} sum_{i = 1}^nbObj max(0, yi - fi(x)) + double doMValue = NOMAD::INF; + for (size_t j = 0; j < nbParetoElements; ++j) + { + double curDoMValue = 0; + for (size_t i = 0; i < fvalues.size(); i++) + { + curDoMValue += std::max(0.0, ref[j * nbObj + i] - fvalues[i]); + } + doMValue = std::min(doMValue, curDoMValue); + + // In this case, the point is dominated by the element of R or equal. No need to continue. + if (doMValue == 0) + { + break; + } + } + + // The point is not dominated. + // NB: The use of NOMAD::Double here enables to have a higher threshold for the positiveness + // of this function than using std::double + if (NOMAD::Double(doMValue) > 0) + { + return -doMValue; + } + + // Second pass: return the minimum move to reach one of the elements of the Pareto front. + // Compute doMValue = min_{y in R} sum_{i = 1}^nbObj max(0, fi(x) - yi). + doMValue = NOMAD::INF; + for (size_t j = 0; j < nbParetoElements; ++j) + { + double curDoMValue = 0; + for (size_t i = 0; i < fvalues.size(); i++) + { + curDoMValue += std::max(0.0, fvalues[i] - ref[j * nbObj + i]); + } + doMValue = std::min(doMValue, curDoMValue); + // The point is equal to one of the points in the Pareto front. No need to continue + if (doMValue == 0) + { + break; + } + } + + return doMValue; + }; + + // Make the objective function available to the evaluator control. + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + evc->setComputeType(NOMAD::ComputeType::DMULTI_COMBINE_F, singleObjCompute); + + // Get all the points of the DMultiMads barrier + const std::vector evalPointList = _ref_dmads_barrier->getAllPoints(); + + // Create a new barrier for this NM launch: HMax is set to initial value of the DMultiMads barrier. + const auto hMax = dMadsBarrier->getHMax(); + + // Update with all the DMultiMads barrier points. + auto megaIter = getParentOfType(false); + // Update with all the DMultiMads barrier points. + megaIter->setBarrier(std::make_shared(hMax, + NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this), + evc->getCurrentEvalType(), + evc->getFHComputeTypeS(), + evalPointList)); + + _tagBefore = NOMAD::EvalPoint::getCurrentTag(); + + // Run Nelder-Mead search + NOMAD::NMSearchMethod::runImp(); + const bool successPostProcessing = postRunUpdates(); + + return successPostProcessing; +} + +bool NOMAD::DMultiMadsNMSearchMethod::runMultiMadsStrategy() +{ + auto dMadsBarrier = std::dynamic_pointer_cast(_ref_dmads_barrier); + + // Compute the reference vector in the objective space. + const auto ref = computeReferencePoint(*dMadsBarrier); + const size_t nbObj = dMadsBarrier->getNbObj(); + std::vector launchSingleObjectiveRuns(nbObj, false); + for (size_t obj = 0; obj < nbObj; ++obj) + { + launchSingleObjectiveRuns[obj] = !ref[obj].isDefined(); + } + const auto launchSingleObjRuns = std::any_of(launchSingleObjectiveRuns.cbegin(), + launchSingleObjectiveRuns.cend(), + [](bool b) {return b;}); + + bool success = false; + + // Two cases + // 1- The current incumbent is an extreme solution. Launch a single-objective Nelder-Mead step for each objective + // for which the current incumbent is an extreme solution. + if (launchSingleObjRuns) + { + for (size_t obj = 0; obj < nbObj; ++ obj) + { + if (launchSingleObjectiveRuns[obj]) + { + OUTPUT_DEBUG_START + AddOutputDebug("DMulti-MADS NM search: single-objective optimization launch for objective f" + std::to_string(obj + 1)); + OUTPUT_DEBUG_END + + const NOMAD::ArrayOfDouble refSingleObj(nbObj); + refSingleObj[obj] = 0; // Only the defined objective will be considered in the NM search + prepareSingleObjectiveRun(refSingleObj); + + // Launch NM search + NOMAD::NMSearchMethod::runImp(); + const bool successPostProcessing = postRunUpdates(); + success = successPostProcessing || success; + } + } + return success; + } + + // 2- The current incumbent is not an extreme solution. Launch a ``Multi-MADS'' search starting from the current + // incumbent using the reference vector. + OUTPUT_DEBUG_START + AddOutputDebug("DMulti-MADS NM search: reference point " + ref.display()); + OUTPUT_DEBUG_END + + prepareMultiMadsRun(ref); + NOMAD::NMSearchMethod::runImp(); + success = postRunUpdates(); + + return success; +} + +void NOMAD::DMultiMadsNMSearchMethod::prepareSingleObjectiveRun(const NOMAD::ArrayOfDouble& ref) +{ + // Get all the points of the DMultiMads barrier + const std::vector evalPointList = _ref_dmads_barrier->getAllPoints(); + + // Define the single-objective function for NM run. + NOMAD::singleOutputComputeFType singleObjCompute = [&ref](const BBOutputTypeList& bbOutputTypeList, + const BBOutput& bbOutput) -> NOMAD::Double + { + if (!bbOutput.getEvalOk() || bbOutputTypeList.empty()) + { + return NOMAD::INF; + } + + if (!bbOutput.checkSizeMatch(bbOutputTypeList)) + { + return NOMAD::INF; + } + + const auto& bbo = bbOutput.getBBOAsArrayOfDouble(); + + size_t j = 0; + for (size_t i = 0; i < bbo.size(); i++) + { + if (bbOutputTypeList[i].isObjective() && ref[j].isDefined()) + { + return bbo[i]; + } + if (bbOutputTypeList[i].isObjective()) + { + j++; + } + } + + // Normally, we should not go here. + return NOMAD::INF; + }; + + // Make the objective function available to the evaluator control. + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + evc->setComputeType(NOMAD::ComputeType::DMULTI_COMBINE_F, singleObjCompute); + + // Create a new barrier for this NM launch: HMax is set to initial value of the DMultiMads barrier. + const auto hMax = _ref_dmads_barrier->getHMax(); + + // Set the mega iter barrier to a ProgressiveBarrier with all the DMultiMads barrier points. + auto megaIter = getParentOfType(false); + megaIter->setBarrier(std::make_shared(hMax, + NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this), + evc->getCurrentEvalType(), + evc->getFHComputeTypeS(), + evalPointList)); + + _tagBefore = NOMAD::EvalPoint::getCurrentTag(); +} + +void NOMAD::DMultiMadsNMSearchMethod::prepareMultiMadsRun(const NOMAD::ArrayOfDouble &ref) +{ + // Get all the points of the DMultiMads barrier + const std::vector evalPointList = _ref_dmads_barrier->getAllPoints(); + const auto dMadsBarrier = std::dynamic_pointer_cast(_ref_dmads_barrier); + + NOMAD::singleOutputComputeFType singleObjCompute = [&ref](const BBOutputTypeList& bbOutputTypeList, + const BBOutput& bbOutput) -> NOMAD::Double + { + if (!bbOutput.getEvalOk() || bbOutputTypeList.empty()) + { + return NOMAD::INF; + } + + if (!bbOutput.checkSizeMatch(bbOutputTypeList)) + { + return NOMAD::INF; + } + + const auto& bbo = bbOutput.getBBOAsArrayOfDouble(); + const auto nbDominatedObj = [&]() -> size_t + { + size_t j = 0; + size_t nbDomObj = 0; + for (size_t i = 0; i < bbo.size(); ++i) + { + if (bbOutputTypeList[i].isObjective() && ref[j].isDefined()) + { + const NOMAD::Double& refValue = ref[j]; + const NOMAD::Double& fValue = bbo[i]; + // The objective component of f is dominated by the same objective component of ref + if (fValue >= refValue) + { + nbDomObj += 1; + } + j++; + } + } + return nbDomObj; + }(); // IIFE + + const size_t nbObj = getNbObj(bbOutputTypeList); + NOMAD::Double minDistDominated = NOMAD::INF; + NOMAD::Double minDistDominating = NOMAD::INF; + NOMAD::Double distRefF = 0; + bool isDominating = true; + size_t j = 0; + for (size_t i = 0; i < bbo.size(); i++) + { + if (bbOutputTypeList[i].isObjective() && ref[j].isDefined()) + { + const NOMAD::Double& refValue = ref[j]; + const NOMAD::Double& fValue = bbo[i]; + const NOMAD::Double refmf = (refValue - fValue) * (refValue - fValue); + if (fValue > refValue) + { + isDominating = false; + minDistDominated = std::min(minDistDominated, refmf); + } + else + { + minDistDominating = std::min(minDistDominating, refmf); + } + distRefF += refmf; + j++; + } + } + if (nbDominatedObj == nbObj) + { + // The objective vector is dominated by the reference point: + // return || ref - f(x) ||^2 + return distRefF; + } + + // The objective vector is not dominated by the reference point. Two cases can occur: + // * f(x) and ref are indifferent: return the distance between the dominance zone and f(x), + // i.e., min_{i in I} || ref - f(x) ||^2, where I = {i : fi(x) > ref[i]}. + // * f(x) is in the dominance zone: return the negative distance between the dominance zone and f(x), + // i.e., min || ref - f(x) ||^2. + const NOMAD::Double objValue = isDominating ? -minDistDominating : minDistDominated; + return objValue; + }; + + // Make the objective function available to the evaluator control. + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + evc->setComputeType(NOMAD::ComputeType::DMULTI_COMBINE_F, singleObjCompute); + + // Create a new barrier for this NM launch: HMax is set to initial value of the DMultiMads barrier. + const auto hMax = _ref_dmads_barrier->getHMax(); + + // Update with all the DMultiMads barrier points. + auto megaIter = getParentOfType(false); + megaIter->setBarrier(std::make_shared(hMax, + NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this), + evc->getCurrentEvalType(), + evc->getFHComputeTypeS(), + evalPointList)); + + _tagBefore = NOMAD::EvalPoint::getCurrentTag(); +} + +bool NOMAD::DMultiMadsNMSearchMethod::postRunUpdates() +{ + bool success = false; + + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + + // Get the progressive barrier temporarily stored into MegaIteration. + auto megaIter = getParentOfType(false); + const std::shared_ptr barrier = megaIter->getBarrier(); + if (nullptr == barrier || nullptr == std::dynamic_pointer_cast(barrier)) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads, after NM search, we should have a ProgressiveBarrier."); + } + + // Reset all DMULTI_COMBINE_F_VALUES in cache + if (NOMAD::CacheBase::getInstance() != nullptr) + { + NOMAD::CacheBase::getInstance()->processOnAllPoints( + [](EvalPoint& evp) + { + evp.resetDMultiCombineFValue(); + } + ); + evc->getBestIncumbent(-1)->resetDMultiCombineFValue(); + } + + // Collect all eval points generated by the NM search. + std::vector evalPointList; + if (_nm->getSuccessType() > NOMAD::SuccessType::NO_TRIALS) + { + const auto evalType = evc->getCurrentEvalType(); + std::function func = [&, evalType](const EvalPoint& evalPoint) -> bool + { + if(evalPoint.getTag() > (int)_tagBefore && evalPoint.isEvalOk(evalType)) + { + return true; + } + return false; + }; + + NOMAD::CacheInterface cacheInterface(this); + cacheInterface.find(func, evalPointList); + } + + // Set back the mega iteration barrier + megaIter->setBarrier(_ref_dmads_barrier); + + // Set back the STANDARD compute type for DMultiMads + evc->setComputeType(_ref_compute_type); + + const NOMAD::FHComputeType completeComputeType = {evc->getCurrentEvalType(), + evc->getFHComputeTypeS()}; + + auto megaIterSuccess = NOMAD::SuccessType::UNSUCCESSFUL; + // Set the mesh and determine successType + for (NOMAD::EvalPoint & ep: evalPointList) + { + ep.setMesh(megaIter->getMesh()); + + const auto epPtr = std::make_shared(ep); + if (megaIterSuccess != NOMAD::SuccessType::FULL_SUCCESS) + { + _ref_dmads_barrier->checkForFHComputeType(completeComputeType); + + if (ep.isFeasible(completeComputeType)) + { + megaIterSuccess = _ref_dmads_barrier->getSuccessTypeOfPoints(epPtr, nullptr); + } + else + { + megaIterSuccess = _ref_dmads_barrier->getSuccessTypeOfPoints(nullptr, epPtr); + } + } + } + + // Update the DMultiMads barrier with NM search points. + success = _ref_dmads_barrier->updateWithPoints(evalPointList); + setSuccessType(megaIterSuccess); + + return success; +} + +void NOMAD::DMultiMadsNMSearchMethod::generateTrialPointsFinal() +{ + throw NOMAD::Exception(__FILE__, __LINE__, "Not yet implemented"); +} + +NOMAD::ArrayOfDouble NOMAD::DMultiMadsNMSearchMethod::computeReferencePoint(const NOMAD::DMultiMadsBarrier& barrier) const +{ + // Get all the points available in the Pareto front approximation. + auto getCurrentParetoFrontApproximation = [](const DMultiMadsBarrier& barrier) -> std::vector + { + if (barrier.getCurrentIncumbentFeas() != nullptr) + { + return barrier.getAllXFeas(); + } + else + { + return barrier.getAllXInf(); + } + }; + std::vector evalPointList = getCurrentParetoFrontApproximation(barrier); + + const NOMAD::EvalPointPtr currentFrameCenter = barrier.getCurrentIncumbentFeas() != nullptr ? barrier.getCurrentIncumbentFeas() + : barrier.getCurrentIncumbentInf(); + + const size_t nbObj = barrier.getNbObj(); + const FHComputeType& initFHComputeType = barrier.getFHComputeType(); + if (evalPointList.size() == 1) + { + return NOMAD::ArrayOfDouble(nbObj); + } + + // When the ie coordinate of the reference point is not defined, it means the current frame incumbent + // is an extreme solution of the Pareto front for the current ie objective. + NOMAD::ArrayOfDouble ref(nbObj); + for (size_t obj = 0; obj < nbObj; ++obj) + { + std::sort(evalPointList.begin(), evalPointList.end(), + [&initFHComputeType, obj](const NOMAD::EvalPointPtr& ev1, const EvalPointPtr& ev2)->bool + { + return ev1->getFs(initFHComputeType)[obj] < ev2->getFs(initFHComputeType)[obj]; + }); + + // Get extreme values value according to one objective + NOMAD::Double fmin = evalPointList[0]->getFs(initFHComputeType)[obj]; + NOMAD::Double fmax = evalPointList[evalPointList.size()-1]->getFs(initFHComputeType)[obj]; + + // The current frame incumbent is an extreme solution for obj. + if (fmin == fmax) + { + continue; + } + + // Find the current frame center + size_t frameCenterId = 0; + for (size_t i = 0; i < evalPointList.size(); ++i) + { + if (currentFrameCenter == evalPointList[i]) + { + frameCenterId = i; + break; + } + } + + // The current frame incumbent is an extreme solution for obj. + if (frameCenterId == 0) + { + continue; + } + + // Compute the reference objective vector. When frameCenterId is the last element of the list, the + // reference vector takes the corresponding objective value. + const size_t nextFId = std::min(frameCenterId + 1, evalPointList.size() - 1); + const auto& nextF = evalPointList[nextFId]->getFs(initFHComputeType); + ref[obj] = nextF[obj]; + } + + return ref; +} diff --git a/src/Algos/DMultiMads/DMultiMadsNMSearchMethod.hpp b/src/Algos/DMultiMads/DMultiMadsNMSearchMethod.hpp new file mode 100644 index 00000000..cbce9eb7 --- /dev/null +++ b/src/Algos/DMultiMads/DMultiMadsNMSearchMethod.hpp @@ -0,0 +1,121 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#ifndef __NOMAD_4_5_DMULTIMADSNMSEARCHMETHOD__ +#define __NOMAD_4_5_DMULTIMADSNMSEARCHMETHOD__ + +#include "../../Algos/AlgoStopReasons.hpp" +#include "../../Algos/DMultiMads/DMultiMadsBarrier.hpp" +#include "../../Algos/Mads/NMSearchMethod.hpp" + +#include "../../nomad_nsbegin.hpp" + +/// Class to perform a Search method for DMultiMads using Nelder-Mead simplex algorithm. +/** + NM works only for single objective. We need to modify the multi objective problem + into a single objective problem before launching NM. Once NM is done the DMultiMads barrier + must be updated with the NM points. + The regular NMSearchMethod is disabled when running DMultiMads. + */ +class DMultiMadsNMSearchMethod final : public NMSearchMethod +{ +private: + size_t _tagBefore; // Use for finding NM trial points in cache + + std::shared_ptr _ref_dmads_barrier; + NOMAD::ComputeType _ref_compute_type; + + bool _use_dom_strategy; + +public: + /// Constructor + /** + /param parentStep The parent of this search step -- \b IN. + */ + explicit DMultiMadsNMSearchMethod(const Step* parentStep) + : NMSearchMethod(parentStep) + { + init(); + } + + virtual bool runImp() override; + +private: + + /// Helper for constructor. + /** + Test if the NM search is enabled or not. Set the maximum number of trial points. + */ + void init(); + + /// Generate new points (no evaluation) + /** + \copydoc SearchMethodAlgo::generateTrialPointsFinal + + Perform one iteration of all reflective steps (Reflect, Expansion, Inside and Outside Contraction). This is just portion of the NM algorithm without iteration. + */ + void generateTrialPointsFinal() override; + + // Helpers for runImp + void preRunValidations(); + + // MultiMads strategy + void prepareSingleObjectiveRun(const NOMAD::ArrayOfDouble& ref); + void prepareMultiMadsRun(const NOMAD::ArrayOfDouble& ref); + bool runMultiMadsStrategy(); + + // DoM strategy + bool runDoMStrategy(); + + bool postRunUpdates(); + NOMAD::ArrayOfDouble computeReferencePoint(const NOMAD::DMultiMadsBarrier& barrier) const; + +}; + +#include "../../nomad_nsend.hpp" + +#endif // __NOMAD_4_5_DMULTIMADSNMSEARCHMETHOD__ + diff --git a/src/Algos/DMultiMads/DMultiMadsQuadDMSSearchMethod.cpp b/src/Algos/DMultiMads/DMultiMadsQuadDMSSearchMethod.cpp new file mode 100644 index 00000000..45acd5b9 --- /dev/null +++ b/src/Algos/DMultiMads/DMultiMadsQuadDMSSearchMethod.cpp @@ -0,0 +1,547 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#include "../../Algos/QuadModel/QuadModelSinglePass.hpp" + +#include "../../Cache/CacheBase.hpp" +#include "../../Algos/CacheInterface.hpp" +#include "../../Algos/EvcInterface.hpp" +#include "../../Algos/DMultiMads/DMultiMadsBarrier.hpp" +#include "../../Algos/DMultiMads/DMultiMadsIteration.hpp" +#include "../../Algos/DMultiMads/DMultiMadsMegaIteration.hpp" +#include "../../Algos/DMultiMads/DMultiMadsQuadDMSSearchMethod.hpp" +#include "../../Algos/SubproblemManager.hpp" +#include "../../Eval/ProgressiveBarrier.hpp" +#include "../../Type/DMultiMadsSearchStrategyType.hpp" + + +void NOMAD::DMultiMadsQuadDMSSearchMethod::init() +{ + if (nullptr == getParentOfType()) + { + throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMadsQuadDMSSearch only works for DMultiMads"); + } + + const auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + _ref_compute_type = evc->getComputeType(); + + if (NOMAD::ComputeType::STANDARD != _ref_compute_type) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do Quad DMS search for DMultiMads on ComputeType other than STANDARD."); + } + + // Get barrier from upper MegaIteration, if available. + const auto megaIter = getParentOfType(false); + if (megaIter == nullptr) + { + throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMadsQuadDMSSearch should have a DMultiMads mega iteration parent."); + } + const std::shared_ptr barrier = megaIter->getBarrier(); + + if (nullptr == barrier || nullptr == std::dynamic_pointer_cast(barrier)) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads using Quad DMS search, we need a DMultiMadsBarrier."); + } + + // Number of objectives. This is used to select the objective combination to consider. + _m = std::dynamic_pointer_cast(barrier)->getNbObj(); + + // Temp for testing. Cheap unit test! + // testObjCombinations(); + + if (evc->getCurrentEvalType() == NOMAD::EvalType::MODEL) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do Quad DMS search for DMultiMads on EvalType::MODEL."); + } + if (!evc->getUseCache()) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads using QUAD DMS search, we need a cache."); + } + + setStepType(NOMAD::StepType::SEARCH_METHOD_DMULTIMADS_QUAD_DMS); + + const bool runQuadSearch = getRunParams()->getAttributeValue("QUAD_MODEL_SEARCH"); + const auto quadStrategy = getRunParams()->getAttributeValue("DMULTIMADS_QUAD_MODEL_STRATEGY"); + const bool isEnabled = runQuadSearch && quadStrategy == NOMAD::DMultiMadsQuadSearchType::DMS; + setEnabled(isEnabled); + + if (isEnabled && std::dynamic_pointer_cast(barrier)->getNbObj() >= 5) + { + throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMads Quad DMS search cannot be performed for 5 or more objectives."); + } + +#ifndef USE_SGTELIB + if (isEnabled()) + { + OUTPUT_INFO_START + AddOutputInfo(getName() + " cannot be performed because NOMAD is compiled without sgtelib library"); + OUTPUT_INFO_END + setEnabled(false); + } +#endif +} + +void NOMAD::DMultiMadsQuadDMSSearchMethod::preRun() +{ + // Initialize these parameters for objective combinations + _l = 0; + _activeObjsIndex.clear(); + _indices.clear(); + + std::shared_ptr barrier = nullptr; + + // Keep a reference to compute type. It will be modified in evc during quad model optim. + const auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + _ref_compute_type = evc->getComputeType(); + + if (NOMAD::ComputeType::STANDARD != _ref_compute_type) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do Quad DMS search for DMultiMads on ComputeType other than STANDARD."); + } + + // Get barrier from upper MegaIteration, if available. + const auto megaIter = getParentOfType(false); + if (megaIter != nullptr) + { + barrier = megaIter->getBarrier(); + } + + if (nullptr == barrier || nullptr == std::dynamic_pointer_cast(barrier)) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads using Quad DMS search, we need a DMultiMadsBarrier."); + } + + if (evc->getCurrentEvalType() == NOMAD::EvalType::MODEL) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do Quad DMS search for DMultiMads on EvalType::MODEL."); + } + if (!evc->getUseCache()) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads using Quad DMS search, we need a cache."); + } + + // Keep a reference to the DMultiMads barrier. + _ref_dmads_barrier = std::dynamic_pointer_cast(barrier); + + // Keep Pareto elements for the detection of the Quad DMS model search success + auto getCurrentParetoFrontApproximation = [](const DMultiMadsBarrier& barrier) -> std::vector + { + if (barrier.getCurrentIncumbentFeas() != nullptr) + { + return barrier.getAllXFeas(); + } + else + { + return barrier.getAllXInf(); + } + }; + _paretoElements.clear(); + _paretoElements = getCurrentParetoFrontApproximation(*_ref_dmads_barrier); +} + + +bool NOMAD::DMultiMadsQuadDMSSearchMethod::runImp() +{ + // Basic checks before running search. + preRun(); + + // Solve single-objective optimization subproblems by increasing levels + // of objective combinations. + size_t previousLevel = 0; + bool successLevel = false; + while (selectObjCombination() && !_stopReasons->checkTerminate()) + { + // We move to the next level of combinations + // Check if the search has reached a success for the previous level. + if (previousLevel < _l) + { + // No need to continue + if (successLevel) + break; + + // Move to the next level + previousLevel = _l; + } + + generateTrialPointOnSingleObjCombination(); + + evalTrialPoints(this); + + // From IterationUtils. Update megaIteration barrier. + const bool successCombination = postRunUpdates(); + successLevel = std::max(successCombination, successLevel); + } + + const bool success = (NOMAD::SuccessType::FULL_SUCCESS == getSuccessType()); + return success; +} + +void NOMAD::DMultiMadsQuadDMSSearchMethod::prepareSingleObjectiveRun() +{ + // Define the single-objective function for Quad DMS run. + NOMAD::singleOutputComputeFType singleObjCompute = [&](const BBOutputTypeList& bbOutputTypeList, + const BBOutput& bbOutput) -> NOMAD::Double + { + if (!bbOutput.getEvalOk() || bbOutputTypeList.empty()) + { + return NOMAD::INF; + } + + if (!bbOutput.checkSizeMatch(bbOutputTypeList)) + { + return NOMAD::INF; + } + + const auto& fvalues = bbOutput.getObjectives(bbOutputTypeList); + NOMAD::Double maxObjFun = NOMAD::M_INF; + for (size_t i = 0; i < fvalues.size(); i++) + { + if (std::any_of(_activeObjsIndex.begin(), _activeObjsIndex.end(), + [i](size_t j) + { + // Objective number starts at 1 in _activeObjsIndex + return j == i + 1; + })) + { + maxObjFun = max(maxObjFun, fvalues[i]); + } + } + + return maxObjFun; + }; + + // Make the objective function available to the evaluator control. + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + evc->setComputeType(NOMAD::ComputeType::DMULTI_COMBINE_F, singleObjCompute); +} + + +bool NOMAD::DMultiMadsQuadDMSSearchMethod::postRunUpdates() +{ + bool success = false; + + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + + // Set back the STANDARD compute type for DMultiMads + evc->setComputeType(_ref_compute_type); + + const NOMAD::FHComputeType completeComputeType = {evc->getCurrentEvalType(), + evc->getFHComputeTypeS()}; + + _ref_dmads_barrier->checkForFHComputeType(completeComputeType); + NOMAD::Double hMax = _ref_dmads_barrier->getHMax(); + + // Determine if the resolution of the subproblem has been a success. + for (auto& ep: _trialPoints) + { + // 0- The search has generated a point that is not eval ok + if (!ep.isEvalOk(completeComputeType.evalType)) + { + continue; + } + + + // 1- The search has generated an infeasible point and there exists a feasible set + // of current solutions. + if (!ep.isFeasible(completeComputeType) && _paretoElements[0]->isFeasible(completeComputeType)) + { + continue; + } + + // 2- The search has generated a feasible point, and there was no feasible point + // generated before: FULL_SUCCESS + if ((_ref_dmads_barrier->getCurrentIncumbentFeas() == nullptr) && + ep.isFeasible(completeComputeType)) + { + success = true; + break; + } + + // 3- Feasible case: check that ep is non-dominated. + if (ep.isFeasible(completeComputeType)) + { + bool isDominated = false; + for (const auto& pElt: _paretoElements) + { + const auto compFlag = pElt->compMO(ep, completeComputeType); + isDominated = (compFlag == NOMAD::CompareType::DOMINATING || + compFlag == NOMAD::CompareType::EQUAL); + if (isDominated) + { + break; + } + } + if (isDominated) + { + continue; + } + success = true; + break; + } + + // 3- Infeasible case: check that ep is non-dominated and below the current threshold. + if (ep.getH(completeComputeType) > hMax) + { + continue; + } + + bool isDominated = false; + for (const auto& pElt: _paretoElements) + { + const auto compFlag = pElt->compMO(ep, completeComputeType, true /*onlyfvalues*/); + isDominated = (compFlag == NOMAD::CompareType::DOMINATING) || + (compFlag == NOMAD::CompareType::EQUAL); + if (isDominated) + { + break; + } + } + if (!isDominated) + { + success = true; + break; + } + } + + // Determine success type according to DMultiMADS criterion + auto megaIterSuccess = getSuccessType(); + for (auto& ep: _trialPoints) + { + + // No need to continue; this step has already been marked as a success. + if (megaIterSuccess == NOMAD::SuccessType::FULL_SUCCESS) + { + break; + } + + // 0- The search has generated a point that is not eval ok + if (!ep.isEvalOk(completeComputeType.evalType)) + { + continue; + } + + const auto epPtr = std::make_shared(ep); + megaIterSuccess = ep.isFeasible(completeComputeType) ? _ref_dmads_barrier->getSuccessTypeOfPoints(epPtr, nullptr) + : _ref_dmads_barrier->getSuccessTypeOfPoints(nullptr, epPtr); + } + + // Transfer all points from _trialPoints list in evalPointList + std::vector evalPointList; + for (const auto& ep: _trialPoints) + { + evalPointList.push_back(ep); + } + _trialPoints.clear(); + + // Update the DMultiMads barrier with Quad DMS search points. + _ref_dmads_barrier->updateWithPoints(evalPointList); + + // Set the success type of the current iteration + setSuccessType(std::max(megaIterSuccess, getSuccessType())); + + return success; +} + +void NOMAD::DMultiMadsQuadDMSSearchMethod::generateTrialPointOnSingleObjCombination() +{ + OUTPUT_DEBUG_START + std::string s = "DMulti-MADS Quad DMS search: single-objective quadratic optimization launched "; + s += "for objectives combination ( "; + for (const auto ind: _activeObjsIndex) + { + s += "f" + std::to_string(ind) + " "; + } + s += ")"; + AddOutputDebug(s); + OUTPUT_DEBUG_END + + // Save the current frame incumbent. + auto dMadsBarrier = std::dynamic_pointer_cast(_ref_dmads_barrier); + const NOMAD::EvalPointPtr currentFrameCenter = dMadsBarrier->getCurrentIncumbentFeas() != nullptr + ? dMadsBarrier->getCurrentIncumbentFeas() + : dMadsBarrier->getCurrentIncumbentInf(); + + const auto megaIter = getParentOfType(false); + + // Define the objective function to use for quad model optimization. + prepareSingleObjectiveRun(); + + NOMAD::QuadModelSinglePass singlePass(this, currentFrameCenter, currentFrameCenter->getMesh(), + {} /* no scaling direction */, + true /* true: prior combine objs */); + + // Generate the trial points + singlePass.generateTrialPoints(); + + // Pass the generated trial pts to this + const auto& trialPtsSinglePass = singlePass.getTrialPoints(); + for (auto evalPoint : trialPtsSinglePass) + { + evalPoint.setPointFrom(currentFrameCenter, NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); + evalPoint.addGenStep(getStepType(), false /*do not inherit -> just qms step*/); + + evalPoint.setMesh(megaIter->getMesh()); + + if (snapPointToBoundsAndProjectOnMesh(evalPoint, _lb, _ub)) + { + evalPoint.addGenStep(getStepType()); + bool inserted = insertTrialPoint(evalPoint); + + OUTPUT_INFO_START + std::string s = "xt:"; + s += (inserted) ? " " : " not inserted: "; + s += evalPoint.display(); + AddOutputInfo(s); + OUTPUT_INFO_END + } + } +} + +void NOMAD::DMultiMadsQuadDMSSearchMethod::generateTrialPointsFinal() +{ + throw NOMAD::Exception(__FILE__, __LINE__, "Not yet implemented"); + +} + +bool NOMAD::DMultiMadsQuadDMSSearchMethod::changeLevelAndUpdateIndex() +{ + // Should we increment _l + // _index[0] cannot exceed _m - _l + if (_indices[0] + _l == _m) + { + // Combinations of max _m objectives + if (_l + 1 < _m) + { + // Start a new level of combinations + // Example _l = 1 (combination of two), _m = 4 + // Row 1 [1 2] [1 3] [1 4] + // Row 2 [2 3] [2 4] + // Row 3 [3 4] + // Row 3, i0 +_l = 3 + 1 = 4 + // Increment level: _l = 2 (combination of three objectives). + // Row 1, first combination [ 1 2 3] + _l++; + _indices.clear(); + for (size_t l = 1 ; l <= _l+1 ; l++) + { + _indices.push_back(l); + } + return true; + } + else + { + return false; + } + } + else + { + // Do not increment l, switch row + // Example _l = 1 (combination of two), _m = 4 + // [1 2] [1 3] [1 4] --> row one is done + // We need to do [2 3] [2 4] + size_t I0 = _indices[0]; + _indices.clear(); + for (size_t l = 1 ; l <= _l+1 ; l++) + { + _indices.push_back(l + I0); + } + return true; + } +} + +bool NOMAD::DMultiMadsQuadDMSSearchMethod::selectObjCombination() +{ + // Perform initialization. + if ( _indices.empty() ) + { + _indices.push_back(1); + _activeObjsIndex.push_back(1); + return true; + } + + // Next combination + bool selectWithSuccess = true; + if (_indices[_l] < _m) + { + // Example: _l = 1 (combinations of two), _m=4 + // Possible combinations of row 1: [1 2] [1 3] [1 4] + // If we have done [1 3] we can increment the last index: [1 4] + _indices[_l]++; + } + else + { + // An index has reached m. Switch row or done. + selectWithSuccess = changeLevelAndUpdateIndex(); + } + + _activeObjsIndex.clear(); + if (!selectWithSuccess) + { + return false; + } + + // Construct obj index + for (const auto i: _indices) + { + _activeObjsIndex.push_back(i); + } + return true; +} + + +void NOMAD::DMultiMadsQuadDMSSearchMethod::testObjCombinations() +{ + std::cout << "Objective combinations: "; + while (selectObjCombination()) + { + std::cout <<" [ "; + for(const auto i: _activeObjsIndex) + { + std::cout << i << " " ; + } + std::cout << " ] "; + } +} diff --git a/src/Algos/DMultiMads/DMultiMadsQuadDMSSearchMethod.hpp b/src/Algos/DMultiMads/DMultiMadsQuadDMSSearchMethod.hpp new file mode 100644 index 00000000..ca977d2e --- /dev/null +++ b/src/Algos/DMultiMads/DMultiMadsQuadDMSSearchMethod.hpp @@ -0,0 +1,126 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#ifndef __NOMAD_4_5_DMULTIMADSQUADDMSSEARCHMETHOD__ +#define __NOMAD_4_5_DMULTIMADSQUADDMSSEARCHMETHOD__ + +#include "../../Algos/AlgoStopReasons.hpp" +#include "../../Algos/DMultiMads/DMultiMadsBarrier.hpp" +#include "../../Algos/Mads/SearchMethodAlgo.hpp" + +#include "../../nomad_nsbegin.hpp" + +/// Class to perform a Search method for DMultiMads using Quad DMS algorithm. +/** + The Quad DMS algorithm solves a succession of single-objective optimization + subproblems. It first tries to minimize each objective component separately. + If the set of current Pareto solutions does not change, it keeps on going + with the minimization of the maximum of two objective components, unless it + modifies the current set of Pareto solutions or it has reached the maximum + number of objectives (min max fi(x)). + In the worst case, 2^m - 1 problems will be solved, where m is the number + of objectives of the original multiobjective problem, which can be costly + when the number of objectives is high. + */ +class DMultiMadsQuadDMSSearchMethod final : public SearchMethodAlgo +{ +private: + + std::shared_ptr _ref_dmads_barrier; + std::vector _paretoElements; ///< Current Pareto set of solutions + + ComputeType _ref_compute_type; + + std::list _activeObjsIndex; + size_t _l; // _l+1 is the current number of active objectives for combination (combination of two objs (_l=1), combination of three obj (_l=2)). + size_t _m; // Number of objectives + std::vector _indices; + +public: + /// Constructor + /** + /param parentStep The parent of this search step -- \b IN. + */ + explicit DMultiMadsQuadDMSSearchMethod(const Step* parentStep) + : SearchMethodAlgo(parentStep), + _m(0), + _l(0) + { + init(); + } + + virtual bool runImp() override; + + // Temp for testing obj combinations + void testObjCombinations(); + +private: + + /// Helper for constructor. + /** + Test if the Quad DMS search is enabled or not. Set the maximum number of trial points. + */ + void init(); + + /// Generate new points (no evaluation) + /** + \copydoc SearchMethodAlgo::generateTrialPointsFinal + */ + void generateTrialPointsFinal() override; + + // Helpers for runImp + void preRun(); + void prepareSingleObjectiveRun(); + bool postRunUpdates(); + bool selectObjCombination() ; + void generateTrialPointOnSingleObjCombination(); + bool changeLevelAndUpdateIndex(); + +}; + +#include "../../nomad_nsend.hpp" + +#endif // __NOMAD_4_5_DMULTIMADSQUADDMSSEARCHMETHOD__ diff --git a/src/Algos/DMultiMads/DMultiMadsQuadModSearchMethod.cpp b/src/Algos/DMultiMads/DMultiMadsQuadModSearchMethod.cpp new file mode 100644 index 00000000..91e6bb1b --- /dev/null +++ b/src/Algos/DMultiMads/DMultiMadsQuadModSearchMethod.cpp @@ -0,0 +1,601 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#include "../../Algos/QuadModel/QuadModelSinglePass.hpp" + +#include "../../Cache/CacheBase.hpp" +#include "../../Algos/CacheInterface.hpp" +#include "../../Algos/DMultiMads/DMultiMadsBarrier.hpp" +#include "../../Algos/DMultiMads/DMultiMadsMegaIteration.hpp" +#include "../../Algos/DMultiMads/DMultiMadsQuadModSearchMethod.hpp" +#include "../../Algos/SubproblemManager.hpp" +#include "../../Eval/ProgressiveBarrier.hpp" +#include "../../Algos/EvcInterface.hpp" +#include "../../Type/DMultiMadsSearchStrategyType.hpp" + +void NOMAD::DMultiMadsQuadModSearchMethod::init() +{ + if (nullptr == getParentOfType()) + { + throw NOMAD::Exception(__FILE__,__LINE__,"DMultiMadsQuadModSearch only works for DMultiMads"); + } + + const auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + _ref_compute_type = evc->getComputeType(); + + if (NOMAD::ComputeType::STANDARD != _ref_compute_type) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do Quad Model search for DMultiMads on ComputeType other than STANDARD."); + } + + // Get barrier from upper MegaIteration, if available. + const auto megaIter = getParentOfType(false); + std::shared_ptr barrier = nullptr; + if (megaIter != nullptr) + { + barrier = megaIter->getBarrier(); + } + + if (nullptr == barrier || nullptr == std::dynamic_pointer_cast(barrier)) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads using Quad Model search, we need a DMultiMadsBarrier."); + } + + if (evc->getCurrentEvalType() == NOMAD::EvalType::MODEL) + { + throw NOMAD::Exception(__FILE__,__LINE__,"Cannot do Quad Model search for DMultiMads on EvalType::MODEL."); + } + if (!evc->getUseCache()) + { + throw NOMAD::Exception(__FILE__,__LINE__,"For DMultiMads using Quad Model search, we need a cache."); + } + + setStepType(NOMAD::StepType::SEARCH_METHOD_QUAD_MODEL); + + const bool runQuadSearch = getRunParams()->getAttributeValue("QUAD_MODEL_SEARCH"); + const auto quadStrategy = getRunParams()->getAttributeValue("DMULTIMADS_QUAD_MODEL_STRATEGY"); + const bool isEnabled = runQuadSearch && + (quadStrategy == NOMAD::DMultiMadsQuadSearchType::DOM || + quadStrategy == NOMAD::DMultiMadsQuadSearchType::MULTI); + setEnabled(isEnabled); + + _flagPriorCombineObjsForModel = _runParams->getAttributeValue("DMULTIMADS_QMS_PRIOR_COMBINE_OBJ"); + _use_dom_strategy = quadStrategy == NOMAD::DMultiMadsQuadSearchType::DOM; +#ifndef USE_SGTELIB + if (isEnabled()) + { + OUTPUT_INFO_START + AddOutputInfo(getName() + " cannot be performed because NOMAD is compiled without sgtelib library"); + OUTPUT_INFO_END + setEnabled(false); + } +#endif +} + + +void NOMAD::DMultiMadsQuadModSearchMethod::prepareSingleObjectiveRun(const NOMAD::ArrayOfDouble& ref) +{ + // Define the single-objective function for quad model optimization run. + NOMAD::singleOutputComputeFType singleObjCompute = [&ref](const BBOutputTypeList& bbOutputTypeList, + const BBOutput& bbOutput) -> NOMAD::Double + { + if (!bbOutput.getEvalOk() || bbOutputTypeList.empty()) + { + return NOMAD::INF; + } + + if (!bbOutput.checkSizeMatch(bbOutputTypeList)) + { + return NOMAD::INF; + } + + const auto& bbo = bbOutput.getBBOAsArrayOfDouble(); + + size_t j = 0; + for (size_t i = 0; i < bbo.size(); i++) + { + if (bbOutputTypeList[i].isObjective() && ref[j].isDefined()) + { + return bbo[i]; + } + if (bbOutputTypeList[i].isObjective()) + { + j++; + } + } + + // Normally, we should not go here. + return NOMAD::INF; + }; + + // Make the objective function available to the evaluator control. + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + evc->setComputeType(NOMAD::ComputeType::DMULTI_COMBINE_F, singleObjCompute); +} + + +void NOMAD::DMultiMadsQuadModSearchMethod::prepareMultiMadsRun(const NOMAD::ArrayOfDouble &ref) +{ + NOMAD::singleOutputComputeFType singleObjCompute = [&ref](const BBOutputTypeList& bbOutputTypeList, + const BBOutput& bbOutput) -> NOMAD::Double + { + if (!bbOutput.getEvalOk() || bbOutputTypeList.empty()) + { + return NOMAD::INF; + } + + if (!bbOutput.checkSizeMatch(bbOutputTypeList)) + { + return NOMAD::INF; + } + + const auto& bbo = bbOutput.getBBOAsArrayOfDouble(); + const auto nbDominatedObj = [&]() -> size_t + { + size_t j = 0; + size_t nbDomObj = 0; + for (size_t i = 0; i < bbo.size(); ++i) + { + if (bbOutputTypeList[i].isObjective() && ref[j].isDefined()) + { + const NOMAD::Double& refValue = ref[j]; + const NOMAD::Double& fValue = bbo[i]; + // The objective component of f is dominated by the same objective component of ref + if (fValue >= refValue) + { + nbDomObj += 1; + } + j++; + } + } + return nbDomObj; + }(); // IIFE + + const size_t nbObj = getNbObj(bbOutputTypeList); + NOMAD::Double minDistDominated = NOMAD::INF; + NOMAD::Double minDistDominating = NOMAD::INF; + NOMAD::Double distRefF = 0; + bool isDominating = true; + size_t j = 0; + for (size_t i = 0; i < bbo.size(); i++) + { + if (bbOutputTypeList[i].isObjective() && ref[j].isDefined()) + { + const NOMAD::Double& refValue = ref[j]; + const NOMAD::Double& fValue = bbo[i]; + const NOMAD::Double refmf = (refValue - fValue) * (refValue - fValue); + if (fValue > refValue) + { + isDominating = false; + minDistDominated = std::min(minDistDominated, refmf); + } + else + { + minDistDominating = std::min(minDistDominating, refmf); + } + distRefF += refmf; + j++; + } + } + if (nbDominatedObj == nbObj) + { + // The objective vector is dominated by the reference point: + // return || ref - f(x) ||^2 + return distRefF; + } + + // The objective vector is not dominated by the reference point. Two cases can occur: + // * f(x) and ref are indifferent: return the distance between the dominance zone and f(x), + // i.e., min_{i in I} || ref - f(x) ||^2, where I = {i : fi(x) > ref[i]}. + // * f(x) is in the dominance zone: return the negative distance between the dominance zone and f(x), + // i.e., min || ref - f(x) ||^2. + const NOMAD::Double objValue = isDominating ? -minDistDominating : minDistDominated; + return objValue; + }; + + // Make the objective function available to the evaluator control. + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + evc->setComputeType(NOMAD::ComputeType::DMULTI_COMBINE_F, singleObjCompute); +} + + +void NOMAD::DMultiMadsQuadModSearchMethod::runMultiMadsStrategy() +{ + // Get the DMultiMads barrier. + auto megaIter = getParentOfType(false); + auto dMadsBarrier = std::dynamic_pointer_cast(megaIter->getBarrier()); + const NOMAD::EvalPointPtr currentFrameCenter = dMadsBarrier->getCurrentIncumbentFeas() != nullptr + ? dMadsBarrier->getCurrentIncumbentFeas() + : dMadsBarrier->getCurrentIncumbentInf(); + + + // Compute the reference vector in the objective space. + const auto ref = computeReferencePoint(*dMadsBarrier); + const size_t nbObj = dMadsBarrier->getNbObj(); + std::vector launchSingleObjectiveRuns(nbObj, false); + for (size_t obj = 0; obj < nbObj; ++obj) + { + launchSingleObjectiveRuns[obj] = !ref[obj].isDefined(); + } + const auto launchSingleObjRuns = std::any_of(launchSingleObjectiveRuns.cbegin(), + launchSingleObjectiveRuns.cend(), + [](bool b) {return b;}); + + // Two cases + if (launchSingleObjRuns) + { + // 1- The current incumbent is an extreme solution. Launch a single-objective Quad model search step for each objective + // for which the current incumbent is an extreme solution. + for (size_t obj = 0; obj < nbObj; ++ obj) + { + if (launchSingleObjectiveRuns[obj]) + { + OUTPUT_DEBUG_START + AddOutputDebug("DMulti-MADS Quad model search: single-objective optimization launch for objective f" + std::to_string(obj + 1)); + OUTPUT_DEBUG_END + + const NOMAD::ArrayOfDouble refSingleObj(nbObj); + refSingleObj[obj] = 0; // Only the defined objective will be considered in the quad model search + prepareSingleObjectiveRun(refSingleObj); + + NOMAD::QuadModelSinglePass singlePass(this, currentFrameCenter, currentFrameCenter->getMesh(), + {} /* no scaling direction */, _flagPriorCombineObjsForModel ); + + // Generate the trial points + singlePass.generateTrialPoints(); + + // Pass the generated trial pts to this + const auto& trialPtsSinglePass = singlePass.getTrialPoints(); + for (auto evalPoint : trialPtsSinglePass) + { + evalPoint.setPointFrom(currentFrameCenter, NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); + evalPoint.addGenStep(getStepType(), false /*do not inherit -> just qms step*/); + insertTrialPoint(evalPoint); + } + } + } + } + else + { + // 2- The current incumbent is not an extreme solution. Launch a quad model optimization search starting from the current + // incumbent using the reference vector to compute objective. + OUTPUT_DEBUG_START + AddOutputDebug("DMulti-MADS Quad Model search: reference point " + ref.display()); + OUTPUT_DEBUG_END + prepareMultiMadsRun(ref); + + NOMAD::QuadModelSinglePass singlePass(this, currentFrameCenter, currentFrameCenter->getMesh(),{} /* no scaling direction */,_flagPriorCombineObjsForModel); + + // Generate the trial points + singlePass.generateTrialPoints(); + + // Pass the generated trial pts to this + const auto& trialPtsSinglePassFeas = singlePass.getTrialPoints(); + for (auto evalPoint : trialPtsSinglePassFeas) + { + evalPoint.setPointFrom(currentFrameCenter, NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); + evalPoint.addGenStep(getStepType(), false /*do not inherit -> just qms step*/); + insertTrialPoint(evalPoint); + } + } + + // Set back the STANDARD compute type for DMultiMads + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + evc->setComputeType(_ref_compute_type); +} + + +void NOMAD::DMultiMadsQuadModSearchMethod::runDoMStrategy() +{ + // Get current barrier + auto megaIter = getParentOfType(false); + auto dMadsBarrier = std::dynamic_pointer_cast(megaIter->getBarrier()); + + // Get current frame center + const NOMAD::EvalPointPtr currentFrameCenter = dMadsBarrier->getCurrentIncumbentFeas() != nullptr + ? dMadsBarrier->getCurrentIncumbentFeas() + : dMadsBarrier->getCurrentIncumbentInf(); + + // Get all the points available in the Pareto front approximation. + auto getCurrentParetoFrontApproximation = [](const DMultiMadsBarrier& barrier) -> std::vector + { + if (barrier.getCurrentIncumbentFeas() != nullptr) + { + return barrier.getAllXFeas(); + } + else + { + return barrier.getAllXInf(); + } + }; + std::vector paretoElements = getCurrentParetoFrontApproximation(*dMadsBarrier); + + // Compute reference vector. + // It is a vector of size: + // (lk - 1) * nobj, if lk > 1; + // nobj otherwise + // where lk is the number of elements in the Pareto front approximation and nobj the number of objectives. + const size_t nbParetoElements = paretoElements.size(); + const size_t nbObj = dMadsBarrier->getNbObj(); + + OUTPUT_DEBUG_START + AddOutputDebug("Nb current Pareto elements: " + std::to_string(nbParetoElements)); + AddOutputDebug("Number of objectives: " + std::to_string(nbObj)); + AddOutputDebug("Current frame center is: " + currentFrameCenter->display()); + OUTPUT_DEBUG_END + + // NB: As this criterion is computationally intensive, we limit the use of NOMAD::Double + // and work directly with std::double. + std::vector ref; + ref.reserve(std::max((int)nbParetoElements - 1, 1) * nbObj); + + // It contains all elements of the Pareto front approximation minus the objective vector of the current frame + // center if the Pareto front approximation is not composed of 1 element + const FHComputeType& initFHComputeType = dMadsBarrier->getFHComputeType(); + if (nbParetoElements == 1) + { + const NOMAD::ArrayOfDouble& fvalues = currentFrameCenter->getFs(initFHComputeType); + for (size_t i = 0; i < nbObj; ++i) + { + const NOMAD::Double fi = fvalues[i]; + ref.push_back(fi.todouble()); + } + } + else + { + for (size_t j = 0; j < nbParetoElements; ++j) + { + const auto& paretoElt = paretoElements[j]; + if (currentFrameCenter == paretoElt) + { + continue; + } + const auto& fvalues = paretoElt->getFs(initFHComputeType); + for (size_t i = 0; i < nbObj; ++i) + { + ref.push_back(fvalues[i].todouble()); + } + } + } + + OUTPUT_DEBUG_START + // NB: The reference vector is costly to print + AddOutputDebug("Reference vector of dimensions " + std::to_string(ref.size() / nbObj) + " x " + std::to_string(nbObj)); + for (size_t j = 0; j < ref.size() / nbObj; ++j) + { + std::string s; + for (size_t i = 0; i < nbObj; ++i) + { + s += " " + std::to_string(ref[j * nbObj + i]); + } + AddOutputDebug(s); + } + OUTPUT_DEBUG_END + + // Compute single-objective function for Quad Model search. + NOMAD::singleOutputComputeFType singleObjCompute = [&ref, nbObj](const BBOutputTypeList& bbOutputTypeList, + const BBOutput& bbOutput) -> NOMAD::Double + { + if (!bbOutput.getEvalOk() || bbOutputTypeList.empty()) + { + return NOMAD::INF; + } + + if (!bbOutput.checkSizeMatch(bbOutputTypeList)) + { + return NOMAD::INF; + } + + const size_t nbParetoElements = ref.size() / nbObj; + + const auto& fvalues = bbOutput.getObjectives(bbOutputTypeList); + + // The single-objective function is defined by: + // psi(x) = - min_{y in R} sum_{i = 1}^nbObj max(0, yi - fi(x)) if fi(x) is not dominated by any element + // of R + // min_{y in R} sum_{i = 1}^nbObj max(0, fi(x) - yi) otherwise. + + // First pass: detect if the point is dominated. + // Compute doMValue = - min_{y in R} sum_{i = 1}^nbObj max(0, yi - fi(x)) + double doMValue = NOMAD::INF; + for (size_t j = 0; j < nbParetoElements; ++j) + { + double curDoMValue = 0; + for (size_t i = 0; i < fvalues.size(); i++) + { + curDoMValue += std::max(0.0, ref[j * nbObj + i] - fvalues[i].todouble()); + } + doMValue = std::min(doMValue, curDoMValue); + + // In this case, the point is dominated by the element of R or equal. No need to continue. + if (doMValue == 0) + { + break; + } + } + + // The point is not dominated. + // NB: The use of NOMAD::Double here enables to have a higher threshold for the positiveness + // of this function than using std::double + if (NOMAD::Double(doMValue) > 0) + { + return -doMValue; + } + + // Second pass: return the minimum move to reach one of the elements of the Pareto front. + // Compute doMValue = min_{y in R} sum_{i = 1}^nbObj max(0, fi(x) - yi). + doMValue = NOMAD::INF; + for (size_t j = 0; j < nbParetoElements; ++j) + { + double curDoMValue = 0; + for (size_t i = 0; i < fvalues.size(); i++) + { + curDoMValue += std::max(0.0, fvalues[i].todouble() - ref[j * nbObj + i]); + } + doMValue = std::min(doMValue, curDoMValue); + // The point is equal to one of the points in the Pareto front. No need to continue + if (doMValue == 0) + { + break; + } + } + + return doMValue; + }; + + // Make the objective function available to the evaluator control. + auto evc = NOMAD::EvcInterface::getEvaluatorControl(); + evc->setComputeType(NOMAD::ComputeType::DMULTI_COMBINE_F, singleObjCompute); + + // NB: Due to the computational cost of the objective function, we always combine the + // objective functions a priori to build the models before starting launching the quad model optimization. + NOMAD::QuadModelSinglePass singlePass(this, currentFrameCenter, currentFrameCenter->getMesh(), + {} /* no scaling direction */, + true /* combine at priory the objective functions for model*/); + + // Generate the trial points + singlePass.generateTrialPoints(); + + // Pass the generated trial pts to this + const auto& trialPtsSinglePassFeas = singlePass.getTrialPoints(); + for (auto evalPoint : trialPtsSinglePassFeas) + { + evalPoint.setPointFrom(currentFrameCenter, NOMAD::SubproblemManager::getInstance()->getSubFixedVariable(this)); + evalPoint.addGenStep(getStepType(), false /*do not inherit -> just qms step*/); + insertTrialPoint(evalPoint); + } + + // Set back the STANDARD compute type for DMultiMads + evc->setComputeType(_ref_compute_type); +} + + +void NOMAD::DMultiMadsQuadModSearchMethod::generateTrialPointsFinal() +{ + if (_use_dom_strategy) + { + runDoMStrategy(); + } + else + { + runMultiMadsStrategy(); + } +} + + +NOMAD::ArrayOfDouble NOMAD::DMultiMadsQuadModSearchMethod::computeReferencePoint(const NOMAD::DMultiMadsBarrier& barrier) const +{ + // Get all the points available in the Pareto front approximation. + auto getCurrentParetoFrontApproximation = [](const DMultiMadsBarrier& barrier) -> std::vector + { + if (barrier.getCurrentIncumbentFeas() != nullptr) + { + return barrier.getAllXFeas(); + } + else + { + return barrier.getAllXInf(); + } + }; + std::vector evalPointList = getCurrentParetoFrontApproximation(barrier); + + const NOMAD::EvalPointPtr currentFrameCenter = barrier.getCurrentIncumbentFeas() != nullptr ? barrier.getCurrentIncumbentFeas() + : barrier.getCurrentIncumbentInf(); + + const size_t nbObj = barrier.getNbObj(); + const FHComputeType& initFHComputeType = barrier.getFHComputeType(); + if (evalPointList.size() == 1) + { + return NOMAD::ArrayOfDouble(nbObj); + } + + // When the ie coordinate of the reference point is not defined, it means the current frame incumbent + // is an extreme solution of the Pareto front for the current ie objective. + NOMAD::ArrayOfDouble ref(nbObj); + for (size_t obj = 0; obj < nbObj; ++obj) + { + std::sort(evalPointList.begin(), evalPointList.end(), + [&initFHComputeType, obj](const NOMAD::EvalPointPtr& ev1, const EvalPointPtr& ev2)->bool + { + return ev1->getFs(initFHComputeType)[obj] < ev2->getFs(initFHComputeType)[obj]; + }); + + // Get extreme values value according to one objective + NOMAD::Double fmin = evalPointList[0]->getFs(initFHComputeType)[obj]; + NOMAD::Double fmax = evalPointList[evalPointList.size()-1]->getFs(initFHComputeType)[obj]; + + // The current frame incumbent is an extreme solution for obj. + if (fmin == fmax) + { + continue; + } + + // Find the current frame center + size_t frameCenterId = 0; + for (size_t i = 0; i < evalPointList.size(); ++i) + { + if (currentFrameCenter == evalPointList[i]) + { + frameCenterId = i; + break; + } + } + + // The current frame incumbent is an extreme solution for obj. + if (frameCenterId == 0) + { + continue; + } + + // Compute the reference objective vector. When frameCenterId is the last element of the list, the + // reference vector takes the corresponding objective value. + const size_t nextFId = std::min(frameCenterId + 1, evalPointList.size() - 1); + const auto nextF = evalPointList[nextFId]->getFs(initFHComputeType); + ref[obj] = nextF[obj]; + } + + return ref; +} diff --git a/src/Algos/DMultiMads/DMultiMadsQuadModSearchMethod.hpp b/src/Algos/DMultiMads/DMultiMadsQuadModSearchMethod.hpp new file mode 100644 index 00000000..1ca4a56d --- /dev/null +++ b/src/Algos/DMultiMads/DMultiMadsQuadModSearchMethod.hpp @@ -0,0 +1,120 @@ +/*---------------------------------------------------------------------------------*/ +/* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */ +/* */ +/* NOMAD - Version 4 has been created and developed by */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* The copyright of NOMAD - version 4 is owned by */ +/* Charles Audet - Polytechnique Montreal */ +/* Sebastien Le Digabel - Polytechnique Montreal */ +/* Viviane Rochon Montplaisir - Polytechnique Montreal */ +/* Christophe Tribes - Polytechnique Montreal */ +/* */ +/* NOMAD 4 has been funded by Rio Tinto, Hydro-Québec, Huawei-Canada, */ +/* NSERC (Natural Sciences and Engineering Research Council of Canada), */ +/* InnovÉÉ (Innovation en Énergie Électrique) and IVADO (The Institute */ +/* for Data Valorization) */ +/* */ +/* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */ +/* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */ +/* and Exxon Mobil. */ +/* */ +/* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */ +/* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */ +/* Exxon Mobil. */ +/* */ +/* Contact information: */ +/* Polytechnique Montreal - GERAD */ +/* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */ +/* e-mail: nomad@gerad.ca */ +/* */ +/* 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 . */ +/* */ +/* You can find information on the NOMAD software at www.gerad.ca/nomad */ +/*---------------------------------------------------------------------------------*/ +#ifndef __NOMAD_4_5_DMULTIMADSQUADMODSEARCHMETHOD__ +#define __NOMAD_4_5_DMULTIMADSQUADMODSEARCHMETHOD__ + +#include "../../Algos/AlgoStopReasons.hpp" +#include "../../Algos/DMultiMads/DMultiMadsBarrier.hpp" +#include "../../Algos/Mads/SearchMethodSimple.hpp" + + + +#include "../../nomad_nsbegin.hpp" + +/// Class to perform a Search method for DMultiMads using Quad model optimization algorithm. +/** + Quadratic model optimization works only for single objective. We need to modify the multi objective problem + into a single objective problem before launching quadratic model optimization. + Once quad model optim is done the DMultiMads barrier + must be updated with the new points. + The regular QuadModelSearchMethod is disabled when running DMultiMads. + */ +class DMultiMadsQuadModSearchMethod final : public SearchMethodSimple +{ +private: + + ComputeType _ref_compute_type; + + bool _flagPriorCombineObjsForModel; + + bool _use_dom_strategy; + +public: + /// Constructor + /** + /param parentStep The parent of this search step -- \b IN. + */ + explicit DMultiMadsQuadModSearchMethod(const Step* parentStep) + : SearchMethodSimple(parentStep) + { + init(); + } + +private: + + /// Helper for constructor. + /** + Test if the quad model search is enabled or not. + */ + void init(); + + /// Generate new points (no evaluation) + /** + \copydoc SearchMethodAlgo::generateTrialPointsFinal + + Perform one quad model optimization to produce trial points. + */ + virtual void generateTrialPointsFinal() override; + + // Helpers for generateTrialPoints + + // MultiMads strategy + void prepareSingleObjectiveRun(const NOMAD::ArrayOfDouble& ref); + void prepareMultiMadsRun(const NOMAD::ArrayOfDouble& ref); + void runMultiMadsStrategy(); + + // DoM strategy + void runDoMStrategy(); + + NOMAD::ArrayOfDouble computeReferencePoint(const NOMAD::DMultiMadsBarrier& barrier) const; + +}; + +#include "../../nomad_nsend.hpp" + +#endif // __NOMAD_4_5_DMULTIMADSQUADMODSEARCHMETHOD__ + diff --git a/src/Algos/DMultiMads/DMultiMadsUpdate.cpp b/src/Algos/DMultiMads/DMultiMadsUpdate.cpp index 1a942b86..0d76f1bb 100644 --- a/src/Algos/DMultiMads/DMultiMadsUpdate.cpp +++ b/src/Algos/DMultiMads/DMultiMadsUpdate.cpp @@ -64,56 +64,44 @@ std::string NOMAD::DMultiMadsUpdate::getName() const bool NOMAD::DMultiMadsUpdate::runImp() { - + std::string s; // Select the current incumbent (See Algo 4) // Two cases depending on previous iteration success: // - Success (full and partial success): select a possibly new incumbent point. // - Failure: decrease the mesh and select the current incumbent point - - auto evc = NOMAD::EvcInterface::getEvaluatorControl(); - NOMAD::EvalType evalType = NOMAD::EvalType::BB; - NOMAD::ComputeType computeType = NOMAD::ComputeType::STANDARD; - std::string s; // for output - if (nullptr != evc) + + // megaIter is already in subproblem. + // So no need to convert from full dimension to subproblem. + auto megaIter = getParentOfType(); + auto iter = getParentOfType(); + auto barrier = std::dynamic_pointer_cast(megaIter->getBarrier()); + + if (nullptr == barrier) { - evalType = evc->getCurrentEvalType(); - computeType = evc->getComputeType(); + throw NOMAD::Exception(__FILE__, __LINE__, "DMultiMadsUpdate: No barrier available"); } - if (NOMAD::EvalType::BB != evalType) + if (NOMAD::EvalType::BB != barrier->getEvalType()) { s = "DMultiMadsUpdate: Only BB eval type is handled"; - throw NOMAD::Exception(__FILE__, __LINE__, s); - } - if (NOMAD::ComputeType::STANDARD != computeType) + + if (NOMAD::ComputeType::STANDARD != barrier->getComputeType()) { s = "DMultiMadsUpdate: Only STANDARD compute type is handled"; throw NOMAD::Exception(__FILE__, __LINE__, s); - } - - // megaIter is already in subproblem. - // So no need to convert from full dimension to subproblem. - auto megaIter = getParentOfType(); - auto iter = getParentOfType(); - auto barrier = std::dynamic_pointer_cast(megaIter->getBarrier()); - + OUTPUT_DEBUG_START - s = "Running " + getName() + ". Barrier: "; + s = "Running " + getName(); AddOutputDebug(s); - std::vector vs = barrier->display(4); - for (const auto & si : vs) - { - AddOutputDebug(si); - } OUTPUT_DEBUG_END - + // If the previous iteration is not a success, the meshes of current incumbents are refined (no success). If not, the current incumbents may change. NOMAD::SuccessType previousSuccess = iter->getPreviousSuccessType(); // If previous success type is not a success (partial or full), reduce the mesh associated to the current frame center. - // The frame center can be set if it does not already exists (just after initialization) + // The frame center can be set if it does not already exist (just after initialization) if (previousSuccess < NOMAD::SuccessType::PARTIAL_SUCCESS) { OUTPUT_DEBUG_START @@ -125,12 +113,7 @@ bool NOMAD::DMultiMadsUpdate::runImp() if ( nullptr != iter->getFrameCenter()) { iter->getFrameCenter()->getMesh()->refineDeltaFrameSize(); - - // Need to update incumbents because mesh of one incumbent has changed. - barrier->updateCurrentIncumbents(); } - - } else { @@ -142,9 +125,21 @@ bool NOMAD::DMultiMadsUpdate::runImp() AddOutputDebug(s); OUTPUT_DEBUG_END } - - + OUTPUT_DEBUG_START + s = "Barrier: "; + AddOutputDebug(s); + std::vector vs = barrier->display(100, true); + for (const auto & si : vs) + { + AddOutputDebug(si); + } + OUTPUT_DEBUG_END + + // Before selecting new frame centers, update current incumbents. + barrier->updateCurrentIncumbents(); + + // Select frame center. Can change if iteration is successful or not. // Current incumbents may have changed because barrier is updated by adding points or by because the frame size of a barrier point has changed (see above). auto currentBestFeas = barrier->getCurrentIncumbentFeas(); diff --git a/src/Algos/DMultiMads/DMultiMadsUpdate.hpp b/src/Algos/DMultiMads/DMultiMadsUpdate.hpp index f8d4751a..bccab42a 100644 --- a/src/Algos/DMultiMads/DMultiMadsUpdate.hpp +++ b/src/Algos/DMultiMads/DMultiMadsUpdate.hpp @@ -44,8 +44,8 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_DMULTIMADSUPDATE__ -#define __NOMAD_4_4_DMULTIMADSUPDATE__ +#ifndef __NOMAD_4_5_DMULTIMADSUPDATE__ +#define __NOMAD_4_5_DMULTIMADSUPDATE__ #include "../../Algos/Step.hpp" @@ -94,4 +94,4 @@ class DMultiMadsUpdate: public Step #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_DMULTIMADSUPDATE__ +#endif // __NOMAD_4_5_DMULTIMADSUPDATE__ diff --git a/src/Algos/DiscoMads/DiscoMads.cpp b/src/Algos/DiscoMads/DiscoMads.cpp index 1c3e5072..ee9fcb5e 100644 --- a/src/Algos/DiscoMads/DiscoMads.cpp +++ b/src/Algos/DiscoMads/DiscoMads.cpp @@ -72,7 +72,7 @@ void NOMAD::DiscoMads::init(bool barrierInitializedFromCache) // -- Display discoMads parameters - bool detectHiddConst = _runParams->getAttributeValue("DISCO_MADS_HID_CONST"); // only for hidden constraints revealation + bool detectHiddConst = _runParams->getAttributeValue("DISCO_MADS_HID_CONST"); // only for hidden constraints revaluation if(detectHiddConst) { // use to reveal hidden constraints @@ -218,7 +218,7 @@ void NOMAD::DiscoMads::readInformationForHotRestart() { // Restart from where we were before. // For this, we need to read some files. - // Note: Cache file is treated independently from hot restart file. + // Note: Cache file is treated independently of hot restart file. if (_runParams->getAttributeValue("HOT_RESTART_READ_FILES")) { diff --git a/src/Algos/DiscoMads/DiscoMads.hpp b/src/Algos/DiscoMads/DiscoMads.hpp index de077224..9242ac8f 100644 --- a/src/Algos/DiscoMads/DiscoMads.hpp +++ b/src/Algos/DiscoMads/DiscoMads.hpp @@ -44,8 +44,8 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_DISCOMADS__ -#define __NOMAD_4_4_DISCOMADS__ +#ifndef __NOMAD_4_5_DISCOMADS__ +#define __NOMAD_4_5_DISCOMADS__ #include "../../Algos/Algorithm.hpp" #include "../../Algos/AlgoStopReasons.hpp" @@ -107,4 +107,4 @@ class DiscoMads: public Algorithm #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_DISCOMADS__ +#endif // __NOMAD_4_5_DISCOMADS__ diff --git a/src/Algos/DiscoMads/DiscoMadsBarrier.cpp b/src/Algos/DiscoMads/DiscoMadsBarrier.cpp index dab5dbb7..94467de9 100644 --- a/src/Algos/DiscoMads/DiscoMadsBarrier.cpp +++ b/src/Algos/DiscoMads/DiscoMadsBarrier.cpp @@ -67,12 +67,12 @@ bool NOMAD::DiscoMadsBarrier::proximityTest(const NOMAD::Point & x1, const NOMAD -const NOMAD::Double NOMAD::DiscoMadsBarrier::getKiemeHvalue(const std::vector& evalPointList, const size_t k, NOMAD::EvalType evalType) const +NOMAD::Double NOMAD::DiscoMadsBarrier::getKiemeHvalue(const std::vector& evalPointList, const size_t k) const { NOMAD::Double kiemeHValue = NaN; std::string s; // for info output - if (evalPointList.size() == 0) + if (evalPointList.empty()) { OUTPUT_INFO_START s = "Warning: DiscoMadsBarrier::getKiemeHvalue called on an empty evalPoints list"; @@ -84,32 +84,32 @@ const NOMAD::Double NOMAD::DiscoMadsBarrier::getKiemeHvalue(const std::vector hValues; - for(auto it:evalPointList) + for(const auto& it:evalPointList) { - hValues.push_back(it->getEval(evalType)->getH()); + hValues.push_back(it->getH(_computeType)); } if(evalPointList.size()!= hValues.size()) { - throw NOMAD::Exception(__FILE__, __LINE__, "Problem to compute k-ieme h value of the evalPoint list."); + throw NOMAD::Exception(__FILE__, __LINE__, "Problem to compute k-th h value of the evalPoint list."); } // Order points with increasing h values std::vector sortedEvalPointList = evalPointList; - std::sort(sortedEvalPointList.begin(), sortedEvalPointList.end(), [](const NOMAD::EvalPointPtr& x1,const NOMAD::EvalPointPtr& x2) { - return x1->getEval(NOMAD::EvalType::BB)->getH() < x2->getEval(NOMAD::EvalType::BB)->getH() ; + std::sort(sortedEvalPointList.begin(), sortedEvalPointList.end(), [this](const NOMAD::EvalPointPtr& x1,const NOMAD::EvalPointPtr& x2) { + return x1->getH(_computeType) < x2->getH(_computeType) ; }); - // Get k-ieme value - kiemeHValue = sortedEvalPointList.at(k-1)->getEval(NOMAD::EvalType::BB)->getH(); + // Get k-th value + kiemeHValue = sortedEvalPointList.at(k-1)->getH(_computeType); OUTPUT_DEBUG_START s = "List of evalPoints sorted with increasing h values: \n "; - for(auto point: sortedEvalPointList) + for(const auto& point: sortedEvalPointList) { s +=point->display()+"\n"; } NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); - s = "h-value of k-ieme point (k= "+std::to_string(k) +"): "+kiemeHValue.tostring(); + s = "h-value of k-th point (k= "+std::to_string(k) +"): "+kiemeHValue.tostring(); NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); NOMAD::OutputQueue::Flush(); OUTPUT_DEBUG_END @@ -118,17 +118,17 @@ const NOMAD::Double NOMAD::DiscoMadsBarrier::getKiemeHvalue(const std::vector &evalPointList,const NOMAD::EvalType evalType,const NOMAD::ComputeType computeType) +size_t NOMAD::DiscoMadsBarrier::getNonDominatedInfPoints(std::vector &evalPointList) { evalPointList.clear(); - if (_xInf.size()> 0) + if (!_xInf.empty()) { std::vector::const_iterator it1= _xInf.begin(), it2; while ( it1 !=_xInf.end() ) { // Do not consider points with h>hMax - if ((*it1)->getEval(evalType)->getH(computeType) > _hMax) + if ((*it1)->getH(_computeType) > _hMax) { continue; } @@ -142,7 +142,7 @@ const size_t NOMAD::DiscoMadsBarrier::getNonDominatedInfPoints(std::vector ep1 is dominated - if ((*it2)->dominates(*(*it1), evalType, computeType)) + if ((*it2)->dominates(*(*it1),_computeType)) { isDominated = true; break; @@ -158,24 +158,16 @@ const size_t NOMAD::DiscoMadsBarrier::getNonDominatedInfPoints(std::vector& evalPointList, - NOMAD::EvalType evalType, - NOMAD::ComputeType computeType, - const bool keepAllPoints /* Not used here */, - const bool updateIncumbentsAndHmax ) + const bool keepAllPoints /* Not used here */, + const bool updateIncumbentsAndHmax ) { - // Just in case - if(evalType==NOMAD::EvalType::MODEL) - { - throw NOMAD::Exception(__FILE__, __LINE__, "DiscoMAdsBarrier:: shoudl not be used on quadratic model optimization because it may be very slow."); - } - bool updatedInc = false; bool revealingIteration = false; string s; // for output @@ -186,12 +178,12 @@ bool NOMAD::DiscoMadsBarrier::updateWithPoints(const std::vectorfind(crittestNewRevealing,newRevealingPoints); - if (newRevealingPoints.size()>0){ + if (!newRevealingPoints.empty()){ revealingIteration=true; OUTPUT_DEBUG_START s = "Iteration is revealing; tags of "+ std::to_string(newRevealingPoints.size()) +" new revealing points seen by the DiscoMadsBarrier: "; - for(auto point: newRevealingPoints) + for(const auto& point: newRevealingPoints) { s+= std::to_string(point.getTag())+" "; } @@ -204,7 +196,7 @@ bool NOMAD::DiscoMadsBarrier::updateWithPoints(const std::vector nonDomInfPtsBelowHmaxBeforeUpdate; - nbNonDomInfPtsBelowHmaxBeforeUpdate = getNonDominatedInfPoints(nonDomInfPtsBelowHmaxBeforeUpdate, evalType, computeType); + nbNonDomInfPtsBelowHmaxBeforeUpdate = getNonDominatedInfPoints(nonDomInfPtsBelowHmaxBeforeUpdate); // --- Step 2 : update RPB constraints considering revealed information for (auto & revealingPoint : newRevealingPoints) {// For each new revealing point... // set revealed constraint to 1.0 (only the constraint of the current evaluated point was updated in callbackCheckIfRevealingAndUpdate) - const NOMAD::Double valeur=revealingPoint.getRevealedConstraint(); revealingPoint.setRevealedConstraint(1.0); // reset revealing status to 1 @@ -233,7 +224,7 @@ bool NOMAD::DiscoMadsBarrier::updateWithPoints(const std::vector nonDomInfPoints; // U^{k+1} in paper - nbNonDomInfPts = getNonDominatedInfPoints(nonDomInfPoints, evalType, computeType); // no points discarded as hmax = Inf + nbNonDomInfPts = getNonDominatedInfPoints(nonDomInfPoints); // no points discarded as hmax = Inf // determine number of infeasible points to keep in the barrier (p. 1850 of paper) // H1 : faire test unitaire sur ça size_t nbInfPointsToKeep; // N(k+,h(bar(x))) in paper @@ -316,7 +307,7 @@ bool NOMAD::DiscoMadsBarrier::updateWithPoints(const std::vector bestFeasPoints; @@ -363,8 +354,6 @@ bool NOMAD::DiscoMadsBarrier::updateWithPoints(const std::vector& evalPointList = std::vector(), bool barrierInitializedFromCache= true, const Double& exclusionRadius=1.0) @@ -77,6 +77,12 @@ class DiscoMadsBarrier : public ProgressiveBarrier barrierInitializedFromCache) { _exclusionRadius = exclusionRadius; + + // Just in case + if(_computeType.evalType == NOMAD::EvalType::MODEL) + { + throw NOMAD::Exception(__FILE__, __LINE__, "DiscoMAdsBarrier:: should not be used on quadratic model optimization."); + } } DiscoMadsBarrier(const DiscoMadsBarrier & b): ProgressiveBarrier(b) @@ -91,15 +97,13 @@ class DiscoMadsBarrier : public ProgressiveBarrier /// Update xFeas and xInf according to given points. // H1 corriger commentaire /* \param evalPointList vector of EvalPoints -- \b IN. - * \param keepAllPoints flag to keep all points \b IN. + * \param keepAllPoints flag -- \b IN. * \return true if the barrier feasible and/or infeasible incumbents are changed, false otherwise * \note Input EvalPoints are already in subproblem dimension */ virtual bool updateWithPoints(const std::vector& evalPointList, - EvalType evalType, - ComputeType computeType, - const bool keepAllPoints = false, - const bool updateInfeasibleIncumbentAndHmax = false ) override; + const bool keepAllPoints = false, + const bool updateInfeasibleIncumbentAndHmax = false ) override; private: /** Helper for updateWithPoints @@ -108,21 +112,19 @@ class DiscoMadsBarrier : public ProgressiveBarrier bool proximityTest(const NOMAD::Point & x1, const NOMAD::EvalPoint & x2); /** Helper for updateWithPoints - * Get the h-value of the k-ieme point of a list of points sorted with increasing h values + * Get the h-value of the k-th point of a list of points sorted with increasing h values */ - const NOMAD::Double getKiemeHvalue(const std::vector& evalPointList, const size_t k, NOMAD::EvalType evalType) const; + NOMAD::Double getKiemeHvalue(const std::vector& evalPointList, const size_t k) const; /** Helper for updateWithPoints * Get non dominated points with h<= hmax from barrier infeasible points and return number of points \param evalPointList vector of non dominated infeasible points with h<= hmax -- \b OUT. - \param evalType Which eval of the EvalPoint to look at -- \b IN. - \param computeType Which compute type of the EvalPoint to look at -- \b IN. \return The number of eval points found. */ - const size_t getNonDominatedInfPoints(std::vector& evalPointList,const EvalType evalType,const ComputeType computeType); + size_t getNonDominatedInfPoints(std::vector& evalPointList); }; #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_DISCOMADSBARRIER__ +#endif // __NOMAD_4_5_DISCOMADSBARRIER__ diff --git a/src/Algos/DiscoMads/DiscoMadsIteration.cpp b/src/Algos/DiscoMads/DiscoMadsIteration.cpp index 4c99d5e1..5bae6b69 100644 --- a/src/Algos/DiscoMads/DiscoMadsIteration.cpp +++ b/src/Algos/DiscoMads/DiscoMadsIteration.cpp @@ -57,12 +57,12 @@ void NOMAD::DiscoMadsIteration::init() { - // Initiliaze revealing poll for discoMads - // For some testing, it is possible that _runParams is null - if (nullptr == _runParams || !_runParams->getAttributeValue("MEGA_SEARCH_POLL")) - { - _revealingPoll = std::make_unique(this); - } + // Initialize revealing poll for discoMads + // For some testing, it is possible that _runParams is null + if (nullptr == _runParams || !_runParams->getAttributeValue("MEGA_SEARCH_POLL")) + { + _revealingPoll = std::make_unique(this); + } } diff --git a/src/Algos/DiscoMads/DiscoMadsIteration.hpp b/src/Algos/DiscoMads/DiscoMadsIteration.hpp index 35b2574b..6e0d4345 100644 --- a/src/Algos/DiscoMads/DiscoMadsIteration.hpp +++ b/src/Algos/DiscoMads/DiscoMadsIteration.hpp @@ -44,8 +44,8 @@ /* */ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ -#ifndef __NOMAD_4_4_DISCOMADSITERATION__ -#define __NOMAD_4_4_DISCOMADSITERATION__ +#ifndef __NOMAD_4_5_DISCOMADSITERATION__ +#define __NOMAD_4_5_DISCOMADSITERATION__ #include "../../Algos/Mads/MadsIteration.hpp" @@ -87,7 +87,7 @@ class DiscoMadsIteration: public NOMAD::MadsIteration /// Implementation of the run tasks of DiscoMADS algorithm. /** Run a DiscoMads iteration: a Search step followed by a Revealing Poll step followed by a Poll step, depending on the stop reasons and successes. - If a revealation occurs, the current iteration is immediately terminated (all remaining evaluations are cancelled) + If a revelation occurs, the current iteration is immediately terminated (all remaining evaluations are cancelled) */ virtual bool runImp() override; @@ -95,4 +95,4 @@ class DiscoMadsIteration: public NOMAD::MadsIteration #include "../../nomad_nsend.hpp" -#endif // __NOMAD_4_4_DISCOMADSITERATION__ +#endif // __NOMAD_4_5_DISCOMADSITERATION__ diff --git a/src/Algos/DiscoMads/DiscoMadsMegaIteration.cpp b/src/Algos/DiscoMads/DiscoMadsMegaIteration.cpp index 84f7fcf9..b073726e 100644 --- a/src/Algos/DiscoMads/DiscoMadsMegaIteration.cpp +++ b/src/Algos/DiscoMads/DiscoMadsMegaIteration.cpp @@ -45,7 +45,6 @@ /* You can find information on the NOMAD software at www.gerad.ca/nomad */ /*---------------------------------------------------------------------------------*/ - #include "../../Algos/EvcInterface.hpp" #include "../../Algos/SubproblemManager.hpp" #include "../../Algos/DiscoMads/DiscoMads.hpp" @@ -59,8 +58,9 @@ #include "../../Cache/CacheSet.hpp" -bool NOMAD::DiscoMadsMegaIteration::discontinuityTest(const NOMAD::EvalPoint & x1, const NOMAD::EvalPoint & x2){ - // Retur True if (x1,x2) is a weak discontinuity is detected between x1 and x2 (called in evaluator callback) +bool NOMAD::DiscoMadsMegaIteration::discontinuityTest(const NOMAD::EvalPoint & x1, const NOMAD::EvalPoint & x2) +{ + // Return True if (x1,x2) is a weak discontinuity is detected between x1 and x2 (called in evaluator callback) bool critvalue=false; // Do not compute criteria if the two points are equal as distance will be zero @@ -73,7 +73,7 @@ bool NOMAD::DiscoMadsMegaIteration::discontinuityTest(const NOMAD::EvalPoint & x // If both points are correctly evaluated... if(x1.getEvalStatus(NOMAD::EvalType::BB)== NOMAD::EvalStatusType::EVAL_OK && x2.getEvalStatus(NOMAD::EvalType::BB)== NOMAD::EvalStatusType::EVAL_OK) - { + { //As this function is used in eval callback, we use "Add" instead of "AddOutputInfo" to avoid segmentation faults as callback may be called deep in code OUTPUT_DEBUGDEBUG_START std::string s = "Test if revelation between points "+ std::to_string(x1.getTag()) + " and "+ std::to_string(x2.getTag()); @@ -86,17 +86,17 @@ bool NOMAD::DiscoMadsMegaIteration::discontinuityTest(const NOMAD::EvalPoint & x // Check for numerical problem if(d==0) { - OUTPUT_DEBUG_START + OUTPUT_DEBUG_START std::string s = "Warning: DiscoMadsMegaIteration:: Revelation:: distance between tested points is null."; NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); NOMAD::OutputQueue::Flush(); - OUTPUT_DEBUG_END - throw NOMAD::Exception(__FILE__,__LINE__,"Numerical precision problem"); + OUTPUT_DEBUG_END + throw NOMAD::Exception(__FILE__,__LINE__,"Numerical precision problem"); } // Revelation if distance between x1 and x2 < detectionRadius and rate of change of at least one revealing output exceeds the limit rate - if (d < _detectionRadius) - { + if (d < _detectionRadius) + { auto arrayOutputx1 = x1.getEval(NOMAD::EvalType::BB)->getBBOutput().getBBOAsArrayOfDouble(); // BB output X1 auto arrayOutputx2 = x2.getEval(NOMAD::EvalType::BB)->getBBOutput().getBBOAsArrayOfDouble(); // BB output x1 @@ -113,10 +113,10 @@ bool NOMAD::DiscoMadsMegaIteration::discontinuityTest(const NOMAD::EvalPoint & x NOMAD::OutputQueue::Flush(); OUTPUT_DEBUGDEBUG_END } - } + } } - } - return critvalue; + } + return critvalue; } @@ -127,15 +127,13 @@ bool NOMAD::DiscoMadsMegaIteration::proximityTestOnRevealingPoint(const NOMAD::P // check first if point x2 is revealing if (x2.getEvalStatus(NOMAD::EvalType::BB)==NOMAD::EvalStatusType::EVAL_OK && x2.getRevealingStatus()>0) { - // then compute distance + // then compute distance NOMAD::Double d=NOMAD::Point::dist(x1,x2); // distance between 2 points if(d< _exclusionRadius) { critvalue=true; } - } - - //TODO: could be optimized by keeping track of a distance matrix for the whole run + } return critvalue; } @@ -146,19 +144,19 @@ void NOMAD::DiscoMadsMegaIteration::callbackCheckIfRevealingAndUpdate(NOMAD::Eva std::string s; //for display - // If evalQueuePoint was a MODEL or SURROGATE eval, it is useless to check for revealation as no new information on BB output is known + // If evalQueuePoint was a MODEL or SURROGATE eval, it is useless to check for revelation as no new information on BB output is known if(evalQueuePoint->getEvalType()==NOMAD::EvalType::BB) { - // Callback is called even after failed eval, discard treatment in this case //TODO: voir avec C.T. si on ne ferait pas plutôt le RunEvalCallback dans evalblock seulement si eval correcte + // Callback is called even after failed eval, discard treatment in this case if(!evalQueuePoint->isEvalOk(NOMAD::EvalType::BB)) { return; } - // Point violating EB constraints cannot be revealing + // Point violating EB constraints cannot be revealing if(!evalQueuePoint->isEBOk(NOMAD::EvalType::BB)) - { + { OUTPUT_DEBUG_START s = std::to_string(evalQueuePoint->getTag())+" is not a revealing point (violates at least one EB constraint)."; NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); @@ -168,14 +166,14 @@ void NOMAD::DiscoMadsMegaIteration::callbackCheckIfRevealingAndUpdate(NOMAD::Eva } auto cache = CacheBase::getInstance().get(); - std::vector revealingPointList; + std::vector revealingPointList; // 1) Try to reveal either hidden constraints or discontinuity // Reveal hidden constraints if(_detectHiddConst) { if(evalQueuePoint->getRevealingStatus()==2){ - evalQueuePoint->setRevealedConstraint(1.0); + evalQueuePoint->setRevealedConstraint(1.0); cache->update(*evalQueuePoint,NOMAD::EvalType::BB); // update revealing status and revealed constraint revealingPointList.push_back(*evalQueuePoint); } @@ -187,9 +185,9 @@ void NOMAD::DiscoMadsMegaIteration::callbackCheckIfRevealingAndUpdate(NOMAD::Eva cache->find(crittest,revealingPointList); // NB: revealingPointList does not contain evalQueuePoint // If we have detected at least one revealing point thanks to evalQueuePoint... - if(revealingPointList.size()>0) - { - // ...then evalQueuePoint is a new revealing point and shoul be updated + if(!revealingPointList.empty()) + { + // ...then evalQueuePoint is a new revealing point and should be updated OUTPUT_DEBUG_START // NOTE: safer to use "Add" instead of "AddOutputInfo" in callback to avoid segmentation faults when accessing step name s = std::to_string(evalQueuePoint->getTag())+" is a revealing point."; NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); @@ -197,17 +195,17 @@ void NOMAD::DiscoMadsMegaIteration::callbackCheckIfRevealingAndUpdate(NOMAD::Eva OUTPUT_DEBUG_END evalQueuePoint->setRevealingStatus(2); // set to 2 to indicate that the point was found revealing at this iteration - evalQueuePoint->setRevealedConstraint(1.0); + evalQueuePoint->setRevealedConstraint(1.0); cache->update(*evalQueuePoint,NOMAD::EvalType::BB); // update revealing status and revealed constraint // update revealing status of other new revealing points (their revealed constraints are set in DiscoMadsBarrier) for(auto evalPoint : revealingPointList) - { + { if(evalPoint.getRevealingStatus()==0) // discard revealing points already known (with status ==1) { - evalPoint.setRevealingStatus(2); + evalPoint.setRevealingStatus(2); cache->update(evalPoint,NOMAD::EvalType::BB); // update only revealing status - // DEV : va poser problème avec le parallelisme + // DEV : va poser problème avec le parallelisme } } @@ -219,33 +217,33 @@ void NOMAD::DiscoMadsMegaIteration::callbackCheckIfRevealingAndUpdate(NOMAD::Eva // 2) If evalQueuePoint is not a revealing point, we check if it is close to revealing points - if(revealingPointList.size()==0){ + if(revealingPointList.empty()){ OUTPUT_DEBUG_START - std::string s = std::to_string(evalQueuePoint->getTag())+" is not a revealing point."; + s = std::to_string(evalQueuePoint->getTag())+" is not a revealing point."; NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); NOMAD::OutputQueue::Flush(); OUTPUT_DEBUG_END // locate revealing neighbours points - std::vector revealingNeighbours; + std::vector revealingNeighbours; auto crittest = [&](const EvalPoint& x2){return this->proximityTestOnRevealingPoint(*evalQueuePoint, x2);}; cache->find(crittest,revealingNeighbours); - if(revealingNeighbours.size()>0) + if(!revealingNeighbours.empty()) { NOMAD::Double revealedConstraint = evalQueuePoint->getRevealedConstraint(); // compute arfificial constraint of evalQueuePoint - for(auto revealingPoint : revealingNeighbours) + for(const auto& revealingPoint : revealingNeighbours) { OUTPUT_DEBUG_START - std::string s = std::to_string(revealingPoint.getTag())+" is a revealing point close to "+std::to_string(evalQueuePoint->getTag()); + s = std::to_string(revealingPoint.getTag())+" is a revealing point close to "+std::to_string(evalQueuePoint->getTag()); NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); NOMAD::OutputQueue::Flush(); OUTPUT_DEBUG_END - NOMAD::Double d=NOMAD::Point::dist(*evalQueuePoint,revealingPoint); // Distance //TODO: should be optimized with a distance matrix (computed here for the 3rd time) - NOMAD::Double tmpConstraint =1-d/_exclusionRadius; + NOMAD::Double d=NOMAD::Point::dist(*evalQueuePoint,revealingPoint); // Distance + NOMAD::Double tmpConstraint =1-d/_exclusionRadius; if(tmpConstraint>revealedConstraint) { revealedConstraint=tmpConstraint; @@ -257,27 +255,26 @@ void NOMAD::DiscoMadsMegaIteration::callbackCheckIfRevealingAndUpdate(NOMAD::Eva if (revealedConstraint> evalQueuePoint->getRevealedConstraint()) { evalQueuePoint->setRevealedConstraint(revealedConstraint); - cache->update(*evalQueuePoint,NOMAD::EvalType::BB); + cache->update(*evalQueuePoint,NOMAD::EvalType::BB); } } - } + } // Debug output to check that all new revealing points have been detected - OUTPUT_DEBUG_START - std::vector newRevealingPointsBis; + OUTPUT_DEBUG_START + std::vector newRevealingPointsBis; auto crittestNewRevealing = [&](const EvalPoint& x){return x.getRevealingStatus()==2;}; cache->find(crittestNewRevealing,newRevealingPointsBis); - if (newRevealingPointsBis.size()>0){ - std::string s; + if (!newRevealingPointsBis.empty()){ s = "List of new revealing points (" +std::to_string(newRevealingPointsBis.size())+"):"; - for(auto point: newRevealingPointsBis) - { + for(const auto& point: newRevealingPointsBis) + { s += " "+std::to_string(point.getTag()); } NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_DEBUG); NOMAD::OutputQueue::Flush(); } - OUTPUT_DEBUG_END + OUTPUT_DEBUG_END // Export cache at the end of megaiteration (for debug) bool cacheExport = false; @@ -291,7 +288,7 @@ void NOMAD::DiscoMadsMegaIteration::callbackCheckIfRevealingAndUpdate(NOMAD::Eva } // Only used for advanced debug -void NOMAD::DiscoMadsMegaIteration::exportCache(std::string cacheFile) +void NOMAD::DiscoMadsMegaIteration::exportCache(const std::string& cacheFile) { NOMAD::EvalPointPtr refBestInf = nullptr, refBestFeas = nullptr; @@ -307,34 +304,37 @@ void NOMAD::DiscoMadsMegaIteration::exportCache(std::string cacheFile) std::vector cachePoints; cache->getAllPoints(cachePoints); + const auto& computeType = _barrier->getFHComputeType(); + auto evalType = computeType.evalType; + // write cache file ofstream myCacheFile; myCacheFile.open (cacheFile); for (const auto & evalPoint : cachePoints) { - if (nullptr != evalPoint.getEval(NOMAD::EvalType::BB) && evalPoint.getEval(NOMAD::EvalType::BB)->goodForCacheFile()) + if (nullptr != evalPoint.getEval(evalType) && evalPoint.getEval(evalType)->goodForCacheFile()) { // Tag myCacheFile<getEvalType()==NOMAD::EvalType::BB) { - // Check if the point is revealing + // Check if the point is revealing if(evalQueuePoint->getRevealingStatus()==2) { _isRevealing = true; //then iteration is revealing - opportunisticIterStop = true; //and evaluations at this iteration should be stopped. + opportunisticIterStop = true; //and evaluations at this iteration should be stopped. } } } @@ -381,10 +381,9 @@ void NOMAD::DiscoMadsMegaIteration::callbackFailedEval(EvalQueuePointPtr & evalQ // Create new values of bb Output auto bboList = evalQueuePoint->getEval(NOMAD::EvalType::BB)->getBBOutput().getBBOAsArrayOfDouble(); - string bboutput; - for(size_t i = 0 ; i < bbOutputTypeList.size(); ++i) + string bboutput; + for(const auto& bbot : bbOutputTypeList) { - NOMAD::BBOutputType bbot = bbOutputTypeList[i]; // Set FOBJ and PB constraints to high value if (bbot.isObjective() || bbot==NOMAD::BBOutputType::PB) { @@ -399,14 +398,14 @@ void NOMAD::DiscoMadsMegaIteration::callbackFailedEval(EvalQueuePointPtr & evalQ continue; } else{ - // Check by security : other types of constraints are not treated + // Check by security : other types of constraints are not treated throw NOMAD::Exception(__FILE__,__LINE__,"Discomads for hidden constraints: callback for failed eval only treat OBJ/PB/EB/RPB constraints."); } } // Assign new bb output to point (change eval status too) bool eval_ok = true; - eval->setBBO(bboutput,bbOutputTypeList,eval_ok); + eval->setBBO(bboutput,bbOutputTypeList, eval_ok); // Update revealing status of point evalQueuePoint->setRevealingStatus(2); @@ -419,10 +418,10 @@ void NOMAD::DiscoMadsMegaIteration::callbackFailedEval(EvalQueuePointPtr & evalQ void NOMAD::DiscoMadsMegaIteration::callbackPostProcessing(const NOMAD::Step & step, bool &stop) -{ +{ // Treat special case of revealation during a search algo: in this case remaining evaluations for this search algo should be stopped // as well as parent search evaluations for this DiscoMads iteration - // NB: this situation is not taken into account in IterationUtils::updateStopReasonForIterStop) + // NB: this situation is not taken into account in IterationUtils::updateStopReasonForIterStop auto evc = NOMAD::EvcInterface::getEvaluatorControl(); stop = false; // reset as we don't control a global stop in this callback @@ -438,12 +437,12 @@ void NOMAD::DiscoMadsMegaIteration::callbackPostProcessing(const NOMAD::Step & s if (evcStopReason.checkStopType(NOMAD::EvalMainThreadStopType::CUSTOM_OPPORTUNISTIC_ITER_STOP)) { - // Is this step done during a search ? - NOMAD::Search * searchStep = step.getParentOfType(false); + // Is this step done during a search ? + auto* searchStep = step.getParentOfType(false); if(nullptr!= searchStep) { // Is this done during a search algo ? Look for an algorithm among the parents. It should be a search algorithm, that is, not the root Algorithm. Stop it completely if found. - // If we simply search for an algorithm among the parents we may endup with the root Mads algorithm. + // If we simply search for an algorithm among the parents we may end up with the root Mads algorithm. auto algoSM = step.getFirstAlgorithm(); if (algoSM != step.getRootAlgorithm()) { @@ -453,16 +452,17 @@ void NOMAD::DiscoMadsMegaIteration::callbackPostProcessing(const NOMAD::Step & s NOMAD::OutputQueue::Flush(); OUTPUT_DEBUG_END - // stop the parent search step iteration (may contains severeal searches) + // stop the parent search step iteration (may contain several searches) searchStep->getAllStopReasons()->set(NOMAD::IterStopType::USER_ITER_STOP); // stop the search algo used in search step algoSM->getAllStopReasons()->set(NOMAD::IterStopType::USER_ALGO_STOP); + } } - // Is this step done during a revealing poll or a poll + // Is this step done during a revealing poll or a poll // => stop is managed by IterationUtils::updateStopReasonForIterStop and passed to checkTerminate - } + } } @@ -472,7 +472,7 @@ void NOMAD::DiscoMadsMegaIteration::init() setStepType(NOMAD::StepType::MEGA_ITERATION); // Check computeType (DiscoMadsMegaIteration should not be done within PhaseOne) - if(NOMAD::EvcInterface::getEvaluatorControl()->getComputeType()!=NOMAD::ComputeType::STANDARD) + if(_barrier->getComputeType()!=NOMAD::ComputeType::STANDARD) { string s = "DiscoMadsMegaIteration: Only STANDARD compute type is handled"; throw NOMAD::Exception(__FILE__, __LINE__, s); @@ -481,13 +481,13 @@ void NOMAD::DiscoMadsMegaIteration::init() // Get values of discomads parameters - _detectionRadius = _runParams->getAttributeValue("DISCO_MADS_DETECTION_RADIUS"); // only for discontinuity revealation - _limitRate = _runParams->getAttributeValue("DISCO_MADS_LIMIT_RATE"); // only for discontinuity revealation + _detectionRadius = _runParams->getAttributeValue("DISCO_MADS_DETECTION_RADIUS"); // only for discontinuity revelation + _limitRate = _runParams->getAttributeValue("DISCO_MADS_LIMIT_RATE"); // only for discontinuity revelation _exclusionRadius = _runParams->getAttributeValue("DISCO_MADS_EXCLUSION_RADIUS"); - _detectHiddConst = _runParams->getAttributeValue("DISCO_MADS_HID_CONST"); // only for hidden constraints revealation - _hiddConstOutputValue = _runParams->getAttributeValue("DISCO_MADS_HID_CONST_OUTPUT_VALUE"); // only for hidden constraints revealation + _detectHiddConst = _runParams->getAttributeValue("DISCO_MADS_HID_CONST"); // only for hidden constraints revelation + _hiddConstOutputValue = _runParams->getAttributeValue("DISCO_MADS_HID_CONST_OUTPUT_VALUE"); // only for hidden constraints revelation @@ -495,32 +495,32 @@ void NOMAD::DiscoMadsMegaIteration::init() // Build vector of indices of revealing output const auto bbotList = NOMAD::Algorithm::getBbOutputType(); std::vector revealingOutputIdx; - for(unsigned int idxOutput=0; idxOutput