pyfemtet 0.5.3__py3-none-any.whl → 0.6.0__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.

Potentially problematic release.


This version of pyfemtet might be problematic. Click here for more details.

Files changed (62) hide show
  1. pyfemtet/__init__.py +1 -1
  2. pyfemtet/{message → _message}/locales/ja/LC_MESSAGES/messages.po +89 -77
  3. pyfemtet/{message → _message}/locales/messages.pot +88 -76
  4. pyfemtet/{message → _message}/messages.py +1 -1
  5. pyfemtet/_warning.py +23 -0
  6. pyfemtet/dispatch_extensions/__init__.py +12 -0
  7. pyfemtet/{dispatch_extensions.py → dispatch_extensions/_impl.py} +45 -43
  8. pyfemtet/logger/__init__.py +3 -0
  9. pyfemtet/{logger.py → logger/_impl.py} +12 -6
  10. pyfemtet/opt/__init__.py +3 -0
  11. pyfemtet/opt/_femopt.py +265 -68
  12. pyfemtet/opt/_femopt_core.py +111 -68
  13. pyfemtet/opt/_test_utils/record_history.py +1 -1
  14. pyfemtet/opt/interface/__init__.py +0 -1
  15. pyfemtet/opt/interface/_base.py +3 -3
  16. pyfemtet/opt/interface/_femtet.py +116 -59
  17. pyfemtet/opt/interface/_femtet_with_nx/_interface.py +35 -12
  18. pyfemtet/opt/interface/_femtet_with_sldworks.py +22 -2
  19. pyfemtet/opt/optimizer/__init__.py +5 -1
  20. pyfemtet/opt/optimizer/_base.py +81 -55
  21. pyfemtet/opt/optimizer/{_optuna_botorchsampler_parameter_constraint_helper.py → _optuna/_botorch_patch/enable_nonlinear_constraint.py} +10 -127
  22. pyfemtet/opt/optimizer/{_optuna.py → _optuna/_optuna.py} +122 -19
  23. pyfemtet/opt/optimizer/_optuna/_pof_botorch.py +1833 -0
  24. pyfemtet/opt/optimizer/_scipy.py +20 -5
  25. pyfemtet/opt/optimizer/_scipy_scalar.py +20 -5
  26. pyfemtet/opt/prediction/{base.py → _base.py} +3 -2
  27. pyfemtet/opt/prediction/single_task_gp.py +10 -5
  28. pyfemtet/opt/samples/femprj_sample/constrained_pipe.py +2 -2
  29. pyfemtet/opt/samples/femprj_sample/her_ex40_parametric.py +2 -2
  30. pyfemtet/opt/visualization/{base.py → _base.py} +1 -1
  31. pyfemtet/opt/visualization/{complex_components → _complex_components}/alert_region.py +2 -2
  32. pyfemtet/opt/visualization/{complex_components → _complex_components}/control_femtet.py +3 -3
  33. pyfemtet/opt/visualization/{complex_components → _complex_components}/main_figure_creator.py +1 -1
  34. pyfemtet/opt/visualization/{complex_components → _complex_components}/main_graph.py +5 -5
  35. pyfemtet/opt/visualization/{complex_components → _complex_components}/pm_graph.py +5 -5
  36. pyfemtet/opt/visualization/{complex_components → _complex_components}/pm_graph_creator.py +2 -2
  37. pyfemtet/opt/visualization/_create_wrapped_components.py +2 -2
  38. pyfemtet/opt/visualization/_process_monitor/__init__.py +0 -0
  39. pyfemtet/opt/visualization/{process_monitor → _process_monitor}/application.py +3 -3
  40. pyfemtet/opt/visualization/{process_monitor → _process_monitor}/pages.py +10 -10
  41. pyfemtet/opt/visualization/_wrapped_components/__init__.py +0 -0
  42. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/dbc.py +1 -1
  43. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/dcc.py +1 -1
  44. pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/html.py +1 -1
  45. pyfemtet/opt/visualization/result_viewer/application.py +4 -4
  46. pyfemtet/opt/visualization/result_viewer/pages.py +9 -9
  47. {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/METADATA +2 -2
  48. {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/RECORD +60 -56
  49. {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/WHEEL +1 -1
  50. pyfemtet/message/locales/ja/LC_MESSAGES/messages.mo +0 -0
  51. pyfemtet/opt/samples/femprj_sample/.gitignore +0 -2
  52. /pyfemtet/{message → _message}/1. make_pot.bat +0 -0
  53. /pyfemtet/{message → _message}/2. make_mo.bat +0 -0
  54. /pyfemtet/{message → _message}/__init__.py +0 -0
  55. /pyfemtet/{message → _message}/babel.cfg +0 -0
  56. /pyfemtet/opt/{visualization/complex_components → optimizer/_optuna}/__init__.py +0 -0
  57. /pyfemtet/opt/{visualization/process_monitor → optimizer/_optuna/_botorch_patch}/__init__.py +0 -0
  58. /pyfemtet/opt/{parameter.py → optimizer/parameter.py} +0 -0
  59. /pyfemtet/opt/visualization/{wrapped_components → _complex_components}/__init__.py +0 -0
  60. /pyfemtet/opt/visualization/{wrapped_components → _wrapped_components}/str_enum.py +0 -0
  61. {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/LICENSE +0 -0
  62. {pyfemtet-0.5.3.dist-info → pyfemtet-0.6.0.dist-info}/entry_points.txt +0 -0
@@ -10,10 +10,30 @@ from pythoncom import CoInitialize, CoUninitialize
10
10
 
11
11
  from pyfemtet.core import ModelError
12
12
  from pyfemtet.opt.interface import FemtetInterface, logger
13
- from pyfemtet.message import Msg
13
+ from pyfemtet._message import Msg
14
14
 
15
15
 
16
16
  class FemtetWithSolidworksInterface(FemtetInterface):
17
+ """Control Femtet and Solidworks.
18
+
19
+ Using this class, you can import CAD files created
20
+ in Solidworks through the Parasolid format into a
21
+ Femtet project. It allows you to pass design
22
+ variables to Solidworks, update the model, and
23
+ perform analysis using the updated model in Femtet.
24
+
25
+
26
+ Args:
27
+ sldprt_path (str):
28
+ The path to .sldprt file containing the
29
+ CAD data from which the import is made.
30
+ **kwargs:
31
+ For other arguments, please refer to the
32
+ :class:`FemtetInterface` class.
33
+
34
+ """
35
+
36
+
17
37
  # 定数の宣言
18
38
  swThisConfiguration = 1 # https://help.solidworks.com/2023/english/api/swconst/SOLIDWORKS.Interop.swconst~SOLIDWORKS.Interop.swconst.swInConfigurationOpts_e.html
19
39
  swAllConfiguration = 2
@@ -76,7 +96,7 @@ class FemtetWithSolidworksInterface(FemtetInterface):
76
96
  CoInitialize()
77
97
  self.initialize_sldworks_connection()
78
98
 
79
- def update_model(self, parameters: pd.DataFrame):
99
+ def update_model(self, parameters: pd.DataFrame, with_warning=False):
80
100
  """Update .x_t"""
81
101
 
82
102
  self.parameters = parameters.copy()
@@ -1,12 +1,16 @@
1
1
  from pyfemtet.opt.optimizer._base import AbstractOptimizer, logger, OptimizationMethodChecker
2
- from pyfemtet.opt.optimizer._optuna import OptunaOptimizer
2
+ from pyfemtet.opt.optimizer._optuna._optuna import OptunaOptimizer
3
3
  from pyfemtet.opt.optimizer._scipy import ScipyOptimizer
4
4
  from pyfemtet.opt.optimizer._scipy_scalar import ScipyScalarOptimizer
5
5
 
6
+ from pyfemtet.opt.optimizer._optuna._pof_botorch import PoFBoTorchSampler, PoFConfig
7
+
6
8
  __all__ = [
7
9
  'ScipyScalarOptimizer',
8
10
  'ScipyOptimizer',
9
11
  'OptunaOptimizer',
10
12
  'AbstractOptimizer',
11
13
  'logger',
14
+ 'PoFBoTorchSampler',
15
+ 'PoFConfig',
12
16
  ]
@@ -8,13 +8,12 @@ from time import sleep
8
8
 
9
9
  # 3rd-party
10
10
  import numpy as np
11
- import pandas as pd
12
11
 
13
12
  # pyfemtet relative
14
- from pyfemtet.opt.interface import FemtetInterface
13
+ from pyfemtet.opt.interface import FEMInterface
15
14
  from pyfemtet.opt._femopt_core import OptimizationStatus, Objective, Constraint
16
- from pyfemtet.message import Msg
17
- from pyfemtet.opt.parameter import ExpressionEvaluator
15
+ from pyfemtet._message import Msg
16
+ from pyfemtet.opt.optimizer.parameter import ExpressionEvaluator, Parameter
18
17
 
19
18
  # logger
20
19
  import logging
@@ -117,17 +116,11 @@ class AbstractOptimizer(ABC):
117
116
  fem (FEMInterface): The finite element method object.
118
117
  fem_class (type): The class of the finite element method object.
119
118
  fem_kwargs (dict): The keyword arguments used to instantiate the finite element method object.
120
- parameters (pd.DataFrame): The parameters used in the optimization.
121
- objectives (dict): A dictionary containing the objective functions used in the optimization.
122
- constraints (dict): A dictionary containing the constraint functions used in the optimization.
123
- entire_status (OptimizationStatus): The status of the entire optimization process.
119
+ variables (ExpressionEvaluator): The variables using optimization process including parameters.
120
+ objectives (dict[str, Objective]): A dictionary containing the objective functions used in the optimization.
121
+ constraints (dict[str, Constraint]): A dictionary containing the constraint functions used in the optimization.
124
122
  history (History): An actor object that records the history of each iteration in the optimization process.
125
- worker_status (OptimizationStatus): The status of each worker in a distributed computing environment.
126
- message (str): A message associated with the current state of the optimization process.
127
123
  seed (int or None): The random seed used for random number generation during the optimization process.
128
- timeout (float or int or None): The maximum time allowed for each iteration of the optimization process. If exceeded, it will be interrupted and terminated early.
129
- n_trials (int or None): The maximum number of trials allowed for each iteration of the optimization process. If exceeded, it will be interrupted and terminated early.
130
- is_cluster (bool): Flag indicating if running on a distributed computing cluster.
131
124
 
132
125
  """
133
126
 
@@ -149,23 +142,46 @@ class AbstractOptimizer(ABC):
149
142
  self.subprocess_idx = None
150
143
  self._exception = None
151
144
  self.method_checker: OptimizationMethodChecker = OptimizationMethodChecker(self)
145
+ self._retry_counter = 0
146
+
147
+ # ===== algorithm specific methods =====
148
+ @abstractmethod
149
+ def run(self) -> None:
150
+ """Start optimization."""
151
+ pass
152
+
153
+ # ----- FEMOpt interfaces -----
154
+ @abstractmethod
155
+ def _setup_before_parallel(self, *args, **kwargs):
156
+ """Setup before parallel processes are launched."""
157
+ pass
158
+
159
+ # ===== calc =====
160
+ def f(self, x: np.ndarray) -> list[np.ndarray]:
161
+ """Calculate objectives and constraints.
162
+
163
+ Args:
164
+ x (np.ndarray): Optimization parameters.
165
+
166
+ Returns:
167
+ list[np.ndarray]:
168
+ The list of internal objective values,
169
+ un-normalized objective values and
170
+ constraint values.
171
+
172
+ """
152
173
 
153
- def f(self, x):
154
- """Get x, update fem analysis, return objectives (and constraints)."""
155
- # interruption の実装は具象クラスに任せる
156
174
 
157
175
  if isinstance(x, np.float64):
158
176
  x = np.array([x])
159
177
 
160
178
  # Optimizer の x の更新
161
179
  self.set_parameter_values(x)
162
-
163
- logger.info('---------------------')
164
180
  logger.info(f'input: {x}')
165
181
 
166
182
  # FEM の更新
167
- logger.debug('fem.update() start')
168
183
  try:
184
+ logger.info(f'Solving FEM...')
169
185
  df_to_fem = self.variables.get_variables(
170
186
  format='df',
171
187
  filter_pass_to_fem=True
@@ -176,25 +192,20 @@ class AbstractOptimizer(ABC):
176
192
  logger.info(f'{type(e).__name__} : {e}')
177
193
  logger.info(Msg.INFO_EXCEPTION_DURING_FEM_ANALYSIS)
178
194
  logger.info(x)
179
- raise e # may be just a ModelError, etc.
195
+ raise e # may be just a ModelError, etc. Handling them in Concrete classes.
180
196
 
181
197
  # y, _y, c の更新
182
- logger.debug('calculate y start')
183
198
  y = [obj.calc(self.fem) for obj in self.objectives.values()]
184
199
 
185
- logger.debug('calculate _y start')
186
200
  _y = [obj.convert(value) for obj, value in zip(self.objectives.values(), y)]
187
201
 
188
- logger.debug('calculate c start')
189
202
  c = [cns.calc(self.fem) for cns in self.constraints.values()]
190
203
 
191
- logger.debug('history.record start')
192
-
204
+ # register to history
193
205
  df_to_opt = self.variables.get_variables(
194
206
  format='df',
195
207
  filter_parameter=True,
196
208
  )
197
-
198
209
  self.history.record(
199
210
  df_to_opt,
200
211
  self.objectives,
@@ -202,36 +213,29 @@ class AbstractOptimizer(ABC):
202
213
  y,
203
214
  c,
204
215
  self.message,
205
- postprocess_func=self.fem.postprocess_func,
206
- postprocess_args=self.fem.create_postprocess_args(),
216
+ postprocess_func=self.fem._postprocess_func,
217
+ postprocess_args=self.fem._create_postprocess_args(),
207
218
  )
208
219
 
209
- logger.debug('history.record end')
210
-
211
- logger.info(f'output: {_y}')
220
+ logger.info(f'output: {y}')
212
221
 
213
222
  return np.array(y), np.array(_y), np.array(c)
214
223
 
215
- def _reconstruct_fem(self, skip_reconstruct=False):
216
- """Reconstruct FEMInterface in a subprocess."""
217
- # reconstruct fem
218
- if not skip_reconstruct:
219
- self.fem = self.fem_class(**self.fem_kwargs)
220
-
221
- # COM 定数の restore
222
- for obj in self.objectives.values():
223
- obj._restore_constants()
224
- for cns in self.constraints.values():
225
- cns._restore_constants()
226
-
224
+ # ===== parameter processing =====
227
225
  def get_parameter(self, format='dict'):
228
226
  """Returns the parameters in the specified format.
229
227
 
230
228
  Args:
231
- format (str, optional): The desired format of the parameters. Can be 'df' (DataFrame), 'value' (alias of values), 'values' (np.ndarray), or 'dict'. Defaults to 'dict'.
229
+ format (str, optional):
230
+ The desired format of the parameters.
231
+ Can be 'df' (DataFrame),
232
+ 'values' (np.ndarray),
233
+ 'dict' or
234
+ 'raw' (list of Variable object).
235
+ Defaults to 'dict'.
232
236
 
233
237
  Returns:
234
- object: The parameters in the specified format.
238
+ The parameters in the specified format.
235
239
 
236
240
  Raises:
237
241
  ValueError: If an invalid format is provided.
@@ -239,11 +243,14 @@ class AbstractOptimizer(ABC):
239
243
  """
240
244
  return self.variables.get_variables(format=format, filter_parameter=True)
241
245
 
242
- def set_parameter(self, params: dict) -> None:
246
+ def set_parameter(self, params: dict[str, float]) -> None:
243
247
  """Update parameter.
244
248
 
245
249
  Args:
246
- params (dict): Key is the name of parameter and the value is the value of it. The partial set is available.
250
+ params (dict):
251
+ Key is the name of parameter and
252
+ the value is the value of it.
253
+ The partial set is available.
247
254
 
248
255
  """
249
256
  for name, value in params.items():
@@ -255,11 +262,25 @@ class AbstractOptimizer(ABC):
255
262
 
256
263
  Args:
257
264
  values (np.ndarray): Values of all parameters.
265
+
258
266
  """
259
267
  prm_names = self.variables.get_parameter_names()
260
268
  assert len(values) == len(prm_names)
261
269
  self.set_parameter({k: v for k, v in zip(prm_names, values)})
262
270
 
271
+ # ===== FEMOpt interfaces =====
272
+ def _reconstruct_fem(self, skip_reconstruct=False):
273
+ """Reconstruct FEMInterface in a subprocess."""
274
+ # reconstruct fem
275
+ if not skip_reconstruct:
276
+ self.fem = self.fem_class(**self.fem_kwargs)
277
+
278
+ # COM 定数の restore
279
+ for obj in self.objectives.values():
280
+ obj._restore_constants()
281
+ for cns in self.constraints.values():
282
+ cns._restore_constants()
283
+
263
284
  def _check_interruption(self):
264
285
  """"""
265
286
  if self.entire_status.get() == OptimizationStatus.INTERRUPTING:
@@ -275,6 +296,7 @@ class AbstractOptimizer(ABC):
275
296
  if not self.worker_status.get() == OptimizationStatus.CRASHED:
276
297
  self.worker_status.set(OptimizationStatus.TERMINATED)
277
298
 
299
+ # run via FEMOpt (considering parallel processing)
278
300
  def _run(
279
301
  self,
280
302
  subprocess_idx,
@@ -331,12 +353,16 @@ class AbstractOptimizer(ABC):
331
353
 
332
354
  return self._exception
333
355
 
334
- @abstractmethod
335
- def run(self) -> None:
336
- """Start calculation using optimization library."""
337
- pass
338
356
 
339
- @abstractmethod
340
- def _setup_before_parallel(self, *args, **kwargs):
341
- """Setup before parallel processes are launched."""
342
- pass
357
+ if __name__ == '__main__':
358
+ class Optimizer(AbstractOptimizer):
359
+ def run(self): pass
360
+ def _setup_before_parallel(self, *args, **kwargs): pass
361
+
362
+ opt = Optimizer()
363
+ opt.set_parameter(
364
+ dict(
365
+ prm1=0.,
366
+ prm2=1.,
367
+ )
368
+ )
@@ -15,48 +15,14 @@ from botorch.optim.initializers import gen_batch_initial_conditions
15
15
 
16
16
  from pyfemtet.opt._femopt_core import Constraint
17
17
  from pyfemtet.opt.optimizer import OptunaOptimizer, logger
18
- from pyfemtet.message import Msg
18
+ from pyfemtet._message import Msg
19
19
 
20
- from time import time
21
-
22
-
23
- __all__ = ['do_patch']
24
20
 
25
21
 
26
22
  BotorchConstraint = Callable[[Tensor], Tensor]
27
23
 
28
24
 
29
- def do_patch(
30
- study: Study,
31
- constraints: dict[str, Constraint],
32
- opt: OptunaOptimizer,
33
- ):
34
- """BoTorchSampler の optimize_acqf をパッチし、パラメータ拘束が実施できるようにします。
35
-
36
- Args:
37
- study (Study): Optuna study. Use to calculate bounds.
38
- constraints (dict[str, Constraint]): Constraints.
39
- opt (OptunaOptimizer): OptunaOptimizer.
40
- """
41
- import optuna_integration
42
-
43
- from optuna_integration import version
44
- if int(version.__version__.split('.')[0]) >= 4:
45
- target_fun = optuna_integration.botorch.botorch.optimize_acqf
46
- else:
47
- target_fun = optuna_integration.botorch.optimize_acqf
48
-
49
- new_fun: callable = OptimizeReplacedACQF(target_fun)
50
- new_fun.set_constraints(list(constraints.values()))
51
- new_fun.set_study(study)
52
- new_fun.set_opt(opt)
53
-
54
- if int(version.__version__.split('.')[0]) >= 4:
55
- optuna_integration.botorch.botorch.optimize_acqf = new_fun
56
- else:
57
- optuna_integration.botorch.optimize_acqf = new_fun
58
-
59
-
25
+ # 拘束関数に pytorch の自動微分機能を適用するためのクラス
60
26
  class GeneralFunctionWithForwardDifference(torch.autograd.Function):
61
27
  """自作関数を pytorch で自動微分するためのクラスです。
62
28
 
@@ -85,6 +51,8 @@ class GeneralFunctionWithForwardDifference(torch.autograd.Function):
85
51
  return None, diff
86
52
 
87
53
 
54
+ # ユーザー定義関数 (pyfemtet.opt.Constraint) を受け取り、
55
+ # botorch で処理できる callable オブジェクトを作成するクラス
88
56
  class ConvertedConstraint:
89
57
  """ユーザーが定義した Constraint を botorch で処理できる形式に変換します。
90
58
 
@@ -116,6 +84,7 @@ class ConvertedConstraint:
116
84
  return Tensor([self._constraint.ub - c])
117
85
 
118
86
 
87
+ # list[pyfemtet.opt.Constraint] について、正規化された入力に対し、 feasible or not を返す関数
119
88
  def is_feasible(study: Study, constraints: list[Constraint], norm_x: np.ndarray, opt: OptunaOptimizer) -> bool:
120
89
  feasible = True
121
90
  cns: Constraint
@@ -132,6 +101,7 @@ def is_feasible(study: Study, constraints: list[Constraint], norm_x: np.ndarray,
132
101
  return feasible
133
102
 
134
103
 
104
+ # 正規化された入力を受けて pyfemtet.opt.Constraint を評価する関数
135
105
  def evaluate_pyfemtet_cns(study: Study, cns: Constraint, norm_x: np.ndarray, opt: OptunaOptimizer) -> float:
136
106
  """Evaluate given constraint function by given NORMALIZED x.
137
107
 
@@ -163,6 +133,9 @@ def evaluate_pyfemtet_cns(study: Study, cns: Constraint, norm_x: np.ndarray, opt
163
133
  return cns.calc(opt.fem)
164
134
 
165
135
 
136
+ # botorch の optimize_acqf で非線形拘束を使えるようにするクラス。以下を備える。
137
+ # - 渡すパラメータ nonlinear_constraints を作成する
138
+ # - gen_initial_conditions で feasible なものを返すラッパー関数
166
139
  class NonlinearInequalityConstraints:
167
140
  """botorch の optimize_acqf に parameter constraints を設定するための引数を作成します。"""
168
141
 
@@ -191,7 +164,7 @@ class NonlinearInequalityConstraints:
191
164
  feasible_q_list = []
192
165
  for each_q in each_num_restarts:
193
166
  norm_x: np.ndarray = each_q.numpy() # normalized parameters
194
-
167
+
195
168
  if is_feasible(self._study, self._constraints, norm_x, self._opt):
196
169
  feasible_q_list.append(each_q) # Keep only feasible rows
197
170
 
@@ -242,93 +215,3 @@ class NonlinearInequalityConstraints:
242
215
  nonlinear_inequality_constraints=self._nonlinear_inequality_constraints,
243
216
  ic_generator=self._generate_feasible_initial_conditions,
244
217
  )
245
-
246
-
247
- class AcquisitionFunctionWithPenalty(AcquisitionFunction):
248
- """獲得関数に infeasible 項を追加します。"""
249
-
250
- # noinspection PyAttributeOutsideInit
251
- def set_acqf(self, acqf):
252
- self._acqf = acqf
253
-
254
- # noinspection PyAttributeOutsideInit
255
- def set_constraints(self, constraints: list[Constraint]):
256
- self._constraints: list[Constraint] = constraints
257
-
258
- # noinspection PyAttributeOutsideInit
259
- def set_study(self, study: Study):
260
- self._study: Study = study
261
-
262
- # noinspection PyAttributeOutsideInit
263
- def set_opt(self, opt: OptunaOptimizer):
264
- self._opt = opt
265
-
266
- def forward(self, X: "Tensor") -> "Tensor":
267
- """
268
-
269
- Args:
270
- X (Tensor): batch_size x 1 x n_params tensor.
271
-
272
- Returns:
273
- Tensor: batch_size tensor.
274
-
275
- """
276
- base = self._acqf.forward(X)
277
-
278
- norm_x: np.ndarray
279
- for i, _norm_x in enumerate(X.detach().numpy()):
280
-
281
- cns: Constraint
282
- for cns in self._constraints:
283
- feasible = is_feasible(self._study, [cns], _norm_x[0], self._opt)
284
- if not feasible:
285
- base[i] = base[i] * 0. # ペナルティ
286
- break
287
-
288
- return base
289
-
290
-
291
- class OptimizeReplacedACQF(partial):
292
- """optimize_acqf をこの partial 関数に置き換えます。"""
293
-
294
- # noinspection PyAttributeOutsideInit
295
- def set_constraints(self, constraints: list[Constraint]):
296
- self._constraints: list[Constraint] = constraints
297
-
298
- # noinspection PyAttributeOutsideInit
299
- def set_study(self, study: Study):
300
- self._study: Study = study
301
-
302
- # noinspection PyAttributeOutsideInit
303
- def set_opt(self, opt: OptunaOptimizer):
304
- self._opt = opt
305
-
306
- def __call__(self, *args, **kwargs):
307
- """置き換え先の関数の処理内容です。
308
-
309
- kwargs を横入りして追記することで拘束を実現します。
310
- """
311
-
312
- logger.info(Msg.START_CANDIDATE_WITH_PARAMETER_CONSTRAINT)
313
-
314
- # FEM の更新が必要な場合、時間がかかることが多いので警告を出す
315
- if any([cns.using_fem for cns in self._constraints]):
316
- logger.warning(Msg.WARN_UPDATE_FEM_PARAMETER_TOOK_A_LONG_TIME)
317
-
318
- # 獲得関数に infeasible な場合のペナルティ項を追加します。
319
- acqf = kwargs['acq_function']
320
- new_acqf = AcquisitionFunctionWithPenalty(...)
321
- new_acqf.set_acqf(acqf)
322
- new_acqf.set_constraints(self._constraints)
323
- new_acqf.set_study(self._study)
324
- new_acqf.set_opt(self._opt)
325
- kwargs['acq_function'] = new_acqf
326
-
327
- # optimize_acqf の探索に parameter constraints を追加します。
328
- nlic = NonlinearInequalityConstraints(self._study, self._constraints, self._opt)
329
- kwargs.update(nlic.create_kwargs())
330
-
331
- # replace other arguments
332
- ...
333
-
334
- return super().__call__(*args, **kwargs)