pyfemtet 1.0.0a0__py3-none-any.whl → 1.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.
Potentially problematic release.
This version of pyfemtet might be problematic. Click here for more details.
- pyfemtet/_i18n/locales/ja/LC_MESSAGES/messages.mo +0 -0
- pyfemtet/_i18n/locales/ja/LC_MESSAGES/messages.po +1 -1
- pyfemtet/_util/dask_util.py +1 -1
- pyfemtet/_util/df_util.py +18 -1
- pyfemtet/_util/helper.py +9 -0
- pyfemtet/opt/__init__.py +3 -1
- pyfemtet/opt/femopt.py +22 -3
- pyfemtet/opt/history/_history.py +21 -7
- pyfemtet/opt/interface/_excel_interface/excel_interface.py +0 -2
- pyfemtet/opt/interface/_femtet_interface/femtet_interface.py +24 -11
- pyfemtet/opt/interface/_femtet_with_nx_interface/femtet_with_nx_interface.py +1 -1
- pyfemtet/opt/interface/_femtet_with_solidworks/femtet_with_solidworks_interface.py +21 -1
- pyfemtet/opt/interface/_solidworks_interface/solidworks_interface.py +21 -0
- pyfemtet/opt/interface/_surrogate_model_interface/base_surrogate_interface.py +99 -8
- pyfemtet/opt/interface/_surrogate_model_interface/botorch_interface.py +30 -3
- pyfemtet/opt/optimizer/_base_optimizer.py +58 -23
- pyfemtet/opt/optimizer/optuna_optimizer/_optuna_attribute.py +47 -57
- pyfemtet/opt/optimizer/optuna_optimizer/_optuna_optimizer.py +138 -20
- pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/pof_botorch_sampler.py +4 -4
- pyfemtet/opt/optimizer/scipy_optimizer/_scipy_optimizer.py +19 -0
- pyfemtet/opt/problem/variable_manager/_variable_manager.py +84 -28
- {pyfemtet-1.0.0a0.dist-info → pyfemtet-1.0.1.dist-info}/METADATA +3 -2
- {pyfemtet-1.0.0a0.dist-info → pyfemtet-1.0.1.dist-info}/RECORD +27 -28
- pyfemtet/opt/interface/_surrogate/_base.py +0 -0
- {pyfemtet-1.0.0a0.dist-info → pyfemtet-1.0.1.dist-info}/LICENSE +0 -0
- {pyfemtet-1.0.0a0.dist-info → pyfemtet-1.0.1.dist-info}/LICENSE_THIRD_PARTY.txt +0 -0
- {pyfemtet-1.0.0a0.dist-info → pyfemtet-1.0.1.dist-info}/WHEEL +0 -0
- {pyfemtet-1.0.0a0.dist-info → pyfemtet-1.0.1.dist-info}/entry_points.txt +0 -0
|
@@ -32,7 +32,7 @@ DIRECTION: TypeAlias = (
|
|
|
32
32
|
]
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
-
logger = get_module_logger('opt.optimizer',
|
|
35
|
+
logger = get_module_logger('opt.optimizer', False)
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
def _log_hidden_constraint(e: Exception):
|
|
@@ -177,11 +177,14 @@ class AbstractOptimizer:
|
|
|
177
177
|
name: str,
|
|
178
178
|
expression_string: str,
|
|
179
179
|
properties: dict[str, ...] | None = None,
|
|
180
|
+
*,
|
|
181
|
+
pass_to_fem: bool = True,
|
|
180
182
|
) -> None:
|
|
181
183
|
var = ExpressionFromString()
|
|
182
184
|
var.name = name
|
|
183
185
|
var._expr = ExpressionFromString.InternalClass(expression_string=expression_string)
|
|
184
186
|
var.properties = properties or dict()
|
|
187
|
+
var.pass_to_fem = pass_to_fem
|
|
185
188
|
_duplicated_name_check(name, self.variable_manager.variables.keys())
|
|
186
189
|
self.variable_manager.variables.update({name: var})
|
|
187
190
|
|
|
@@ -190,11 +193,14 @@ class AbstractOptimizer:
|
|
|
190
193
|
name: str,
|
|
191
194
|
sympy_expr: sympy.Expr,
|
|
192
195
|
properties: dict[str, ...] | None = None,
|
|
196
|
+
*,
|
|
197
|
+
pass_to_fem: bool = True,
|
|
193
198
|
) -> None:
|
|
194
199
|
var = ExpressionFromString()
|
|
195
200
|
var.name = name
|
|
196
201
|
var._expr = ExpressionFromString.InternalClass(sympy_expr=sympy_expr)
|
|
197
202
|
var.properties = properties or dict()
|
|
203
|
+
var.pass_to_fem = pass_to_fem
|
|
198
204
|
_duplicated_name_check(name, self.variable_manager.variables.keys())
|
|
199
205
|
self.variable_manager.variables.update({name: var})
|
|
200
206
|
|
|
@@ -205,6 +211,8 @@ class AbstractOptimizer:
|
|
|
205
211
|
properties: dict[str, ...] | None = None,
|
|
206
212
|
args: tuple | None = None,
|
|
207
213
|
kwargs: dict | None = None,
|
|
214
|
+
*,
|
|
215
|
+
pass_to_fem: bool = True,
|
|
208
216
|
) -> None:
|
|
209
217
|
var = ExpressionFromFunction()
|
|
210
218
|
var.name = name
|
|
@@ -212,6 +220,7 @@ class AbstractOptimizer:
|
|
|
212
220
|
var.args = args or tuple()
|
|
213
221
|
var.kwargs = kwargs or dict()
|
|
214
222
|
var.properties = properties or dict()
|
|
223
|
+
var.pass_to_fem = pass_to_fem
|
|
215
224
|
_duplicated_name_check(name, self.variable_manager.variables.keys())
|
|
216
225
|
self.variable_manager.variables.update({name: var})
|
|
217
226
|
|
|
@@ -425,6 +434,7 @@ class AbstractOptimizer:
|
|
|
425
434
|
|
|
426
435
|
def __init__(self, opt: AbstractOptimizer):
|
|
427
436
|
self.opt: AbstractOptimizer = opt
|
|
437
|
+
self.subsampling_idx: SubSampling | None = None
|
|
428
438
|
|
|
429
439
|
def _preprocess(self):
|
|
430
440
|
pass
|
|
@@ -451,6 +461,7 @@ class AbstractOptimizer:
|
|
|
451
461
|
variables_pass_to_fem: dict[str, SupportedVariableTypes],
|
|
452
462
|
history: History = None,
|
|
453
463
|
datetime_start=None,
|
|
464
|
+
trial_id=None,
|
|
454
465
|
) -> _FReturnValue:
|
|
455
466
|
|
|
456
467
|
# create context
|
|
@@ -477,6 +488,8 @@ class AbstractOptimizer:
|
|
|
477
488
|
{obj_name: ObjectiveResult(obj, opt_.fem, float('nan'))
|
|
478
489
|
for obj_name, obj in opt_.objectives.items()}
|
|
479
490
|
)
|
|
491
|
+
record.sub_sampling = self.subsampling_idx
|
|
492
|
+
record.trial_id = trial_id
|
|
480
493
|
record.sub_fidelity_name = opt_.sub_fidelity_name
|
|
481
494
|
record.fidelity = opt_.fidelity
|
|
482
495
|
record.datetime_start = datetime_start
|
|
@@ -489,7 +502,8 @@ class AbstractOptimizer:
|
|
|
489
502
|
raise SkipSolve
|
|
490
503
|
|
|
491
504
|
# start solve
|
|
492
|
-
if opt_.
|
|
505
|
+
if opt_.sub_fidelity_name != MAIN_FIDELITY_NAME:
|
|
506
|
+
logger.info('----------')
|
|
493
507
|
logger.info(_('fidelity: ({name})', name=opt_.sub_fidelity_name))
|
|
494
508
|
logger.info(_('input variables:'))
|
|
495
509
|
logger.info(parameters)
|
|
@@ -620,7 +634,9 @@ class AbstractOptimizer:
|
|
|
620
634
|
x: TrialInput,
|
|
621
635
|
x_pass_to_fem_: dict[str, SupportedVariableTypes],
|
|
622
636
|
opt_: AbstractOptimizer | None = None,
|
|
637
|
+
trial_id: str =None,
|
|
623
638
|
) -> _FReturnValue | None:
|
|
639
|
+
"""Nothing will be raised even if infeasible."""
|
|
624
640
|
|
|
625
641
|
vm = self.opt.variable_manager
|
|
626
642
|
|
|
@@ -634,32 +650,40 @@ class AbstractOptimizer:
|
|
|
634
650
|
# if opt_ is not self, update variable manager
|
|
635
651
|
opt_.variable_manager = vm
|
|
636
652
|
|
|
637
|
-
#
|
|
638
|
-
|
|
653
|
+
# noinspection PyMethodParameters
|
|
654
|
+
class Process:
|
|
655
|
+
def __enter__(self_):
|
|
656
|
+
# preprocess
|
|
657
|
+
self._preprocess()
|
|
639
658
|
|
|
640
|
-
|
|
641
|
-
|
|
659
|
+
def __exit__(self_, exc_type, exc_val, exc_tb):
|
|
660
|
+
# postprocess
|
|
661
|
+
self._postprocess()
|
|
642
662
|
|
|
643
|
-
|
|
644
|
-
datetime_start = datetime.datetime.now()
|
|
645
|
-
try:
|
|
646
|
-
f_return = self._solve_or_raise(
|
|
647
|
-
opt_, x, x_pass_to_fem_, self.opt.history, datetime_start
|
|
648
|
-
)
|
|
663
|
+
with Process():
|
|
649
664
|
|
|
650
|
-
|
|
651
|
-
|
|
665
|
+
# declare output
|
|
666
|
+
f_return = None
|
|
652
667
|
|
|
653
|
-
|
|
654
|
-
|
|
668
|
+
# start solve
|
|
669
|
+
datetime_start = datetime.datetime.now()
|
|
670
|
+
try:
|
|
671
|
+
f_return = self._solve_or_raise(
|
|
672
|
+
opt_, x, x_pass_to_fem_, self.opt.history,
|
|
673
|
+
datetime_start, trial_id
|
|
674
|
+
)
|
|
655
675
|
|
|
656
|
-
|
|
657
|
-
|
|
676
|
+
except HardConstraintViolation as e:
|
|
677
|
+
self._hard_constraint_handling(e)
|
|
658
678
|
|
|
659
|
-
|
|
660
|
-
|
|
679
|
+
except _HiddenConstraintViolation as e:
|
|
680
|
+
self._hidden_constraint_handling(e)
|
|
661
681
|
|
|
662
|
-
|
|
682
|
+
except SkipSolve as e:
|
|
683
|
+
self._skip_handling(e)
|
|
684
|
+
|
|
685
|
+
else:
|
|
686
|
+
self._if_succeeded(f_return)
|
|
663
687
|
|
|
664
688
|
# check interruption
|
|
665
689
|
self.opt._check_and_raise_interruption()
|
|
@@ -790,8 +814,19 @@ class AbstractOptimizer:
|
|
|
790
814
|
# noinspection PyMethodParameters
|
|
791
815
|
class LoggingOutput:
|
|
792
816
|
def __enter__(self_):
|
|
793
|
-
|
|
794
|
-
|
|
817
|
+
df = self.history.get_df(
|
|
818
|
+
equality_filters=MAIN_FILTER
|
|
819
|
+
)
|
|
820
|
+
self_.count = len(df) + 1
|
|
821
|
+
|
|
822
|
+
succeeded_count = len(df[df['state'] == TrialState.succeeded])
|
|
823
|
+
succeeded_text = _(
|
|
824
|
+
en_message='{succeeded_count} succeeded trials',
|
|
825
|
+
jp_message='成功した試行数: {succeeded_count}',
|
|
826
|
+
succeeded_count=succeeded_count,
|
|
827
|
+
)
|
|
828
|
+
|
|
829
|
+
logger.info(f'▼▼▼▼▼ solve {self_.count} ({succeeded_text}) start ▼▼▼▼▼')
|
|
795
830
|
|
|
796
831
|
def __exit__(self_, exc_type, exc_val, exc_tb):
|
|
797
832
|
logger.info(f'▲▲▲▲▲ solve {self_.count} end ▲▲▲▲▲\n')
|
|
@@ -1,73 +1,63 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import TypedDict, Sequence
|
|
4
|
+
|
|
5
|
+
import optuna.trial
|
|
6
|
+
|
|
3
7
|
from pyfemtet.opt.problem.problem import *
|
|
4
8
|
from pyfemtet.opt.history import *
|
|
5
9
|
from pyfemtet.opt.optimizer._base_optimizer import *
|
|
6
10
|
|
|
7
11
|
|
|
8
12
|
class OptunaAttribute:
|
|
9
|
-
"""Manage optuna user attribute
|
|
13
|
+
"""Manage optuna user attribute.
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
By `set_user_attr_to_trial`,
|
|
16
|
+
key (str):
|
|
17
|
+
{sub_fidelity_name}(_{subsampling_idx})
|
|
18
|
+
value (dict):
|
|
13
19
|
fidelity: ...
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
internal_y_values: ...
|
|
21
|
+
violation_values: ...
|
|
22
|
+
pf_state: ...
|
|
17
23
|
|
|
18
24
|
"""
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
self.sub_fidelity_name = opt.sub_fidelity_name
|
|
32
|
-
self.
|
|
33
|
-
|
|
34
|
-
self.
|
|
35
|
-
self.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@classmethod
|
|
39
|
-
def main_fidelity_key(cls):
|
|
40
|
-
return MAIN_FIDELITY_NAME
|
|
25
|
+
class AttributeStructure(TypedDict):
|
|
26
|
+
fidelity: Fidelity | None
|
|
27
|
+
internal_y_values: Sequence[float] | None
|
|
28
|
+
violation_values: Sequence[float] | None
|
|
29
|
+
pf_state: TrialState | None
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
opt: AbstractOptimizer,
|
|
34
|
+
subsampling_idx: SubSampling | None = None,
|
|
35
|
+
):
|
|
36
|
+
# key
|
|
37
|
+
self.sub_fidelity_name: str = opt.sub_fidelity_name
|
|
38
|
+
self.subsampling_idx: SubSampling | None = subsampling_idx
|
|
39
|
+
# value
|
|
40
|
+
self.fidelity: Fidelity = opt.fidelity
|
|
41
|
+
self.y_values: Sequence[float] | None = None
|
|
42
|
+
self.v_values: Sequence[float] | None = None
|
|
43
|
+
self.pf_state: TrialState | None = None
|
|
41
44
|
|
|
42
45
|
@property
|
|
43
|
-
def key(self):
|
|
44
|
-
|
|
46
|
+
def key(self) -> str:
|
|
47
|
+
key = self.sub_fidelity_name
|
|
48
|
+
if self.subsampling_idx is not None:
|
|
49
|
+
key += f'_{self.subsampling_idx}'
|
|
50
|
+
return key
|
|
45
51
|
|
|
46
52
|
@property
|
|
47
|
-
def value(self):
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
@staticmethod
|
|
60
|
-
def get_fidelity(optuna_attribute: OptunaAttribute):
|
|
61
|
-
return optuna_attribute.value['fidelity']
|
|
62
|
-
|
|
63
|
-
@staticmethod
|
|
64
|
-
def get_violation(optuna_attribute: OptunaAttribute):
|
|
65
|
-
return optuna_attribute.value[OptunaAttribute.CONSTRAINT_KEY]
|
|
66
|
-
|
|
67
|
-
@staticmethod
|
|
68
|
-
def get_violation_from_trial_attr(trial_attr: dict): # value is OptunaAttribute.value
|
|
69
|
-
return trial_attr[OptunaAttribute.CONSTRAINT_KEY]
|
|
70
|
-
|
|
71
|
-
@staticmethod
|
|
72
|
-
def get_pf_state_from_trial_attr(trial_attr: dict): # value is OptunaAttribute.value
|
|
73
|
-
return trial_attr[OptunaAttribute.PYFEMTET_TRIAL_STATE_KEY]
|
|
53
|
+
def value(self) -> AttributeStructure:
|
|
54
|
+
out = self.AttributeStructure(
|
|
55
|
+
fidelity=self.fidelity,
|
|
56
|
+
internal_y_values=self.y_values,
|
|
57
|
+
violation_values=self.v_values,
|
|
58
|
+
pf_state=self.pf_state,
|
|
59
|
+
)
|
|
60
|
+
return out
|
|
61
|
+
|
|
62
|
+
def set_user_attr_to_trial(self, trial: optuna.trial.Trial):
|
|
63
|
+
trial.set_user_attr(self.key, self.value)
|
|
@@ -39,6 +39,37 @@ warnings.filterwarnings('ignore', 'Argument ``constraints_func`` is an experimen
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
class OptunaOptimizer(AbstractOptimizer):
|
|
42
|
+
"""
|
|
43
|
+
An optimizer class utilizing Optuna for hyperparameter optimization.
|
|
44
|
+
|
|
45
|
+
This class provides an interface to conduct optimization studies using Optuna.
|
|
46
|
+
It manages the study lifecycle, sampler configuration, and trial execution.
|
|
47
|
+
|
|
48
|
+
Attributes:
|
|
49
|
+
study_name (str): Name of the Optuna study.
|
|
50
|
+
storage (str | optuna.storages.BaseStorage): Storage URL or object for the Optuna study.
|
|
51
|
+
storage_path (str): Path to the Optuna study storage.
|
|
52
|
+
current_trial (optuna.trial.Trial | None): The current Optuna trial being evaluated.
|
|
53
|
+
sampler_class (type[optuna.samplers.BaseSampler]): The class of the Optuna sampler to use.
|
|
54
|
+
sampler_kwargs (dict): Keyword arguments to initialize the sampler.
|
|
55
|
+
n_trials (int | None): Number of trials to run in the study.
|
|
56
|
+
timeout (float | None): Maximum time allowed for the optimization.
|
|
57
|
+
callbacks (list): List of callback functions to invoke during optimization.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
sampler_class (type[optuna.samplers.BaseSampler], optional): The sampler class for suggesting parameter values. Defaults to TPESampler if None.
|
|
61
|
+
sampler_kwargs (dict[str, ...], optional): Dictionary of keyword arguments for the sampler. Defaults to an empty dictionary.
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
None
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
>>> optimizer = OptunaOptimizer()
|
|
68
|
+
>>> optimizer.n_trials = 100
|
|
69
|
+
>>> optimizer.timeout = 600
|
|
70
|
+
>>> # Further configuration and usage...
|
|
71
|
+
"""
|
|
72
|
+
|
|
42
73
|
# system
|
|
43
74
|
study_name = 'pyfemtet-study'
|
|
44
75
|
storage: str | optuna.storages.BaseStorage
|
|
@@ -122,7 +153,7 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
122
153
|
|
|
123
154
|
y, dict_y_internal, c, record = f_return
|
|
124
155
|
|
|
125
|
-
# convert constraint to **sorted** violation
|
|
156
|
+
# convert constraint to **sorted 1-d array** violation
|
|
126
157
|
assert len(c) == len(self.opt_.constraints)
|
|
127
158
|
v = {}
|
|
128
159
|
for cns_name, cns in self.opt_.constraints.items():
|
|
@@ -139,10 +170,7 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
139
170
|
|
|
140
171
|
def _postprocess(self):
|
|
141
172
|
# update trial attribute
|
|
142
|
-
self.opt.current_trial
|
|
143
|
-
self.optuna_attr.key,
|
|
144
|
-
self.optuna_attr.value,
|
|
145
|
-
)
|
|
173
|
+
self.optuna_attr.set_user_attr_to_trial(self.opt.current_trial)
|
|
146
174
|
|
|
147
175
|
def _create_infeasible_constraints(self, opt_: AbstractOptimizer = None) -> tuple:
|
|
148
176
|
opt_ = opt_ if opt_ is not None else self
|
|
@@ -155,9 +183,9 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
155
183
|
return tuple(1e9 * np.ones(count, dtype=np.float64))
|
|
156
184
|
|
|
157
185
|
def _constraint(self, trial: optuna.trial.FrozenTrial):
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return
|
|
186
|
+
main_key = OptunaAttribute(self).key
|
|
187
|
+
user_attribute: OptunaAttribute.AttributeStructure = trial.user_attrs[main_key]
|
|
188
|
+
return user_attribute['violation_values']
|
|
161
189
|
|
|
162
190
|
def _objective(self, trial: optuna.trial.Trial):
|
|
163
191
|
|
|
@@ -226,9 +254,9 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
226
254
|
|
|
227
255
|
# To avoid trial FAILED with hard constraint
|
|
228
256
|
# violation, check pf_state and raise TrialPruned.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
state =
|
|
257
|
+
main_key = OptunaAttribute(self).key
|
|
258
|
+
user_attribute: OptunaAttribute.AttributeStructure = trial.user_attrs[main_key]
|
|
259
|
+
state: TrialState = user_attribute['pf_state']
|
|
232
260
|
if state in [
|
|
233
261
|
TrialState.hard_constraint_violation,
|
|
234
262
|
TrialState.model_error,
|
|
@@ -245,9 +273,6 @@ class OptunaOptimizer(AbstractOptimizer):
|
|
|
245
273
|
|
|
246
274
|
return y_internal
|
|
247
275
|
|
|
248
|
-
if get_client() is None:
|
|
249
|
-
self.history.save()
|
|
250
|
-
|
|
251
276
|
def _get_callback(self, n_trials: int):
|
|
252
277
|
|
|
253
278
|
# restart である場合、追加 N 回と見做す
|
|
@@ -587,16 +612,16 @@ def debug_1():
|
|
|
587
612
|
_opt.add_parameter('x1', 1, -1, 1, step=0.1)
|
|
588
613
|
_opt.add_parameter('x2', 1, -1, 1, step=0.1)
|
|
589
614
|
_opt.add_categorical_parameter('x3', 'a', choices=['a', 'b', 'c'])
|
|
590
|
-
_opt.add_constraint('cns', _cns, lower_bound=-0.9, args=(
|
|
591
|
-
_opt.add_objective('obj1', _parabola, args=(
|
|
592
|
-
# _opt.add_objective('obj2', _parabola2, args=(
|
|
615
|
+
# _opt.add_constraint('cns', _cns, lower_bound=-0.9, args=(_opt,))
|
|
616
|
+
_opt.add_objective('obj1', _parabola, args=(_opt,))
|
|
617
|
+
# _opt.add_objective('obj2', _parabola2, args=(_opt,))
|
|
593
618
|
|
|
594
619
|
# # ===== sub-fidelity =====
|
|
595
620
|
# __fem = NoFEM()
|
|
596
621
|
# __opt = SubFidelityModel()
|
|
597
622
|
# __opt.fem = __fem
|
|
598
|
-
# __opt.add_objective('obj1', _parabola, args=(
|
|
599
|
-
# __opt.add_objective('obj2', _parabola2, args=(
|
|
623
|
+
# __opt.add_objective('obj1', _parabola, args=(__opt,))
|
|
624
|
+
# # __opt.add_objective('obj2', _parabola2, args=(__opt,))
|
|
600
625
|
#
|
|
601
626
|
# _opt.add_sub_fidelity_model(name='low-fidelity', sub_fidelity_model=__opt, fidelity=0.5)
|
|
602
627
|
#
|
|
@@ -622,6 +647,96 @@ def debug_1():
|
|
|
622
647
|
_opt.history.save()
|
|
623
648
|
|
|
624
649
|
|
|
650
|
+
def debug_1s():
|
|
651
|
+
# from pyfemtet.opt.optimizer.optuna_optimizer.pof_botorch.pof_botorch_sampler import
|
|
652
|
+
# sampler = PoFBoTorchSampler(
|
|
653
|
+
# n_startup_trials=5,
|
|
654
|
+
# seed=42,
|
|
655
|
+
# constraints_func=self._constraint,
|
|
656
|
+
# pof_config=PoFConfig(
|
|
657
|
+
# # consider_pof=False,
|
|
658
|
+
# # feasibility_cdf_threshold='mean',
|
|
659
|
+
# ),
|
|
660
|
+
# partial_optimize_acqf_kwargs=PartialOptimizeACQFConfig(
|
|
661
|
+
# # gen_candidates='scipy',
|
|
662
|
+
# timeout_sec=5.,
|
|
663
|
+
# # method='SLSQP' # 'COBYLA, COBYQA, SLSQP or trust-constr
|
|
664
|
+
# tol=0.1,
|
|
665
|
+
# # scipy_minimize_kwargs=dict(),
|
|
666
|
+
# ),
|
|
667
|
+
# )
|
|
668
|
+
# from optuna_integration import BoTorchSampler
|
|
669
|
+
# sampler = BoTorchSampler(n_startup_trials=5)
|
|
670
|
+
|
|
671
|
+
os.chdir(os.path.dirname(__file__))
|
|
672
|
+
|
|
673
|
+
def _parabola(_fem: AbstractFEMInterface, _opt: AbstractOptimizer) -> float:
|
|
674
|
+
d = _opt.get_variables()
|
|
675
|
+
x1 = d['x1']
|
|
676
|
+
x2 = d['x2']
|
|
677
|
+
# if _cns(_fem, _opt) < 0:
|
|
678
|
+
# raise PostProcessError
|
|
679
|
+
return x1 ** 2 + x2 ** 2
|
|
680
|
+
|
|
681
|
+
def _parabola2(_fem: AbstractFEMInterface, _opt: AbstractOptimizer) -> float:
|
|
682
|
+
x = _opt.get_variables('values')
|
|
683
|
+
return ((x - 0.1) ** 2).sum()
|
|
684
|
+
|
|
685
|
+
def _cns(_fem: AbstractFEMInterface, _opt: AbstractOptimizer) -> float:
|
|
686
|
+
x = _opt.get_variables('values')
|
|
687
|
+
return x[0]
|
|
688
|
+
|
|
689
|
+
_fem = NoFEM()
|
|
690
|
+
_opt = OptunaOptimizer()
|
|
691
|
+
_opt.fem = _fem
|
|
692
|
+
|
|
693
|
+
# _opt.sampler = optuna.samplers.RandomSampler(seed=42)
|
|
694
|
+
_opt.seed = 42
|
|
695
|
+
_opt.sampler_class = optuna.samplers.TPESampler
|
|
696
|
+
# _opt.sampler_class = optuna.samplers.RandomSampler
|
|
697
|
+
_opt.sampler_kwargs = dict(
|
|
698
|
+
n_startup_trials=5,
|
|
699
|
+
)
|
|
700
|
+
_opt.n_trials = 10
|
|
701
|
+
|
|
702
|
+
_opt.add_parameter('x1', 1, -1, 1, step=0.1)
|
|
703
|
+
_opt.add_parameter('x2', 1, -1, 1, step=0.1)
|
|
704
|
+
_opt.add_categorical_parameter('x3', 'a', choices=['a', 'b', 'c'])
|
|
705
|
+
# _opt.add_constraint('cns', _cns, lower_bound=-0.9, args=(_opt,))
|
|
706
|
+
_opt.add_objective('obj1', _parabola, args=(_opt,))
|
|
707
|
+
# _opt.add_objective('obj2', _parabola2, args=(_opt,))
|
|
708
|
+
|
|
709
|
+
# ===== sub-fidelity =====
|
|
710
|
+
__fem = NoFEM()
|
|
711
|
+
__opt = SubFidelityModel()
|
|
712
|
+
__opt.fem = __fem
|
|
713
|
+
__opt.add_objective('obj1', _parabola, args=(__opt,))
|
|
714
|
+
# __opt.add_objective('obj2', _parabola2, args=(__opt,))
|
|
715
|
+
|
|
716
|
+
_opt.add_sub_fidelity_model(name='low-fidelity', sub_fidelity_model=__opt, fidelity=0.5)
|
|
717
|
+
|
|
718
|
+
def _solve_condition(_history: History):
|
|
719
|
+
|
|
720
|
+
sub_fidelity_df = _history.get_df(
|
|
721
|
+
{'sub_fidelity_name': 'low-fidelity'}
|
|
722
|
+
)
|
|
723
|
+
idx = sub_fidelity_df['state'] == TrialState.succeeded
|
|
724
|
+
pdf = sub_fidelity_df[idx]
|
|
725
|
+
|
|
726
|
+
return len(pdf) % 5 == 0
|
|
727
|
+
|
|
728
|
+
_opt.set_solve_condition(_solve_condition)
|
|
729
|
+
|
|
730
|
+
# _opt.history.path = 'restart-test.csv'
|
|
731
|
+
_opt.run()
|
|
732
|
+
|
|
733
|
+
# import plotly.express as px
|
|
734
|
+
# _df = _opt.history.get_df()
|
|
735
|
+
# px.scatter_3d(_df, x='x1', y='x2', z='obj', color='fidelity', opacity=0.5).show()
|
|
736
|
+
|
|
737
|
+
_opt.history.save()
|
|
738
|
+
|
|
739
|
+
|
|
625
740
|
def substrate_size(Femtet):
|
|
626
741
|
"""基板のXY平面上での専有面積を計算します。"""
|
|
627
742
|
substrate_w = Femtet.GetVariableValue('substrate_w')
|
|
@@ -669,10 +784,13 @@ def debug_3():
|
|
|
669
784
|
opt.add_parameter(name="substrate_d", initial_value=60, lower_bound=34, upper_bound=60)
|
|
670
785
|
|
|
671
786
|
opt.n_trials = 5
|
|
672
|
-
opt.history.path = os.path.join(os.path.dirname(__file__), 'femtet-test.csv')
|
|
787
|
+
opt.history.path = os.path.join(os.path.dirname(__file__), 'femtet-test-2.csv')
|
|
673
788
|
|
|
674
789
|
opt.run()
|
|
675
790
|
|
|
676
791
|
|
|
677
792
|
if __name__ == '__main__':
|
|
793
|
+
debug_1()
|
|
794
|
+
debug_1s()
|
|
795
|
+
debug_2()
|
|
678
796
|
debug_3()
|
|
@@ -138,7 +138,7 @@ if TYPE_CHECKING:
|
|
|
138
138
|
# noinspection PyTypeChecker
|
|
139
139
|
_logger = get_logger(False)
|
|
140
140
|
|
|
141
|
-
DEBUG =
|
|
141
|
+
DEBUG = False
|
|
142
142
|
logger = get_module_logger('opt.PoFBoTorchSampler', DEBUG)
|
|
143
143
|
|
|
144
144
|
warnings.filterwarnings('ignore', category=InputDataWarning)
|
|
@@ -973,9 +973,9 @@ class PoFBoTorchSampler(BoTorchSampler):
|
|
|
973
973
|
feasible_trials: list[FrozenTrial] = []
|
|
974
974
|
infeasible_trials: list[FrozenTrial] = []
|
|
975
975
|
for trial in (completed_trials + pruned_trials):
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
976
|
+
main_key = OptunaAttribute(self.pyfemtet_optimizer).key
|
|
977
|
+
user_attribute: OptunaAttribute.AttributeStructure = trial.user_attrs[main_key]
|
|
978
|
+
state: PFTrialState = user_attribute['pf_state']
|
|
979
979
|
|
|
980
980
|
if state in self.pof_config._states_to_consider_pof:
|
|
981
981
|
infeasible_trials.append(trial)
|
|
@@ -36,6 +36,25 @@ class _ScipyCallback:
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
class ScipyOptimizer(AbstractOptimizer):
|
|
39
|
+
"""
|
|
40
|
+
Optimizer class that utilizes SciPy optimization methods.
|
|
41
|
+
|
|
42
|
+
This class serves as a wrapper around SciPy's optimization routines,
|
|
43
|
+
allowing customization of the optimization method, tolerance, and options.
|
|
44
|
+
It also provides mechanisms for handling constraints with enhancement and scaling.
|
|
45
|
+
|
|
46
|
+
Attributes:
|
|
47
|
+
method (str): The optimization method to use (e.g., 'BFGS', 'Nelder-Mead').
|
|
48
|
+
tol (float or None): Tolerance for termination.
|
|
49
|
+
options (dict): Additional options to pass to the SciPy optimizer.
|
|
50
|
+
constraint_enhancement (float): Small value added to enhance constraint handling.
|
|
51
|
+
constraint_scaling (float): Scaling factor applied to constraints.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
method (str): The optimization method to use (e.g., 'BFGS', 'Nelder-Mead').
|
|
55
|
+
tol (float or None): Tolerance for termination.
|
|
56
|
+
|
|
57
|
+
"""
|
|
39
58
|
|
|
40
59
|
_timeout: None = None
|
|
41
60
|
_n_trials: None = None
|