gemseo-multi-fidelity 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. gemseo_multi_fidelity/__init__.py +17 -0
  2. gemseo_multi_fidelity/core/MFMapperAdapter_input.json +22 -0
  3. gemseo_multi_fidelity/core/MFMapperAdapter_output.json +22 -0
  4. gemseo_multi_fidelity/core/MFMapperLinker_input.json +22 -0
  5. gemseo_multi_fidelity/core/MFMapperLinker_output.json +22 -0
  6. gemseo_multi_fidelity/core/MFScenarioAdapter_input.json +39 -0
  7. gemseo_multi_fidelity/core/MFScenarioAdapter_output.json +23 -0
  8. gemseo_multi_fidelity/core/__init__.py +16 -0
  9. gemseo_multi_fidelity/core/boxed_domain.py +242 -0
  10. gemseo_multi_fidelity/core/corr_function.py +411 -0
  11. gemseo_multi_fidelity/core/criticality.py +124 -0
  12. gemseo_multi_fidelity/core/ds_mapper.py +307 -0
  13. gemseo_multi_fidelity/core/errors.py +42 -0
  14. gemseo_multi_fidelity/core/eval_mapper.py +188 -0
  15. gemseo_multi_fidelity/core/id_mapper_adapter.py +61 -0
  16. gemseo_multi_fidelity/core/mapper_adapter.py +126 -0
  17. gemseo_multi_fidelity/core/mapper_linker.py +72 -0
  18. gemseo_multi_fidelity/core/mf_formulation.py +635 -0
  19. gemseo_multi_fidelity/core/mf_logger.py +216 -0
  20. gemseo_multi_fidelity/core/mf_opt_problem.py +480 -0
  21. gemseo_multi_fidelity/core/mf_scenario.py +205 -0
  22. gemseo_multi_fidelity/core/noise_criterion.py +94 -0
  23. gemseo_multi_fidelity/core/projpolytope.out +0 -0
  24. gemseo_multi_fidelity/core/scenario_adapter.py +568 -0
  25. gemseo_multi_fidelity/core/stop_criteria.py +201 -0
  26. gemseo_multi_fidelity/core/strict_chain.py +75 -0
  27. gemseo_multi_fidelity/core/utils_model_quality.py +74 -0
  28. gemseo_multi_fidelity/corrections/__init__.py +16 -0
  29. gemseo_multi_fidelity/corrections/add_corr_function.py +80 -0
  30. gemseo_multi_fidelity/corrections/correction_factory.py +65 -0
  31. gemseo_multi_fidelity/corrections/mul_corr_function.py +86 -0
  32. gemseo_multi_fidelity/drivers/__init__.py +16 -0
  33. gemseo_multi_fidelity/drivers/mf_algo_factory.py +38 -0
  34. gemseo_multi_fidelity/drivers/mf_driver_lib.py +462 -0
  35. gemseo_multi_fidelity/drivers/refinement.py +234 -0
  36. gemseo_multi_fidelity/drivers/settings/__init__.py +16 -0
  37. gemseo_multi_fidelity/drivers/settings/base_mf_driver_settings.py +59 -0
  38. gemseo_multi_fidelity/drivers/settings/mf_refine_settings.py +50 -0
  39. gemseo_multi_fidelity/formulations/__init__.py +16 -0
  40. gemseo_multi_fidelity/formulations/refinement.py +144 -0
  41. gemseo_multi_fidelity/mapping/__init__.py +16 -0
  42. gemseo_multi_fidelity/mapping/identity_mapper.py +74 -0
  43. gemseo_multi_fidelity/mapping/interp_mapper.py +422 -0
  44. gemseo_multi_fidelity/mapping/mapper_factory.py +70 -0
  45. gemseo_multi_fidelity/mapping/mapping_errors.py +46 -0
  46. gemseo_multi_fidelity/mapping/subset_mapper.py +122 -0
  47. gemseo_multi_fidelity/mf_rosenbrock/__init__.py +16 -0
  48. gemseo_multi_fidelity/mf_rosenbrock/delayed_disc.py +136 -0
  49. gemseo_multi_fidelity/mf_rosenbrock/refact_rosen_testcase.py +46 -0
  50. gemseo_multi_fidelity/mf_rosenbrock/rosen_mf_case.py +284 -0
  51. gemseo_multi_fidelity/mf_rosenbrock/rosen_mf_funcs.py +350 -0
  52. gemseo_multi_fidelity/models/__init__.py +16 -0
  53. gemseo_multi_fidelity/models/fake_updater.py +112 -0
  54. gemseo_multi_fidelity/models/model_updater.py +91 -0
  55. gemseo_multi_fidelity/models/rbf/__init__.py +16 -0
  56. gemseo_multi_fidelity/models/rbf/kernel_factory.py +66 -0
  57. gemseo_multi_fidelity/models/rbf/kernels/__init__.py +16 -0
  58. gemseo_multi_fidelity/models/rbf/kernels/gaussian.py +93 -0
  59. gemseo_multi_fidelity/models/rbf/kernels/matern_3_2.py +101 -0
  60. gemseo_multi_fidelity/models/rbf/kernels/matern_5_2.py +101 -0
  61. gemseo_multi_fidelity/models/rbf/kernels/rbf_kernel.py +172 -0
  62. gemseo_multi_fidelity/models/rbf/rbf_model.py +422 -0
  63. gemseo_multi_fidelity/models/sparse_rbf_updater.py +96 -0
  64. gemseo_multi_fidelity/models/taylor/__init__.py +16 -0
  65. gemseo_multi_fidelity/models/taylor/taylor.py +212 -0
  66. gemseo_multi_fidelity/models/taylor_updater.py +66 -0
  67. gemseo_multi_fidelity/models/updater_factory.py +62 -0
  68. gemseo_multi_fidelity/settings/__init__.py +16 -0
  69. gemseo_multi_fidelity/settings/drivers.py +22 -0
  70. gemseo_multi_fidelity/settings/formulations.py +16 -0
  71. gemseo_multi_fidelity-0.0.1.dist-info/METADATA +99 -0
  72. gemseo_multi_fidelity-0.0.1.dist-info/RECORD +76 -0
  73. gemseo_multi_fidelity-0.0.1.dist-info/WHEEL +5 -0
  74. gemseo_multi_fidelity-0.0.1.dist-info/entry_points.txt +2 -0
  75. gemseo_multi_fidelity-0.0.1.dist-info/licenses/LICENSE.txt +165 -0
  76. gemseo_multi_fidelity-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,422 @@
1
+ # Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 3 as published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public License
13
+ # along with this program; if not, write to the Free Software Foundation,
14
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15
+
16
+ # Copyright (c) 2019 AIRBUS OPERATIONS
17
+
18
+ #
19
+ # Contributors:
20
+ # INITIAL AUTHORS - API and implementation and/or documentation
21
+ # :author: Romain Olivanti
22
+ # OTHER AUTHORS - MACROSCOPIC CHANGES
23
+ """Interpolation mapper."""
24
+
25
+ from __future__ import annotations
26
+
27
+ import logging
28
+ from copy import deepcopy
29
+ from typing import TYPE_CHECKING
30
+ from typing import ClassVar
31
+
32
+ from numpy import array
33
+ from numpy import atleast_2d
34
+ from numpy import eye
35
+ from numpy import inf
36
+ from numpy import vstack
37
+ from numpy import zeros
38
+ from numpy.linalg import norm
39
+
40
+ from gemseo_multi_fidelity.core.ds_mapper import DesignSpaceMapper
41
+ from gemseo_multi_fidelity.mapping.mapping_errors import MappingError
42
+
43
+ if TYPE_CHECKING:
44
+ from gemseo.algos.design_space import DesignSpace
45
+ from numpy.typing import NDArray
46
+
47
+ LOGGER = logging.getLogger(__name__)
48
+
49
+
50
+ class InterpolationMapper(DesignSpaceMapper):
51
+ """Interpolation mapper."""
52
+
53
+ LINEAR = "linear"
54
+ CUBIC = "cubic"
55
+ AUTO_INTERP_TYPES: ClassVar[list] = [LINEAR, CUBIC]
56
+
57
+ def __init__(
58
+ self,
59
+ design_space_in: DesignSpace,
60
+ design_space_out: DesignSpace,
61
+ interp_logic: dict | None = None,
62
+ auto_interp: bool = False,
63
+ split_pattern: str = "_",
64
+ auto_interp_type: str = "linear",
65
+ ) -> None:
66
+ """Constructor.
67
+
68
+ Args:
69
+ design_space_in: The input design space.
70
+ design_space_out: The output design space.
71
+ interp_logic: The user-defined interpolation logic between input and output
72
+ variables.
73
+ auto_interp: ``True`` to activate the auto interpolation feature. Not used
74
+ if interp_logic is provided.
75
+ split_pattern: The pattern used to identify variables can that be linked to
76
+ interpolate i.e. 'name_0', 'name_1', ...
77
+ auto_interp_type: The type of interpolation law to consider.
78
+ """
79
+ super().__init__(design_space_in, design_space_out)
80
+ self._prolg_oper = None
81
+ self._restr_oper = None
82
+ self._norm_prolg = None
83
+ self._restr_factor = None
84
+
85
+ if interp_logic is not None:
86
+ self._build_interp_from_logic(interp_logic)
87
+ else:
88
+ if not auto_interp:
89
+ msg = (
90
+ "Automatic interpolation not activated but "
91
+ "no interpolation logic has been provided"
92
+ )
93
+ raise ValueError(msg)
94
+ self._build_interp_auto(split_pattern, auto_interp_type)
95
+
96
+ self._check_interp()
97
+ self._compute_factors()
98
+
99
+ def _build_interp_from_logic(self, interp_logic: dict) -> None:
100
+ """Build operators from the interp logic that contains all the logic.
101
+
102
+ Args:
103
+ interp_logic: The interp logic.
104
+ """
105
+ prolg_oper = {}
106
+ restr_oper = {}
107
+
108
+ for var_out, prolg_logic in iter(list(interp_logic.items())):
109
+ prolg_oper[var_out] = {}
110
+ for var_in, oper in iter(list(prolg_logic.items())):
111
+ try:
112
+ len(oper)
113
+ prolg_val = atleast_2d(oper).copy()
114
+ except TypeError:
115
+ # Light storage, make sure it is a float
116
+ prolg_val = float(oper)
117
+ prolg_oper[var_out][var_in] = prolg_val
118
+ if var_in not in restr_oper:
119
+ restr_oper[var_in] = {}
120
+ # Do not save the prolg transpose on purpose, use only a reference
121
+ restr_oper[var_in][var_out] = prolg_val
122
+ self._prolg_oper = prolg_oper
123
+ self._restr_oper = restr_oper
124
+
125
+ def _build_interp_on_var_size(
126
+ self,
127
+ var_name: str,
128
+ dim_in: int,
129
+ dim_out: int,
130
+ interp_type: str,
131
+ log_prefix: str,
132
+ ) -> dict:
133
+ """Build a prolongation operator based on input and output sizes.
134
+
135
+ Args:
136
+ var_name: The name of the variable considered.
137
+ dim_in: The input dimension.
138
+ dim_out: The output dimension.
139
+ interp_type: The type of interpolation to use.
140
+ log_prefix: The prefix for logs.
141
+
142
+ Returns:
143
+ The prolongation operator.
144
+ """
145
+ if dim_out == dim_in:
146
+ # Exact match
147
+ LOGGER.info("%s assuming identity law for %s", log_prefix, var_name)
148
+ oper_array = 1.0
149
+ else:
150
+ # Check if sizes allow deducing the operator and log it so that
151
+ # the user has a better understanding of what to expect
152
+ if dim_out == 2 * dim_in - 1:
153
+ # Outside values are exact
154
+ LOGGER.info(
155
+ "%s assuming %s interpolation law with exact outside values for %s",
156
+ log_prefix,
157
+ interp_type,
158
+ var_name,
159
+ )
160
+ elif dim_out == 2 * dim_in + 1:
161
+ # Outside values will be interpolated
162
+ LOGGER.info(
163
+ "%s assuming %s interpolation law "
164
+ "with interpolated outside values for %s",
165
+ log_prefix,
166
+ interp_type,
167
+ var_name,
168
+ )
169
+ else:
170
+ msg = (
171
+ "{None} not same size for the variable {None} "
172
+ "between in and out but cannot deduce "
173
+ "an interpolation pattern"
174
+ )
175
+ raise MappingError(msg)
176
+ # Actual array assembly
177
+ oper_array = self._build_prolg_oper(dim_in, dim_out, interp_type)
178
+ return {var_name: oper_array}
179
+
180
+ def _build_prolg_oper(self, dim_in: int, dim_out: int, interp_type: str) -> NDArray:
181
+ """Build a linear interpolation operator.
182
+
183
+ Args:
184
+ dim_in: The input dimension.
185
+ dim_out: The output dimension.
186
+ interp_type: The type of interpolation to use.
187
+
188
+ Returns:
189
+ The linear interpolation operator.
190
+ """
191
+ # Checks
192
+ if interp_type not in self.AUTO_INTERP_TYPES:
193
+ err = "{} not in implemented auto interpolation laws: {}"
194
+ err = err.format(interp_type, self.AUTO_INTERP_TYPES)
195
+ raise ValueError(err)
196
+
197
+ if interp_type == self.CUBIC and dim_in % 3 != 0:
198
+ msg = "Cannot use cubic interpolation if dim_in % 3 != 0"
199
+ raise MappingError(msg)
200
+
201
+ assert dim_in < dim_out
202
+
203
+ is_outside_interpolated = dim_out == 2 * dim_in + 1
204
+
205
+ if is_outside_interpolated:
206
+ # Outside values will be added at the end
207
+ dim_out -= 2
208
+
209
+ i_in = 0
210
+ oper = zeros((dim_out, dim_in))
211
+
212
+ # TODO use a sparse representation?
213
+ for i in range(dim_out):
214
+ if i % 2 == 0:
215
+ oper[i, i_in] = 1.0
216
+ i_in += 1
217
+ else:
218
+ if interp_type == self.LINEAR:
219
+ oper[i, i_in - 1 : i_in + 1] = array([0.5, 0.5])
220
+ else:
221
+ if i % 3 == 0:
222
+ oper[i, i_in - 2 : i_in + 1] = array([-0.0625, 0.5625, 0.5625])
223
+ else:
224
+ oper[i, i_in - 1 : i_in + 2] = array([0.5625, 0.5625, -0.0625])
225
+
226
+ if is_outside_interpolated:
227
+ # stack first and last row
228
+ first_row = zeros((1, dim_in))
229
+ last_row = zeros((1, dim_in))
230
+ if interp_type == self.LINEAR:
231
+ first_row[0, 0] = 0.5
232
+ last_row[0, -1] = 0.5
233
+ else:
234
+ first_row[0, 0:2] = array([0.75, -0.125])
235
+ last_row[0, -2::] = array([-0.125, 0.75])
236
+ oper = vstack((first_row, oper, last_row))
237
+ return oper
238
+
239
+ def _build_inter_on_var_names(
240
+ self, var: str, var_dim: int, split_pattern: str, log_prefix: str
241
+ ) -> dict:
242
+ """Build interpolation on var names.
243
+
244
+ Tries to build the interpolation logic for var_out using other variables for the
245
+ input design space.
246
+
247
+ Args:
248
+ var: The name of the output variable.
249
+ var_dim: The dimension of the output variable.
250
+ split_pattern: The pattern used to identify linked variables.
251
+ log_prefix: The prefix for logs.
252
+
253
+ Returns:
254
+ The interpolation logic.
255
+ """
256
+ ds_in = self.design_space_in
257
+ split_name = var.split(split_pattern)
258
+ var_gen_name = "".join(split_name[0:-1])
259
+ interp_dict = {}
260
+
261
+ try:
262
+ var_index = int(split_name[-1])
263
+ except ValueError as exc:
264
+ msg = f"{var} cannot be linked to variables in the input design space"
265
+ raise MappingError(msg) from exc
266
+
267
+ prev_var = f"{var_gen_name}{split_pattern}{var_index - 1:d}"
268
+ next_var = f"{var_gen_name}{split_pattern}{var_index + 1:d}"
269
+
270
+ # ds_in has prev var?
271
+ prev_dim = ds_in.get_size(prev_var)
272
+ if prev_dim is not None:
273
+ if prev_dim != var_dim:
274
+ err = "{} {} sizes do not match: {:d} != {:d}"
275
+ err = err.format(var, prev_var, var_dim, prev_dim)
276
+ raise MappingError(err)
277
+ interp_dict[prev_var] = 0.5
278
+
279
+ # ds_in has next var?
280
+ next_dim = ds_in.get_size(next_var)
281
+ if next_dim is not None:
282
+ if next_dim != var_dim:
283
+ err = "{} {} sizes do not match: {:d} != {:d}"
284
+ err = err.format(var, next_var, var_dim, next_dim)
285
+ raise MappingError(err)
286
+ interp_dict[next_var] = 0.5
287
+ return interp_dict
288
+
289
+ def _build_interp_auto(self, split_pattern: str, interp_type: str) -> dict:
290
+ """Handle the auto interpolation detection.
291
+
292
+ Args:
293
+ split_pattern: The pattern used to identify linked variables.
294
+ interp_type: The type of interpolation to use.
295
+
296
+ Returns:
297
+ The interpolation logic.
298
+ """
299
+ ds_in = self.design_space_in
300
+ ds_out = self.design_space_out
301
+ interp_logic = {}
302
+ log_prefix = "Auto interpolation mapping:"
303
+
304
+ # Try to build the interp logic using auto rules
305
+ for var_out, dim_out in iter(list(ds_out.variable_sizes.items())):
306
+ # Checks if the var exists in the input design space
307
+ dim_in = ds_in.get_size(var_out)
308
+ if dim_in is not None:
309
+ # The variable exists in the input design space
310
+ interp_dict = self._build_interp_on_var_size(
311
+ var_out, dim_in, dim_out, interp_type, log_prefix
312
+ )
313
+ else:
314
+ if interp_type != self.LINEAR:
315
+ raise NotImplementedError
316
+ interp_dict = self._build_inter_on_var_names(
317
+ var_out, dim_out, split_pattern, log_prefix
318
+ )
319
+ interp_logic[var_out] = interp_dict
320
+
321
+ # Call _build_interp_from_logic using the logic built above
322
+ self._build_interp_from_logic(interp_logic)
323
+
324
+ def _check_interp(self) -> None:
325
+ """Check that all variables are correctly connected."""
326
+ vars_in = self.design_space_in.variable_names
327
+
328
+ def _check_size_zero(item):
329
+ if len(item) == 0:
330
+ raise KeyError
331
+
332
+ for var_out in self.design_space_out.variable_names:
333
+ try:
334
+ dict_prolg = self._prolg_oper[var_out]
335
+
336
+ # Might have been declared empty by mistake
337
+ _check_size_zero(dict_prolg)
338
+ except KeyError as exc:
339
+ err = f"{var_out} not connected to any input variable"
340
+ raise MappingError(err) from exc
341
+ for var in iter(list(dict_prolg.keys())):
342
+ if var not in vars_in:
343
+ err = (
344
+ f"{var_out} connected to variable: {var} "
345
+ f"not belonging to input variables: {vars_in}"
346
+ )
347
+ raise MappingError(err)
348
+
349
+ def _compute_factors(self) -> None:
350
+ """Compute factors."""
351
+ prolg_arr, _, _ = self.get_jac_array()
352
+ self._norm_prolg = norm(prolg_arr, ord=inf)
353
+ self._restr_factor = 1.0 / norm(prolg_arr.T, ord=inf)
354
+
355
+ def _map_vars_direct(self, dvs_dict_in: dict) -> dict:
356
+ """TODO.
357
+
358
+ Args:
359
+ dvs_dict_in: ??? TODO.
360
+
361
+ Returns:
362
+ ??? TODO
363
+ """
364
+ dvs_dict_out = {}
365
+ # Loop on vars out
366
+ for var_out, prolg_link in iter(list(self._prolg_oper.items())):
367
+ val_out = zeros(self.design_space_out.get_size(var_out))
368
+ # Loop on vars in
369
+ for var_in, sub_oper in prolg_link.items():
370
+ dvs_in = dvs_dict_in[var_in]
371
+ if isinstance(sub_oper, float):
372
+ # Light storage
373
+ val_out += sub_oper * dvs_in
374
+ else:
375
+ # Array
376
+ val_out += sub_oper.dot(dvs_in)
377
+ dvs_dict_out[var_out] = val_out
378
+ return dvs_dict_out
379
+
380
+ def _map_vars_reverse(self, dvs_dict_out: dict) -> dict:
381
+ """TODO.
382
+
383
+ Args:
384
+ dvs_dict_out: ??? TODO.
385
+
386
+ Returns:
387
+ ??? TODO.
388
+ """
389
+ dvs_dict_in = {}
390
+ # Loop on vars in
391
+ for var_in, restr_link in iter(list(self._restr_oper.items())):
392
+ val_in = zeros(self.design_space_in.get_size(var_in))
393
+ # Loop on vars out
394
+ for var_out, sub_oper in restr_link.items():
395
+ dvs_out = dvs_dict_out[var_out]
396
+ if isinstance(sub_oper, float):
397
+ val_in += sub_oper * dvs_out
398
+ else:
399
+ # sub_oper is a reference to the prolg operator for efficiency
400
+ # Therefore use sub_oper.T
401
+ val_in += dvs_out.dot(sub_oper)
402
+ # Apply the restriction factor
403
+ val_in *= self._restr_factor
404
+ dvs_dict_in[var_in] = val_in
405
+ return dvs_dict_in
406
+
407
+ def get_jac(self) -> dict:
408
+ """Get the jacobian."""
409
+ jac_dict = {}
410
+
411
+ # Make sure everything is formated into arrays
412
+ for var_out, prolg_link in iter(list(self._prolg_oper.items())):
413
+ jac_dict[var_out] = {}
414
+ for var_in, oper in iter(list(prolg_link.items())):
415
+ if isinstance(oper, float):
416
+ prolg = eye(self.design_space_out.get_size(var_out))
417
+ else:
418
+ # Copy to be on the safe side
419
+ prolg = oper.copy()
420
+ jac_dict[var_out][var_in] = prolg
421
+ # Build arrays
422
+ return deepcopy(jac_dict)
@@ -0,0 +1,70 @@
1
+ # Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 3 as published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public License
13
+ # along with this program; if not, write to the Free Software Foundation,
14
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15
+
16
+ # Copyright (c) 2019 AIRBUS OPERATIONS
17
+
18
+ #
19
+ # Contributors:
20
+ # INITIAL AUTHORS - API and implementation and/or documentation
21
+ # :author: Romain Olivanti
22
+ # OTHER AUTHORS - MACROSCOPIC CHANGES
23
+ """A factory to create a design space mapper from its name."""
24
+
25
+ from __future__ import annotations
26
+
27
+ from typing import TYPE_CHECKING
28
+ from typing import ClassVar
29
+
30
+ from gemseo_multi_fidelity.mapping.identity_mapper import IdentityMapper
31
+ from gemseo_multi_fidelity.mapping.interp_mapper import InterpolationMapper
32
+
33
+ if TYPE_CHECKING:
34
+ from gemseo.algos.design_space import DesignSpace
35
+
36
+ from gemseo_multi_fidelity.core.ds_mapper import DesignSpaceMapper
37
+
38
+
39
+ class DSMapperFactory:
40
+ """DesignSpaceMapper factory."""
41
+
42
+ ID = "identity"
43
+ INTERP = "interp"
44
+
45
+ AVAILABLE_MAPPERS: ClassVar[list] = [ID, INTERP]
46
+ """List of available mappers."""
47
+
48
+ def create(
49
+ self, name: str, ds_in: DesignSpace, ds_out: DesignSpace, **kwargs
50
+ ) -> DesignSpaceMapper:
51
+ """Create a DesignSpace Mapper from its name.
52
+
53
+ Args:
54
+ name: The name of the DesignSpace Mapper to use.
55
+ ds_in: The input design space.
56
+ ds_out: The output design space.
57
+ kwargs: The keyword arguments to be passed to the mapper class.
58
+
59
+ Returns:
60
+ The DesignSpace Mapper.
61
+ """
62
+ if name == self.ID:
63
+ klass = IdentityMapper
64
+ elif name == self.INTERP:
65
+ klass = InterpolationMapper
66
+ else:
67
+ msg = f"{name} not in {self.AVAILABLE_MAPPERS}"
68
+ raise ValueError(msg)
69
+
70
+ return klass(ds_in, ds_out, **kwargs)
@@ -0,0 +1,46 @@
1
+ # Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 3 as published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public License
13
+ # along with this program; if not, write to the Free Software Foundation,
14
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15
+
16
+ # Copyright (c) 2019 AIRBUS OPERATIONS
17
+
18
+ #
19
+ # Contributors:
20
+ # INITIAL AUTHORS - API and implementation and/or documentation
21
+ # :author: Romain Olivanti
22
+ # OTHER AUTHORS - MACROSCOPIC CHANGES
23
+ """Mapping error."""
24
+
25
+ from __future__ import annotations
26
+
27
+
28
+ class MappingError(Exception):
29
+ """Error to raise if a mapping is not consistent."""
30
+
31
+ def __init__(self, msg: str | None = None) -> None:
32
+ """Constructor.
33
+
34
+ Args:
35
+ msg: The explanation for the error.
36
+ """
37
+ super().__init__()
38
+ self.msg = msg
39
+
40
+ def __str__(self) -> str:
41
+ """Textual representation of the Error.
42
+
43
+ Returns:
44
+ The textual representation.
45
+ """
46
+ return repr(self.msg)
@@ -0,0 +1,122 @@
1
+ # Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 3 as published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public License
13
+ # along with this program; if not, write to the Free Software Foundation,
14
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15
+
16
+ # Copyright (c) 2020 AIRBUS OPERATIONS
17
+
18
+ #
19
+ # Contributors:
20
+ # INITIAL AUTHORS - API and implementation and/or documentation
21
+ # :author: Romain Olivanti
22
+ # OTHER AUTHORS - MACROSCOPIC CHANGES
23
+ """Subset mapper."""
24
+
25
+ from __future__ import annotations
26
+
27
+ from typing import TYPE_CHECKING
28
+
29
+ from numpy import array
30
+
31
+ from gemseo_multi_fidelity.core.ds_mapper import DesignSpaceMapper
32
+
33
+ if TYPE_CHECKING:
34
+ from gemseo.algos.design_space import DesignSpace
35
+ from numpy.typing import NDArray
36
+
37
+
38
+ class SubsetMapper(DesignSpaceMapper):
39
+ """Mapper of only a subset of variables."""
40
+
41
+ def __init__(
42
+ self,
43
+ design_space_in: DesignSpace,
44
+ design_space_out: DesignSpace,
45
+ vars_mapping: dict | None = None,
46
+ ) -> None:
47
+ """Constructor.
48
+
49
+ Args:
50
+ design_space_in: The input DesignSpace object.
51
+ design_space_out: The output DesignSpace object.
52
+ vars_mapping: The user-defined mapping between input and output variables.
53
+ """
54
+ super().__init__(design_space_in, design_space_out)
55
+ self._vars_mapping = self._check_vars_mapping(vars_mapping)
56
+
57
+ def _check_vars_mapping(self, vars_mapping: dict) -> dict:
58
+ vars_in = self.design_space_in.variable_names
59
+ vars_out = self.design_space_out.variable_names
60
+ if vars_mapping is None:
61
+ # Find the variables that can be matched automatically
62
+ vars_mapping = {}
63
+
64
+ for var in vars_out:
65
+ if var in vars_in:
66
+ vars_mapping[var] = var
67
+ else:
68
+ if not isinstance(vars_mapping, dict):
69
+ msg = "vars_mapping must be a dict or None"
70
+ raise TypeError(msg)
71
+ linked_vars_in = []
72
+ for var_out, var_in in vars_mapping.items():
73
+ if var_out not in vars_out:
74
+ msg = f"{var_out} not in {vars_out}"
75
+ raise ValueError(msg)
76
+ if var_in not in vars_in:
77
+ msg = f"{var_in} not in {vars_in}"
78
+ raise ValueError(msg)
79
+ if var_in in linked_vars_in:
80
+ msg = f"{var_in} linked to more than one var out"
81
+ raise ValueError(msg)
82
+ linked_vars_in.append(var_in)
83
+ return vars_mapping
84
+
85
+ def _map_vars_direct(self, dvs_dict_in: DesignSpace) -> DesignSpace:
86
+ """Map vars direct.
87
+
88
+ Args:
89
+ dvs_dict_in: The input design space.
90
+
91
+ Returns:
92
+ The output design space.
93
+ """
94
+ sub_dict_out = {
95
+ var_out: dvs_dict_in[var_in]
96
+ for var_out, var_in in self._vars_mapping.items()
97
+ }
98
+ dvs_dict_out = self.design_space_out.get_current_value(as_dict=True)
99
+ dvs_dict_out.update(sub_dict_out)
100
+ return dvs_dict_out
101
+
102
+ def _map_vars_reverse(self, dvs_dict_out: DesignSpace) -> DesignSpace:
103
+ """Map vars reverse.
104
+
105
+ Args:
106
+ dvs_dict_out: The output design space.
107
+
108
+ Returns:
109
+ The input design space.
110
+ """
111
+ return {
112
+ var_in: dvs_dict_out[var_out]
113
+ for var_out, var_in in self._vars_mapping.items()
114
+ }
115
+
116
+ def get_jac(self) -> NDArray:
117
+ """Get the jacobian.
118
+
119
+ Args:
120
+ The jacobian.
121
+ """
122
+ return {key: {val: array([[1.0]])} for key, val in self._vars_mapping.items()}
@@ -0,0 +1,16 @@
1
+ # Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 3 as published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public License
13
+ # along with this program; if not, write to the Free Software Foundation,
14
+ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15
+
16
+ """Rosenbrock test case for multi-fidelity."""