NOMAD Source  Version 4.0.0 Beta
Subproblem.cpp
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------------*/
2 /* NOMAD - Nonlinear Optimization by Mesh Adaptive Direct Search - */
3 /* */
4 /* NOMAD - Version 4.0.0 has been created by */
5 /* Viviane Rochon Montplaisir - Polytechnique Montreal */
6 /* Christophe Tribes - Polytechnique Montreal */
7 /* */
8 /* The copyright of NOMAD - version 4.0.0 is owned by */
9 /* Charles Audet - Polytechnique Montreal */
10 /* Sebastien Le Digabel - Polytechnique Montreal */
11 /* Viviane Rochon Montplaisir - Polytechnique Montreal */
12 /* Christophe Tribes - Polytechnique Montreal */
13 /* */
14 /* NOMAD v4 has been funded by Rio Tinto, Hydro-Québec, NSERC (Natural */
15 /* Sciences and Engineering Research Council of Canada), InnovÉÉ (Innovation */
16 /* en Énergie Électrique) and IVADO (The Institute for Data Valorization) */
17 /* */
18 /* NOMAD v3 was created and developed by Charles Audet, Sebastien Le Digabel, */
19 /* Christophe Tribes and Viviane Rochon Montplaisir and was funded by AFOSR */
20 /* and Exxon Mobil. */
21 /* */
22 /* NOMAD v1 and v2 were created and developed by Mark Abramson, Charles Audet, */
23 /* Gilles Couture, and John E. Dennis Jr., and were funded by AFOSR and */
24 /* Exxon Mobil. */
25 /* */
26 /* Contact information: */
27 /* Polytechnique Montreal - GERAD */
28 /* C.P. 6079, Succ. Centre-ville, Montreal (Quebec) H3C 3A7 Canada */
29 /* e-mail: nomad@gerad.ca */
30 /* */
31 /* This program is free software: you can redistribute it and/or modify it */
32 /* under the terms of the GNU Lesser General Public License as published by */
33 /* the Free Software Foundation, either version 3 of the License, or (at your */
34 /* option) any later version. */
35 /* */
36 /* This program is distributed in the hope that it will be useful, but WITHOUT */
37 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
38 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License */
39 /* for more details. */
40 /* */
41 /* You should have received a copy of the GNU Lesser General Public License */
42 /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
43 /* */
44 /* You can find information on the NOMAD software at www.gerad.ca/nomad */
45 /*---------------------------------------------------------------------------------*/
46 /**
47  \file Subproblem.cpp
48  \brief Subproblem of lesser dimension than the original problem
49  \author Viviane Rochon Montplaisir
50  \date February 2019
51  */
52 #include "../Algos/Subproblem.hpp"
53 #include "../Output/OutputQueue.hpp"
54 #include "../Type/BBInputType.hpp"
55 
56 
57 /*------------*/
58 /* Subproblem */
59 /*------------*/
60 void NOMAD::Subproblem::init()
61 {
62  if (nullptr == _refPbParams)
63  {
64  throw NOMAD::Exception(__FILE__, __LINE__,
65  "A valid PbParameters must be provided to the Subproblem constructor.");
66  }
67 
68  if (_fixedVariable.isEmpty())
69  {
70  std::string s = "Error: Fixed variable of dimension 0";
71  throw NOMAD::Exception(__FILE__,__LINE__,s);
72  }
73 
74  // Compute new dimension
75  NOMAD::Point subFixedVariable = _refPbParams->getAttributeValue<NOMAD::Point>("FIXED_VARIABLE");
76  _dimension = subFixedVariable.size() - subFixedVariable.nbDefined();
77 
78 
79  setupProblemParameters();
80 }
81 
82 
83 NOMAD::Subproblem::~Subproblem()
84 {
85 }
86 
87 
88 void NOMAD::Subproblem::setupProblemParameters()
89 {
90  // NOTE: If a new parameter with dimension is added to the class PbParameters,
91  // this method will break.
92  // It could be generalized by going through each parameter, and adjust it only
93  // if it is an ArrayOfDouble, Point, or Dimension. Backlog task.
94  const size_t refDimension = _refPbParams->getAttributeValue<size_t>("DIMENSION");
95  size_t n = _dimension;
96 
97  _subPbParams = std::make_shared<NOMAD::PbParameters>(*_refPbParams);
98  _subPbParams->setAttributeValue("DIMENSION", n);
99 
100  // Get reference values for parameters
101  const auto refX0s = _refPbParams->getAttributeValue<NOMAD::ArrayOfPoint>("X0");
102  const auto refLowerBound = _refPbParams->getAttributeValue<NOMAD::ArrayOfDouble>("LOWER_BOUND");
103  const auto refUpperBound = _refPbParams->getAttributeValue<NOMAD::ArrayOfDouble>("UPPER_BOUND");
104  const auto refBBInputType = _refPbParams->getAttributeValue<NOMAD::BBInputTypeList>("BB_INPUT_TYPE");
105  const auto refInitMeshSize = _refPbParams->getAttributeValue<NOMAD::ArrayOfDouble>("INITIAL_MESH_SIZE");
106  const auto refInitFrameSize = _refPbParams->getAttributeValue<NOMAD::ArrayOfDouble>("INITIAL_FRAME_SIZE");
107  const auto refMinMeshSize = _refPbParams->getAttributeValue<NOMAD::ArrayOfDouble>("MIN_MESH_SIZE");
108  const auto refMinFrameSize = _refPbParams->getAttributeValue<NOMAD::ArrayOfDouble>("MIN_FRAME_SIZE");
109  const auto refGranularity = _refPbParams->getAttributeValue<NOMAD::ArrayOfDouble>("GRANULARITY");
110  const auto refListVariableGroup = _refPbParams->getAttributeValue<NOMAD::ListOfVariableGroup>("VARIABLE_GROUP");
111 
112  // Initialize new arrays
114  for (size_t x0index = 0; x0index < refX0s.size(); x0index++)
115  {
116  NOMAD::Point x0(n);
117  x0s.push_back(x0);
118  }
119  NOMAD::Point subFixedVariable(n);
120  NOMAD::ArrayOfDouble lb(n), ub(n);
121  NOMAD::BBInputTypeList bbInputType;
122  NOMAD::ArrayOfDouble initialMeshSize(n), initialFrameSize(n), minMeshSize(n), minFrameSize(n);
123  NOMAD::ArrayOfDouble granularity(n);
124  NOMAD::ListOfVariableGroup listVariableGroup = refListVariableGroup ;
125 
126  // Compute new fixed variable.
127  // Current value of _fixedVariable contains only values from parent. Merge in values from _refPbParams.
128  NOMAD::Point refFixedVariable = _refPbParams->getAttributeValue<NOMAD::Point>("FIXED_VARIABLE");
129 
130  // Compute new values, simply using the values on the positions of non-fixed variables.
131  size_t i = 0;
132  for (size_t refIndex = 0; refIndex < refDimension; refIndex++)
133  {
134  if (refFixedVariable[refIndex].isDefined())
135  {
136  continue;
137  }
138 
139  for (size_t x0index = 0; x0index < refX0s.size(); x0index++)
140  {
141  auto refX0 = refX0s[x0index];
142  x0s[x0index][i] = refX0[refIndex];
143  }
144  lb[i] = refLowerBound[refIndex];
145  ub[i] = refUpperBound[refIndex];
146  bbInputType.push_back(refBBInputType[refIndex]);
147  initialMeshSize[i] = refInitMeshSize[refIndex];
148  initialFrameSize[i] = refInitFrameSize[refIndex];
149  minMeshSize[i] = refMinMeshSize[refIndex];
150  minFrameSize[i] = refMinFrameSize[refIndex];
151  granularity[i] = refGranularity[refIndex];
152 
153  i++;
154  }
155  resetVariableGroupsAgainstFixedVariables(listVariableGroup, refFixedVariable);
156 
157 
158  // Set new values to _subPbParams
159  _subPbParams->setAttributeValue("X0", x0s);
160  _subPbParams->setAttributeValue("FIXED_VARIABLE", subFixedVariable); // No fixed variable defined in the subproblem
161  _subPbParams->setAttributeValue("LOWER_BOUND", lb);
162  _subPbParams->setAttributeValue("UPPER_BOUND", ub);
163  _subPbParams->setAttributeValue("BB_INPUT_TYPE", bbInputType);
164  _subPbParams->setAttributeValue("INITIAL_MESH_SIZE", initialMeshSize);
165  _subPbParams->setAttributeValue("INITIAL_FRAME_SIZE", initialFrameSize);
166  _subPbParams->setAttributeValue("MIN_MESH_SIZE", minMeshSize);
167  _subPbParams->setAttributeValue("MIN_FRAME_SIZE", minFrameSize);
168  _subPbParams->setAttributeValue("GRANULARITY", granularity);
169  _subPbParams->setAttributeValue("VARIABLE_GROUP", listVariableGroup);
170 
171  _subPbParams->doNotShowWarnings();
172 
173  _subPbParams->checkAndComply();
174 
175  // Only now, conbine refFixedVariable into _fixedVariable.
176  // Verify that refFixedVariable is of the dimension of the subproblem defined by _fixedVariable.
177  if (refFixedVariable.size() == _fixedVariable.size())
178  {
179  refFixedVariable = refFixedVariable.makeSubSpacePointFromFixed(_fixedVariable);
180  }
181  const size_t subdim1 = _fixedVariable.size() - _fixedVariable.nbDefined();
182  if (refFixedVariable.size() != subdim1)
183  {
184  std::string s = "Expecting FIXED_VARIABLE to be of size " + std::to_string(subdim1);
185  s += ". Current FIXED_VARIABLE is of size " + std::to_string(refFixedVariable.size());
186  s += ": " + refFixedVariable.display();
187  throw NOMAD::Exception(__FILE__,__LINE__, s);
188  }
189 
190  for (size_t refIndex = 0, newIndex = 0; refIndex < _fixedVariable.size(); refIndex++)
191  {
192  if (!_fixedVariable[refIndex].isDefined())
193  {
194  _fixedVariable[refIndex] = refFixedVariable[newIndex];
195  newIndex++;
196  }
197  }
198 
200  std::string s = "FIXED_VARIABLE set to " + _fixedVariable.display();
201  NOMAD::OutputQueue::Add(s, NOMAD::OutputLevel::LEVEL_INFO);
203 
204 }
205 
206 
207 // If a variable is fixed, its index must be removed from the group of variables
208 // All the indices above the fixed variable index must be decreased by one
209 void NOMAD::Subproblem::resetVariableGroupsAgainstFixedVariables(NOMAD::ListOfVariableGroup & lvg, const NOMAD::Point & fixedVar) const
210 {
211  if (lvg.empty() || !fixedVar.isDefined())
212  {
213  return;
214  }
215 
216  // Put the indices of fixed variables in a single set.
217  const size_t n = fixedVar.size();
218  std::set<size_t> indicesToRemove;
219  for (size_t i = 0 ; i < n ; i++)
220  {
221  if (fixedVar[i].isDefined())
222  {
223  indicesToRemove.insert(i);
224  }
225  }
226 
227  NOMAD::ListOfVariableGroup updatedLvg;
228  while (!indicesToRemove.empty())
229  {
230  updatedLvg.clear();
231  auto itIndexBegin = indicesToRemove.begin();
232 
233  // Remove an index in a variable group. Decrement by one all indices (in all variable groups) above the index to remove.
234  for (auto vg: lvg)
235  {
236  NOMAD::VariableGroup updatedVariableGroup;
237  for (auto index : vg)
238  {
239  // Do not include an index equal to the index to remove.
240  // Include and decrement indices above the index to remove.
241  // Include indices below the index to remove.
242  if (index > *itIndexBegin)
243  {
244  updatedVariableGroup.insert(index-1);
245  }
246  else if (index < *itIndexBegin)
247  {
248  updatedVariableGroup.insert(index);
249  }
250 
251  }
252  // A variable group can be empty -> do not include.
253  if (!updatedVariableGroup.empty())
254  {
255  updatedLvg.push_back(updatedVariableGroup);
256  }
257  }
258 
259  // Remove index from the set of indices. Decrement remaining indices that are smaller than the index to remove.
260  std::set<size_t> updatedIndicesToRemove;
261  for (std::set<size_t>::iterator itIndex = ++itIndexBegin; itIndex != indicesToRemove.end() ; ++itIndex)
262  {
263  updatedIndicesToRemove.insert((*itIndex)-1);
264  }
265  indicesToRemove = updatedIndicesToRemove;
266  lvg = updatedLvg;
267  }
268 
269 }
270 
ArrayOfPoint
std::vector< Point > ArrayOfPoint
Type definition for the representation of a vector of points.
Definition: ArrayOfPoint.hpp:63
BBInputTypeList
std::vector< BBInputType > BBInputTypeList
Definition: BBInputType.hpp:80
OUTPUT_INFO_END
#define OUTPUT_INFO_END
Definition: OutputQueue.hpp:151
VariableGroup
std::set< size_t > VariableGroup
Type definition for the representation of a variable group (set of indices).
Definition: ListOfVariableGroup.hpp:64
ListOfVariableGroup
std::list< VariableGroup > ListOfVariableGroup
Type definition for the representation of a vector of points.
Definition: ListOfVariableGroup.hpp:71
OUTPUT_INFO_START
#define OUTPUT_INFO_START
Definition: OutputQueue.hpp:148