pyfemtet 0.9.5__py3-none-any.whl → 1.0.0b0__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/__init__.py +6 -1
- pyfemtet/_i18n/1. make_pot_and_update_po.bat +8 -0
- pyfemtet/_i18n/2. build_mo.bat +5 -0
- pyfemtet/_i18n/__init__.py +4 -0
- pyfemtet/_i18n/babel.cfg +2 -0
- pyfemtet/_i18n/i18n.py +37 -0
- pyfemtet/_i18n/locales/ja/LC_MESSAGES/messages.mo +0 -0
- pyfemtet/_i18n/locales/ja/LC_MESSAGES/messages.po +1020 -0
- pyfemtet/_i18n/locales/messages.pot +987 -0
- pyfemtet/{_message → _i18n}/messages.py +128 -41
- pyfemtet/_util/closing.py +19 -0
- pyfemtet/_util/dask_util.py +89 -7
- pyfemtet/_util/df_util.py +29 -0
- pyfemtet/_util/excel_macro_util.py +8 -3
- pyfemtet/_util/excel_parse_util.py +43 -23
- pyfemtet/_util/femtet_access_inspection.py +120 -0
- pyfemtet/{_femtet_config_util/autosave.py → _util/femtet_autosave.py} +7 -0
- pyfemtet/_util/femtet_exit.py +105 -0
- pyfemtet/_util/femtet_version.py +20 -0
- pyfemtet/_util/helper.py +94 -0
- pyfemtet/_util/process_util.py +107 -0
- pyfemtet/_util/str_enum.py +44 -0
- pyfemtet/core.py +15 -47
- pyfemtet/dispatch_extensions/__init__.py +8 -11
- pyfemtet/dispatch_extensions/_impl.py +42 -198
- pyfemtet/logger/__init__.py +8 -1
- pyfemtet/logger/_impl.py +5 -6
- pyfemtet/opt/__init__.py +3 -17
- pyfemtet/opt/exceptions.py +45 -0
- pyfemtet/opt/femopt.py +608 -0
- pyfemtet/opt/history/__init__.py +11 -0
- pyfemtet/opt/history/_history.py +1404 -0
- pyfemtet/opt/history/_hypervolume.py +169 -0
- pyfemtet/opt/history/_optimality.py +79 -0
- pyfemtet/opt/interface/__init__.py +17 -24
- pyfemtet/opt/interface/_base_interface.py +222 -0
- pyfemtet/opt/interface/_excel_interface/__init__.py +3 -0
- pyfemtet/opt/interface/_excel_interface/debug-excel-interface.xlsm +0 -0
- pyfemtet/opt/interface/_excel_interface/excel_interface.py +999 -0
- pyfemtet/opt/interface/_femtet_interface/__init__.py +3 -0
- pyfemtet/opt/interface/{_femtet_parametric.py → _femtet_interface/_femtet_parametric.py} +20 -12
- pyfemtet/opt/interface/{_femtet.py → _femtet_interface/femtet_interface.py} +505 -349
- pyfemtet/opt/interface/_femtet_with_nx_interface/__init__.py +5 -0
- pyfemtet/opt/interface/_femtet_with_nx_interface/femtet_with_nx_interface.py +230 -0
- pyfemtet/opt/interface/_femtet_with_nx_interface/model1.prt +0 -0
- pyfemtet/opt/interface/_femtet_with_nx_interface/model1.x_t +98 -0
- pyfemtet/opt/interface/{_femtet_with_nx → _femtet_with_nx_interface}/update_model.py +1 -3
- pyfemtet/opt/interface/_femtet_with_solidworks/__init__.py +5 -0
- pyfemtet/opt/interface/_femtet_with_solidworks/femtet_with_solidworks_interface.py +122 -0
- pyfemtet/opt/interface/_solidworks_interface/__init__.py +5 -0
- pyfemtet/opt/interface/_solidworks_interface/solidworks_interface.py +206 -0
- pyfemtet/opt/interface/_surrogate_model_interface/__init__.py +8 -0
- pyfemtet/opt/interface/_surrogate_model_interface/base_surrogate_interface.py +150 -0
- pyfemtet/opt/interface/_surrogate_model_interface/botorch_interface.py +298 -0
- pyfemtet/opt/interface/_surrogate_model_interface/debug-pof-botorch.reccsv +18 -0
- pyfemtet/opt/interface/_with_excel_settings/__init__.py +61 -0
- pyfemtet/opt/interface/_with_excel_settings/with_excel_settings.py +134 -0
- pyfemtet/opt/meta_script/YAML_Generator.xlsm +0 -0
- pyfemtet/opt/meta_script/__main__.py +58 -36
- pyfemtet/opt/optimizer/__init__.py +7 -9
- pyfemtet/opt/optimizer/_base_optimizer.py +885 -0
- pyfemtet/opt/optimizer/optuna_optimizer/__init__.py +9 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_optuna_attribute.py +73 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_optuna_optimizer.py +678 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/__init__.py +7 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/debug-pof-botorch.reccsv +18 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/enable_nonlinear_constraint.py +244 -0
- pyfemtet/opt/optimizer/optuna_optimizer/_pof_botorch/pof_botorch_sampler.py +1249 -0
- pyfemtet/opt/optimizer/optuna_optimizer/wat_ex14_parametric_jp.femprj +0 -0
- pyfemtet/opt/optimizer/scipy_optimizer/__init__.py +1 -0
- pyfemtet/opt/optimizer/scipy_optimizer/_scipy_optimizer.py +364 -0
- pyfemtet/opt/prediction/__init__.py +7 -0
- pyfemtet/opt/prediction/_botorch_utils.py +133 -0
- pyfemtet/opt/prediction/_gpytorch_modules_extension.py +142 -0
- pyfemtet/opt/prediction/_helper.py +155 -0
- pyfemtet/opt/prediction/_model.py +118 -0
- pyfemtet/opt/problem/problem.py +304 -0
- pyfemtet/opt/problem/variable_manager/__init__.py +20 -0
- pyfemtet/opt/problem/variable_manager/_string_as_expression.py +115 -0
- pyfemtet/opt/problem/variable_manager/_variable_manager.py +295 -0
- pyfemtet/opt/visualization/history_viewer/__main__.py +5 -0
- pyfemtet/opt/visualization/{_base.py → history_viewer/_base_application.py} +18 -13
- pyfemtet/opt/visualization/history_viewer/_common_pages.py +150 -0
- pyfemtet/opt/visualization/{_complex_components → history_viewer/_complex_components}/alert_region.py +10 -5
- pyfemtet/opt/visualization/{_complex_components → history_viewer/_complex_components}/control_femtet.py +16 -13
- pyfemtet/opt/visualization/{_complex_components → history_viewer/_complex_components}/main_graph.py +117 -47
- pyfemtet/opt/visualization/{_complex_components → history_viewer/_complex_components}/pm_graph.py +159 -138
- pyfemtet/opt/visualization/history_viewer/_process_monitor/_application.py +173 -0
- pyfemtet/opt/visualization/history_viewer/_process_monitor/_pages.py +291 -0
- pyfemtet/opt/visualization/{_wrapped_components → history_viewer/_wrapped_components}/dbc.py +1 -1
- pyfemtet/opt/visualization/{_wrapped_components → history_viewer/_wrapped_components}/dcc.py +1 -1
- pyfemtet/opt/visualization/{_wrapped_components → history_viewer/_wrapped_components}/html.py +1 -1
- pyfemtet/opt/visualization/history_viewer/result_viewer/__main__.py +5 -0
- pyfemtet/opt/visualization/{result_viewer/application.py → history_viewer/result_viewer/_application.py} +6 -6
- pyfemtet/opt/visualization/{result_viewer/pages.py → history_viewer/result_viewer/_pages.py} +106 -82
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08.csv +18 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08.db +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8.log +45 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_1.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_1.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_10.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_10.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_11.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_11.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_12.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_12.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_13.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_13.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_14.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_14.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_15.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_15.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_16.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_16.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_17.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_17.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_18.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_18.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_19.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_19.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_2.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_2.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_20.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_20.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_3.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_3.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.bgr +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.bnd +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.btr +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.mtl +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_4.prm +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_5.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_5.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_6.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_6.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_7.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_7.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_8.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_8.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_9.jpg +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.Results/ex8_trial_9.pdt +0 -0
- pyfemtet/opt/visualization/history_viewer/result_viewer/tutorial_files/tutorial_gau_ex08_parametric.femprj +0 -0
- pyfemtet/opt/visualization/plotter/main_figure_creator.py +536 -0
- pyfemtet/opt/visualization/plotter/pm_graph_creator.py +359 -0
- pyfemtet/opt/worker_status.py +120 -0
- {pyfemtet-0.9.5.dist-info → pyfemtet-1.0.0b0.dist-info}/METADATA +23 -24
- pyfemtet-1.0.0b0.dist-info/RECORD +172 -0
- pyfemtet-1.0.0b0.dist-info/entry_points.txt +3 -0
- pyfemtet/_femtet_config_util/exit.py +0 -59
- pyfemtet/_message/1. make_pot.bat +0 -11
- pyfemtet/_message/2. make_mo.bat +0 -6
- pyfemtet/_message/__init__.py +0 -5
- pyfemtet/_message/babel.cfg +0 -2
- pyfemtet/_message/locales/ja/LC_MESSAGES/messages.mo +0 -0
- pyfemtet/_message/locales/ja/LC_MESSAGES/messages.po +0 -570
- pyfemtet/_message/locales/messages.pot +0 -551
- pyfemtet/_warning.py +0 -87
- pyfemtet/brep/_impl.py +0 -18
- pyfemtet/opt/_femopt.py +0 -1007
- pyfemtet/opt/_femopt_core.py +0 -1169
- pyfemtet/opt/_test_utils/control_femtet.py +0 -39
- pyfemtet/opt/_test_utils/hyper_sphere.py +0 -24
- pyfemtet/opt/_test_utils/record_history.py +0 -130
- pyfemtet/opt/advanced_samples/excel_ui/(ref) original_project.femprj +0 -0
- pyfemtet/opt/advanced_samples/excel_ui/femtet-macro.xlsm +0 -0
- pyfemtet/opt/advanced_samples/excel_ui/pyfemtet-core.py +0 -291
- pyfemtet/opt/advanced_samples/excel_ui/test-pyfemtet-core.cmd +0 -22
- pyfemtet/opt/advanced_samples/restart/gal_ex13_parametric.femprj +0 -0
- pyfemtet/opt/advanced_samples/restart/gal_ex13_parametric_restart.py +0 -99
- pyfemtet/opt/advanced_samples/restart/gal_ex13_parametric_restart_jp.py +0 -102
- pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_create_training_data.py +0 -60
- pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_create_training_data_jp.py +0 -57
- pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_optimize_with_surrogate.py +0 -100
- pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_optimize_with_surrogate_jp.py +0 -90
- pyfemtet/opt/advanced_samples/surrogate_model/gal_ex13_parametric.femprj +0 -0
- pyfemtet/opt/interface/_base.py +0 -101
- pyfemtet/opt/interface/_excel_interface.py +0 -984
- pyfemtet/opt/interface/_femtet_excel.py +0 -141
- pyfemtet/opt/interface/_femtet_with_nx/__init__.py +0 -3
- pyfemtet/opt/interface/_femtet_with_nx/_interface.py +0 -178
- pyfemtet/opt/interface/_femtet_with_sldworks.py +0 -298
- pyfemtet/opt/interface/_surrogate/__init__.py +0 -5
- pyfemtet/opt/interface/_surrogate/_base.py +0 -129
- pyfemtet/opt/interface/_surrogate/_chaospy.py +0 -71
- pyfemtet/opt/interface/_surrogate/_singletaskgp.py +0 -71
- pyfemtet/opt/interface/_surrogate_excel.py +0 -102
- pyfemtet/opt/optimizer/_base.py +0 -376
- pyfemtet/opt/optimizer/_optuna/_botorch_patch/enable_nonlinear_constraint.py +0 -220
- pyfemtet/opt/optimizer/_optuna/_optuna.py +0 -434
- pyfemtet/opt/optimizer/_optuna/_pof_botorch.py +0 -1914
- pyfemtet/opt/optimizer/_scipy.py +0 -159
- pyfemtet/opt/optimizer/_scipy_scalar.py +0 -127
- pyfemtet/opt/optimizer/parameter.py +0 -113
- pyfemtet/opt/prediction/_base.py +0 -61
- pyfemtet/opt/prediction/single_task_gp.py +0 -119
- pyfemtet/opt/samples/femprj_sample/ParametricIF.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/ParametricIF.py +0 -29
- pyfemtet/opt/samples/femprj_sample/ParametricIF_test_result.reccsv +0 -13
- pyfemtet/opt/samples/femprj_sample/cad_ex01_NX.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/cad_ex01_NX.prt +0 -0
- pyfemtet/opt/samples/femprj_sample/cad_ex01_NX.py +0 -135
- pyfemtet/opt/samples/femprj_sample/cad_ex01_NX_test_result.reccsv +0 -23
- pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.SLDPRT +0 -0
- pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/cad_ex01_SW.py +0 -131
- pyfemtet/opt/samples/femprj_sample/cad_ex01_SW_test_result.reccsv +0 -23
- pyfemtet/opt/samples/femprj_sample/constrained_pipe.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/constrained_pipe.py +0 -96
- pyfemtet/opt/samples/femprj_sample/constrained_pipe_test_result.reccsv +0 -13
- pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric.py +0 -74
- pyfemtet/opt/samples/femprj_sample/gal_ex58_parametric_test_result.reccsv +0 -13
- pyfemtet/opt/samples/femprj_sample/gau_ex08_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/gau_ex08_parametric.py +0 -58
- pyfemtet/opt/samples/femprj_sample/gau_ex08_parametric_test_result.reccsv +0 -23
- pyfemtet/opt/samples/femprj_sample/gau_ex12_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/gau_ex12_parametric.py +0 -52
- pyfemtet/opt/samples/femprj_sample/her_ex40_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/her_ex40_parametric.py +0 -138
- pyfemtet/opt/samples/femprj_sample/her_ex40_parametric_test_result.reccsv +0 -18
- pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric.py +0 -60
- pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric_parallel.py +0 -61
- pyfemtet/opt/samples/femprj_sample/paswat_ex1_parametric_test_result.reccsv +0 -18
- pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric.py +0 -58
- pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric_parallel.py +0 -58
- pyfemtet/opt/samples/femprj_sample/wat_ex14_parametric_test_result.reccsv +0 -18
- pyfemtet/opt/samples/femprj_sample_jp/ParametricIF_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/ParametricIF_jp.py +0 -29
- pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_NX_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_NX_jp.py +0 -129
- pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_SW_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/cad_ex01_SW_jp.py +0 -125
- pyfemtet/opt/samples/femprj_sample_jp/constrained_pipe_jp.py +0 -93
- pyfemtet/opt/samples/femprj_sample_jp/gal_ex58_parametric_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/gal_ex58_parametric_jp.py +0 -70
- pyfemtet/opt/samples/femprj_sample_jp/gau_ex08_parametric_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/gau_ex08_parametric_jp.py +0 -57
- pyfemtet/opt/samples/femprj_sample_jp/gau_ex12_parametric_jp.py +0 -52
- pyfemtet/opt/samples/femprj_sample_jp/her_ex40_parametric_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/her_ex40_parametric_jp.py +0 -138
- pyfemtet/opt/samples/femprj_sample_jp/paswat_ex1_parametric_jp.femprj +0 -0
- pyfemtet/opt/samples/femprj_sample_jp/paswat_ex1_parametric_jp.py +0 -58
- pyfemtet/opt/samples/femprj_sample_jp/paswat_ex1_parametric_parallel_jp.py +0 -59
- pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_jp.py +0 -56
- pyfemtet/opt/samples/femprj_sample_jp/wat_ex14_parametric_parallel_jp.py +0 -56
- pyfemtet/opt/visualization/_complex_components/main_figure_creator.py +0 -332
- pyfemtet/opt/visualization/_complex_components/pm_graph_creator.py +0 -201
- pyfemtet/opt/visualization/_process_monitor/application.py +0 -226
- pyfemtet/opt/visualization/_process_monitor/pages.py +0 -406
- pyfemtet/opt/visualization/_wrapped_components/__init__.py +0 -0
- pyfemtet/opt/visualization/result_viewer/__init__.py +0 -0
- pyfemtet-0.9.5.dist-info/RECORD +0 -158
- pyfemtet-0.9.5.dist-info/entry_points.txt +0 -3
- /pyfemtet/{_femtet_config_util → opt/problem}/__init__.py +0 -0
- /pyfemtet/{brep → opt/visualization/history_viewer}/__init__.py +0 -0
- /pyfemtet/opt/{_test_utils → visualization/history_viewer/_complex_components}/__init__.py +0 -0
- /pyfemtet/opt/{optimizer/_optuna → visualization/history_viewer/_process_monitor}/__init__.py +0 -0
- /pyfemtet/opt/{optimizer/_optuna/_botorch_patch → visualization/history_viewer/_wrapped_components}/__init__.py +0 -0
- /pyfemtet/opt/visualization/{_wrapped_components → history_viewer/_wrapped_components}/str_enum.py +0 -0
- /pyfemtet/opt/visualization/{result_viewer → history_viewer/result_viewer}/.gitignore +0 -0
- /pyfemtet/opt/visualization/{_complex_components → history_viewer/result_viewer}/__init__.py +0 -0
- /pyfemtet/opt/visualization/{_process_monitor → plotter}/__init__.py +0 -0
- /pyfemtet/opt/{samples/femprj_sample_jp/wat_ex14_parametric_jp.femprj → wat_ex14_parametric_jp.femprj} +0 -0
- {pyfemtet-0.9.5.dist-info → pyfemtet-1.0.0b0.dist-info}/LICENSE +0 -0
- {pyfemtet-0.9.5.dist-info → pyfemtet-1.0.0b0.dist-info}/LICENSE_THIRD_PARTY.txt +0 -0
- {pyfemtet-0.9.5.dist-info → pyfemtet-1.0.0b0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,1404 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, TypeAlias, Literal
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import csv
|
|
7
|
+
import ast
|
|
8
|
+
import math
|
|
9
|
+
import json
|
|
10
|
+
import datetime
|
|
11
|
+
import dataclasses
|
|
12
|
+
from time import sleep
|
|
13
|
+
from contextlib import nullcontext
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
import pandas as pd
|
|
17
|
+
|
|
18
|
+
import pyfemtet
|
|
19
|
+
|
|
20
|
+
from pyfemtet._i18n import *
|
|
21
|
+
from pyfemtet._util.df_util import *
|
|
22
|
+
from pyfemtet._util.dask_util import *
|
|
23
|
+
from pyfemtet._util.str_enum import StrEnum
|
|
24
|
+
from pyfemtet.opt.exceptions import *
|
|
25
|
+
from pyfemtet.opt.problem.problem import *
|
|
26
|
+
from pyfemtet.opt.problem.variable_manager import *
|
|
27
|
+
from pyfemtet.logger import get_module_logger
|
|
28
|
+
|
|
29
|
+
from pyfemtet.opt.history._optimality import *
|
|
30
|
+
from pyfemtet.opt.history._hypervolume import *
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from pyfemtet.opt.interface import AbstractFEMInterface
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
'TrialState',
|
|
38
|
+
'History',
|
|
39
|
+
'ColumnOrderMode',
|
|
40
|
+
'Record',
|
|
41
|
+
'create_err_msg_from_exception',
|
|
42
|
+
'CorrespondingColumnNameRuler',
|
|
43
|
+
'MAIN_FILTER',
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
MAIN_FILTER: dict = {'sub_fidelity_name': MAIN_FIDELITY_NAME}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
logger = get_module_logger('opt.history', False)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def create_err_msg_from_exception(e: Exception):
|
|
53
|
+
""":meta private:"""
|
|
54
|
+
additional = ' '.join(map(str, e.args))
|
|
55
|
+
if additional == '':
|
|
56
|
+
return type(e).__name__
|
|
57
|
+
else:
|
|
58
|
+
return type(e).__name__ + f'({additional})'
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TrialState(StrEnum):
|
|
62
|
+
|
|
63
|
+
succeeded = 'Success'
|
|
64
|
+
skipped = 'Skip'
|
|
65
|
+
hard_constraint_violation = 'Hard constraint violation'
|
|
66
|
+
soft_constraint_violation = 'Soft constraint violation'
|
|
67
|
+
|
|
68
|
+
# Hidden Constraint
|
|
69
|
+
model_error = 'Model error'
|
|
70
|
+
mesh_error = 'Mesh error'
|
|
71
|
+
solve_error = 'Solve error'
|
|
72
|
+
post_error = 'Post-processing error'
|
|
73
|
+
|
|
74
|
+
unknown_error = 'Unknown error'
|
|
75
|
+
undefined = 'undefined'
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def get_corresponding_state_from_exception(e: Exception) -> TrialState:
|
|
79
|
+
""":meta private:"""
|
|
80
|
+
if isinstance(e, ModelError):
|
|
81
|
+
state = TrialState.model_error
|
|
82
|
+
elif isinstance(e, MeshError):
|
|
83
|
+
state = TrialState.mesh_error
|
|
84
|
+
elif isinstance(e, SolveError):
|
|
85
|
+
state = TrialState.solve_error
|
|
86
|
+
elif isinstance(e, PostProcessError):
|
|
87
|
+
state = TrialState.post_error
|
|
88
|
+
elif isinstance(e, HardConstraintViolation):
|
|
89
|
+
state = TrialState.hard_constraint_violation
|
|
90
|
+
elif isinstance(e, SkipSolve):
|
|
91
|
+
state = TrialState.skipped
|
|
92
|
+
else:
|
|
93
|
+
state = TrialState.unknown_error
|
|
94
|
+
return state
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def get_corresponding_exception_from_state(state: TrialState) -> Exception | None:
|
|
98
|
+
""":meta private:"""
|
|
99
|
+
if state == TrialState.model_error:
|
|
100
|
+
e = ModelError()
|
|
101
|
+
elif state == TrialState.mesh_error:
|
|
102
|
+
e = MeshError()
|
|
103
|
+
elif state == TrialState.solve_error:
|
|
104
|
+
e = SolveError()
|
|
105
|
+
elif state == TrialState.post_error:
|
|
106
|
+
e = PostProcessError()
|
|
107
|
+
elif state == TrialState.unknown_error:
|
|
108
|
+
e = Exception()
|
|
109
|
+
elif state == TrialState.hard_constraint_violation:
|
|
110
|
+
e = HardConstraintViolation
|
|
111
|
+
elif state == TrialState.skipped:
|
|
112
|
+
e = SkipSolve
|
|
113
|
+
else:
|
|
114
|
+
e = None
|
|
115
|
+
return e
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def get_hidden_constraint_violation_states(cls):
|
|
119
|
+
""":meta private:"""
|
|
120
|
+
return [cls.get_corresponding_state_from_exception(exception_type())
|
|
121
|
+
for exception_type in _HiddenConstraintViolation.__pyfemtet_subclasses__]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class DataFrameWrapper:
|
|
125
|
+
""":meta private:"""
|
|
126
|
+
|
|
127
|
+
__df: pd.DataFrame
|
|
128
|
+
_lock_name = 'edit-df'
|
|
129
|
+
_dataset_name = 'df'
|
|
130
|
+
|
|
131
|
+
def __init__(self, df: pd.DataFrame):
|
|
132
|
+
self.set_df(df)
|
|
133
|
+
|
|
134
|
+
def __len__(self):
|
|
135
|
+
return len(self.get_df())
|
|
136
|
+
|
|
137
|
+
def __str__(self):
|
|
138
|
+
return self.get_df().__str__()
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def lock(self):
|
|
142
|
+
return Lock(self._lock_name)
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def lock_if_not_locked(self):
|
|
146
|
+
if self.lock.locked():
|
|
147
|
+
return nullcontext()
|
|
148
|
+
else:
|
|
149
|
+
return self.lock
|
|
150
|
+
|
|
151
|
+
def get_df(self, equality_filters: dict = None) -> pd.DataFrame:
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
equality_filters (dict, optional):
|
|
156
|
+
{column: value} formatted dict.
|
|
157
|
+
Each condition is considered as
|
|
158
|
+
an 'and' condition.
|
|
159
|
+
|
|
160
|
+
Defaults to no filter.
|
|
161
|
+
|
|
162
|
+
Returns (pd.DataFrame):
|
|
163
|
+
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
client = get_client()
|
|
167
|
+
|
|
168
|
+
# dask クラスターがある場合
|
|
169
|
+
if client is not None:
|
|
170
|
+
|
|
171
|
+
# あるけど with を抜けている場合
|
|
172
|
+
if client.scheduler is None:
|
|
173
|
+
df = self.__df
|
|
174
|
+
|
|
175
|
+
# 健在の場合
|
|
176
|
+
else:
|
|
177
|
+
|
|
178
|
+
df = None
|
|
179
|
+
|
|
180
|
+
with Lock('access_dataset_df'):
|
|
181
|
+
# datasets 内に存在する場合
|
|
182
|
+
if self._dataset_name in client.list_datasets():
|
|
183
|
+
df = client.get_dataset(self._dataset_name)
|
|
184
|
+
|
|
185
|
+
# set の前に get されることはあってはならない
|
|
186
|
+
else:
|
|
187
|
+
raise RuntimeError
|
|
188
|
+
|
|
189
|
+
assert df is not None
|
|
190
|
+
|
|
191
|
+
# dask クラスターがない場合
|
|
192
|
+
else:
|
|
193
|
+
df = self.__df
|
|
194
|
+
|
|
195
|
+
# filter に合致するものを取得
|
|
196
|
+
if equality_filters is not None:
|
|
197
|
+
df = get_partial_df(df, equality_filters)
|
|
198
|
+
|
|
199
|
+
return df
|
|
200
|
+
|
|
201
|
+
def set_df(self, df, equality_filters: dict = None):
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
df:
|
|
206
|
+
equality_filters (dict, optional):
|
|
207
|
+
{column: value} formatted dict.
|
|
208
|
+
Each condition is considered as
|
|
209
|
+
an 'and' condition.
|
|
210
|
+
Only the indexed rows will be updated.
|
|
211
|
+
|
|
212
|
+
Defaults to no filter.
|
|
213
|
+
|
|
214
|
+
Returns (pd.DataFrame):
|
|
215
|
+
|
|
216
|
+
"""
|
|
217
|
+
|
|
218
|
+
# フィルタを適用
|
|
219
|
+
# partial_df を get_df した時点のものから
|
|
220
|
+
# 変わっていたらエラーになる
|
|
221
|
+
if equality_filters is not None:
|
|
222
|
+
assert self.lock.locked(), 'set_df() with equality_filters must be called with locking.'
|
|
223
|
+
partial_df = df
|
|
224
|
+
df = self.get_df()
|
|
225
|
+
apply_partial_df(df, partial_df, equality_filters)
|
|
226
|
+
|
|
227
|
+
# dask クラスター上のデータを更新
|
|
228
|
+
client = get_client()
|
|
229
|
+
if client is not None:
|
|
230
|
+
if client.scheduler is not None:
|
|
231
|
+
with Lock('access_dataset_df'):
|
|
232
|
+
|
|
233
|
+
# datasets 上に存在する場合は削除(上書きができない)
|
|
234
|
+
if self._dataset_name in client.list_datasets():
|
|
235
|
+
|
|
236
|
+
# remove
|
|
237
|
+
client.unpublish_dataset(self._dataset_name)
|
|
238
|
+
|
|
239
|
+
# update
|
|
240
|
+
client.publish_dataset(**{self._dataset_name: df})
|
|
241
|
+
sleep(0.1)
|
|
242
|
+
|
|
243
|
+
# local のデータを更新
|
|
244
|
+
self.__df = df
|
|
245
|
+
|
|
246
|
+
def start_dask(self):
|
|
247
|
+
# Register the df initialized before dask context.
|
|
248
|
+
self.set_df(self.__df)
|
|
249
|
+
|
|
250
|
+
def end_dask(self):
|
|
251
|
+
# Get back the df on dask to use the value outside
|
|
252
|
+
# dask context.
|
|
253
|
+
self.__df = self.get_df()
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class CorrespondingColumnNameRuler:
|
|
257
|
+
""":meta private:"""
|
|
258
|
+
|
|
259
|
+
@staticmethod
|
|
260
|
+
def direction_name(obj_name):
|
|
261
|
+
return obj_name + '_direction'
|
|
262
|
+
|
|
263
|
+
@staticmethod
|
|
264
|
+
def prm_lower_bound_name(prm_name):
|
|
265
|
+
return prm_name + '_lower_bound'
|
|
266
|
+
|
|
267
|
+
@staticmethod
|
|
268
|
+
def prm_upper_bound_name(prm_name):
|
|
269
|
+
return prm_name + '_upper_bound'
|
|
270
|
+
|
|
271
|
+
@staticmethod
|
|
272
|
+
def prm_choices_name(prm_name):
|
|
273
|
+
return prm_name + '_choices'
|
|
274
|
+
|
|
275
|
+
@staticmethod
|
|
276
|
+
def prm_step_name(prm_name):
|
|
277
|
+
return prm_name + '_step'
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class ColumnOrderMode(StrEnum):
|
|
281
|
+
"""The order rule of the history csv columns."""
|
|
282
|
+
per_category = 'per_category' #: Sort per each object.
|
|
283
|
+
important_first = 'important_first' #: The values of parameters and objectives first.
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
ColumnOrderModeStr: TypeAlias = Literal['per_category', 'important_first']
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class DuplicatedColumnNameError(Exception):
|
|
290
|
+
""":meta private:"""
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class NoDuplicateDict(dict):
|
|
294
|
+
def update(self, m: dict, /, **kwargs):
|
|
295
|
+
for key_ in m.keys():
|
|
296
|
+
if key_ in self.keys():
|
|
297
|
+
raise DuplicatedColumnNameError(
|
|
298
|
+
_(
|
|
299
|
+
en_message='The name `{name}` is duplicated. '
|
|
300
|
+
'Please use another name.',
|
|
301
|
+
jp_message='名前 「{name}」 が重複しています。'
|
|
302
|
+
'別の名前を使ってください。',
|
|
303
|
+
name=key_,
|
|
304
|
+
)
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
super().update(m, **kwargs)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
class ColumnManager:
|
|
311
|
+
""":meta private:"""
|
|
312
|
+
|
|
313
|
+
parameters: TrialInput
|
|
314
|
+
y_names: list[str]
|
|
315
|
+
c_names: list[str]
|
|
316
|
+
column_dtypes: dict[str, type]
|
|
317
|
+
meta_columns: list[str]
|
|
318
|
+
|
|
319
|
+
@staticmethod
|
|
320
|
+
def columns_to_keep_even_if_nan():
|
|
321
|
+
return [
|
|
322
|
+
'messages',
|
|
323
|
+
]
|
|
324
|
+
|
|
325
|
+
def initialize(
|
|
326
|
+
self,
|
|
327
|
+
parameters: TrialInput,
|
|
328
|
+
y_names,
|
|
329
|
+
c_names,
|
|
330
|
+
additional_data: dict,
|
|
331
|
+
column_order_mode: str = ColumnOrderMode.per_category,
|
|
332
|
+
):
|
|
333
|
+
self.parameters = parameters
|
|
334
|
+
self.y_names = y_names
|
|
335
|
+
self.c_names = c_names
|
|
336
|
+
self.set_full_sorted_column_information(
|
|
337
|
+
additional_data=additional_data,
|
|
338
|
+
column_order_mode=column_order_mode,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
def set_full_sorted_column_information(
|
|
342
|
+
self,
|
|
343
|
+
extra_parameters: TrialInput = None,
|
|
344
|
+
extra_y_names: list[str] = None,
|
|
345
|
+
extra_c_names: list[str] = None,
|
|
346
|
+
additional_data: dict = None,
|
|
347
|
+
column_order_mode: str = ColumnOrderMode.per_category,
|
|
348
|
+
):
|
|
349
|
+
extra_parameters = extra_parameters or TrialInput()
|
|
350
|
+
extra_y_names = extra_y_names or []
|
|
351
|
+
extra_c_names = extra_c_names or []
|
|
352
|
+
|
|
353
|
+
# column name になるので重複は許されない
|
|
354
|
+
column_dtypes: dict = NoDuplicateDict()
|
|
355
|
+
meta_columns: list = []
|
|
356
|
+
column_dtypes_later: dict = NoDuplicateDict()
|
|
357
|
+
meta_columns_later: list = []
|
|
358
|
+
|
|
359
|
+
if column_order_mode == ColumnOrderMode.per_category:
|
|
360
|
+
target_cds: dict = column_dtypes
|
|
361
|
+
target_mcs: list = meta_columns
|
|
362
|
+
elif column_order_mode == ColumnOrderMode.important_first:
|
|
363
|
+
target_cds: dict = column_dtypes_later
|
|
364
|
+
target_mcs: list = meta_columns_later
|
|
365
|
+
else:
|
|
366
|
+
assert False, f'Unknown {column_order_mode=}'
|
|
367
|
+
|
|
368
|
+
# noinspection PyUnresolvedReferences
|
|
369
|
+
keys = Record.__dataclass_fields__.copy().keys()
|
|
370
|
+
for key in keys:
|
|
371
|
+
# Note:
|
|
372
|
+
# as_df() で空欄になりうるカラムには
|
|
373
|
+
# Nan や '' を許容する dtype を指定すること
|
|
374
|
+
# 例えば、 trial に int を指定してはいけない
|
|
375
|
+
#
|
|
376
|
+
# Note:
|
|
377
|
+
# pandas は column_dtypes に str を受け付けない
|
|
378
|
+
# (object にキャストされる模様)
|
|
379
|
+
|
|
380
|
+
if key == 'x':
|
|
381
|
+
for prm_name in self.parameters.keys():
|
|
382
|
+
|
|
383
|
+
param = self.parameters[prm_name]
|
|
384
|
+
|
|
385
|
+
if isinstance(param, NumericParameter):
|
|
386
|
+
# important
|
|
387
|
+
column_dtypes.update({prm_name: float})
|
|
388
|
+
meta_columns.append('prm.num.value')
|
|
389
|
+
|
|
390
|
+
# later
|
|
391
|
+
f = CorrespondingColumnNameRuler.prm_lower_bound_name
|
|
392
|
+
target_cds.update({f(prm_name): float})
|
|
393
|
+
target_mcs.append('prm.num.lower_bound')
|
|
394
|
+
|
|
395
|
+
f = CorrespondingColumnNameRuler.prm_upper_bound_name
|
|
396
|
+
target_cds.update({f(prm_name): float})
|
|
397
|
+
target_mcs.append('prm.num.upper_bound')
|
|
398
|
+
|
|
399
|
+
f = CorrespondingColumnNameRuler.prm_step_name
|
|
400
|
+
target_cds.update({f(prm_name): float})
|
|
401
|
+
target_mcs.append('prm.num.step')
|
|
402
|
+
|
|
403
|
+
elif isinstance(param, CategoricalParameter):
|
|
404
|
+
# important
|
|
405
|
+
column_dtypes.update({prm_name: object})
|
|
406
|
+
meta_columns.append('prm.cat.value')
|
|
407
|
+
|
|
408
|
+
# later
|
|
409
|
+
f = CorrespondingColumnNameRuler.prm_choices_name
|
|
410
|
+
target_cds.update({f(prm_name): object})
|
|
411
|
+
target_mcs.append('prm.cat.choices')
|
|
412
|
+
|
|
413
|
+
else:
|
|
414
|
+
raise NotImplementedError
|
|
415
|
+
|
|
416
|
+
for extra_prm_name, extra_param in extra_parameters.items():
|
|
417
|
+
|
|
418
|
+
if isinstance(extra_param, NumericParameter):
|
|
419
|
+
# later
|
|
420
|
+
target_cds.update({extra_prm_name: float})
|
|
421
|
+
target_mcs.append('')
|
|
422
|
+
|
|
423
|
+
f = CorrespondingColumnNameRuler.prm_lower_bound_name
|
|
424
|
+
target_cds.update({f(extra_prm_name): object})
|
|
425
|
+
target_mcs.append('')
|
|
426
|
+
|
|
427
|
+
f = CorrespondingColumnNameRuler.prm_upper_bound_name
|
|
428
|
+
target_cds.update({f(extra_prm_name): object})
|
|
429
|
+
target_mcs.append('')
|
|
430
|
+
|
|
431
|
+
elif isinstance(extra_param, CategoricalParameter):
|
|
432
|
+
target_cds.update({extra_prm_name: object})
|
|
433
|
+
target_mcs.append('')
|
|
434
|
+
|
|
435
|
+
f = CorrespondingColumnNameRuler.prm_choices_name
|
|
436
|
+
target_cds.update({f(extra_prm_name): object})
|
|
437
|
+
target_mcs.append('')
|
|
438
|
+
|
|
439
|
+
else:
|
|
440
|
+
raise NotImplementedError
|
|
441
|
+
|
|
442
|
+
elif key == 'y':
|
|
443
|
+
f = CorrespondingColumnNameRuler.direction_name
|
|
444
|
+
for name in self.y_names:
|
|
445
|
+
# important
|
|
446
|
+
column_dtypes.update({name: float})
|
|
447
|
+
meta_columns.append('obj')
|
|
448
|
+
|
|
449
|
+
# later
|
|
450
|
+
target_cds.update({f(name): object}) # str | float
|
|
451
|
+
target_mcs.append(f('obj'))
|
|
452
|
+
|
|
453
|
+
for name in extra_y_names:
|
|
454
|
+
# later
|
|
455
|
+
target_cds.update({name: float})
|
|
456
|
+
target_mcs.append('')
|
|
457
|
+
|
|
458
|
+
# later
|
|
459
|
+
target_cds.update({f(name): object}) # str | float
|
|
460
|
+
target_mcs.append('')
|
|
461
|
+
|
|
462
|
+
elif key == 'c':
|
|
463
|
+
|
|
464
|
+
for name in self.c_names:
|
|
465
|
+
# important
|
|
466
|
+
column_dtypes.update({name: float})
|
|
467
|
+
meta_columns.append('cns')
|
|
468
|
+
|
|
469
|
+
for name in extra_c_names:
|
|
470
|
+
# later
|
|
471
|
+
target_cds.update({name: float})
|
|
472
|
+
target_mcs.append('')
|
|
473
|
+
|
|
474
|
+
# additional_data を入れる
|
|
475
|
+
elif key == self._get_additional_data_column():
|
|
476
|
+
# important
|
|
477
|
+
column_dtypes.update({key: object})
|
|
478
|
+
meta_columns.append(json.dumps(additional_data or dict()))
|
|
479
|
+
|
|
480
|
+
elif key in (
|
|
481
|
+
'feasibility',
|
|
482
|
+
'optimality',
|
|
483
|
+
'sub_sampling',
|
|
484
|
+
'sub_fidelity_name',
|
|
485
|
+
):
|
|
486
|
+
# important
|
|
487
|
+
column_dtypes.update({key: object})
|
|
488
|
+
meta_columns.append('')
|
|
489
|
+
|
|
490
|
+
else:
|
|
491
|
+
# later
|
|
492
|
+
target_cds.update({key: object})
|
|
493
|
+
target_mcs.append('')
|
|
494
|
+
|
|
495
|
+
column_dtypes.update(column_dtypes_later)
|
|
496
|
+
meta_columns.extend(meta_columns_later)
|
|
497
|
+
|
|
498
|
+
self.column_dtypes = dict(**column_dtypes)
|
|
499
|
+
self.meta_columns = meta_columns
|
|
500
|
+
|
|
501
|
+
@staticmethod
|
|
502
|
+
def _get_additional_data_column():
|
|
503
|
+
return 'trial'
|
|
504
|
+
|
|
505
|
+
@classmethod
|
|
506
|
+
def _get_additional_data(cls, columns, meta_columns) -> dict:
|
|
507
|
+
for column, meta_column in zip(columns, meta_columns):
|
|
508
|
+
if column == cls._get_additional_data_column():
|
|
509
|
+
if meta_column:
|
|
510
|
+
return json.loads(meta_column)
|
|
511
|
+
else:
|
|
512
|
+
return json.loads('{}')
|
|
513
|
+
else:
|
|
514
|
+
raise RuntimeError(f'"{cls._get_additional_data_column()}" is not found in given columns.')
|
|
515
|
+
|
|
516
|
+
@staticmethod
|
|
517
|
+
def _filter_columns(meta_column, columns, meta_columns) -> list[str]:
|
|
518
|
+
out = []
|
|
519
|
+
assert len(columns) == len(meta_columns), f'{len(columns)=} and {len(meta_columns)=}'
|
|
520
|
+
|
|
521
|
+
for i, (column_, meta_column_) in enumerate(zip(columns, meta_columns)):
|
|
522
|
+
if meta_column_ == meta_column:
|
|
523
|
+
out.append(column_)
|
|
524
|
+
return out
|
|
525
|
+
|
|
526
|
+
@classmethod
|
|
527
|
+
def _filter_prm_names(cls, columns, meta_columns) -> list[str]:
|
|
528
|
+
return (
|
|
529
|
+
cls._filter_columns('prm.num.value', columns, meta_columns)
|
|
530
|
+
+ cls._filter_columns('prm.cat.value', columns, meta_columns)
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
def filter_columns(self, meta_column) -> list[str]:
|
|
534
|
+
columns = list(self.column_dtypes.keys())
|
|
535
|
+
return self._filter_columns(meta_column, columns, self.meta_columns)
|
|
536
|
+
|
|
537
|
+
def get_prm_names(self) -> list[str]:
|
|
538
|
+
return (
|
|
539
|
+
self.filter_columns('prm.num.value')
|
|
540
|
+
+ self.filter_columns('prm.cat.value')
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
def get_obj_names(self) -> list[str]:
|
|
544
|
+
return self.filter_columns('obj')
|
|
545
|
+
|
|
546
|
+
def get_cns_names(self) -> list[str]:
|
|
547
|
+
return self.filter_columns('cns')
|
|
548
|
+
|
|
549
|
+
@staticmethod
|
|
550
|
+
def _is_numerical_parameter(prm_name, columns):
|
|
551
|
+
prm_lb_name = CorrespondingColumnNameRuler.prm_lower_bound_name(prm_name)
|
|
552
|
+
return prm_lb_name in columns
|
|
553
|
+
|
|
554
|
+
@staticmethod
|
|
555
|
+
def _is_categorical_parameter(prm_name, columns):
|
|
556
|
+
prm_choices_name = CorrespondingColumnNameRuler.prm_choices_name(prm_name)
|
|
557
|
+
return prm_choices_name in columns
|
|
558
|
+
|
|
559
|
+
def is_numerical_parameter(self, prm_name) -> bool:
|
|
560
|
+
return self._is_numerical_parameter(prm_name, tuple(self.column_dtypes.keys()))
|
|
561
|
+
|
|
562
|
+
def is_categorical_parameter(self, prm_name) -> bool:
|
|
563
|
+
return self._is_categorical_parameter(prm_name, tuple(self.column_dtypes.keys()))
|
|
564
|
+
|
|
565
|
+
@staticmethod
|
|
566
|
+
def _get_parameter(prm_name: str, df: pd.DataFrame) -> Parameter:
|
|
567
|
+
if ColumnManager._is_numerical_parameter(prm_name, df.columns):
|
|
568
|
+
out = NumericParameter()
|
|
569
|
+
out.name = prm_name
|
|
570
|
+
out.value = float(df[prm_name].dropna().values[-1])
|
|
571
|
+
|
|
572
|
+
# lower_bound
|
|
573
|
+
key = CorrespondingColumnNameRuler.prm_lower_bound_name(prm_name)
|
|
574
|
+
if key in df.columns:
|
|
575
|
+
out.lower_bound = float(df[key].dropna().values[-1])
|
|
576
|
+
else:
|
|
577
|
+
out.lower_bound = None
|
|
578
|
+
|
|
579
|
+
# upper bound
|
|
580
|
+
key = CorrespondingColumnNameRuler.prm_upper_bound_name(prm_name)
|
|
581
|
+
if key in df.columns:
|
|
582
|
+
out.upper_bound = float(df[key].dropna().values[-1])
|
|
583
|
+
else:
|
|
584
|
+
out.upper_bound = None
|
|
585
|
+
|
|
586
|
+
# step
|
|
587
|
+
key = CorrespondingColumnNameRuler.prm_step_name(prm_name)
|
|
588
|
+
if key in df.columns:
|
|
589
|
+
out.step = float(df[key].dropna().values[-1])
|
|
590
|
+
else:
|
|
591
|
+
out.step = None
|
|
592
|
+
|
|
593
|
+
elif ColumnManager._is_categorical_parameter(prm_name, df.columns):
|
|
594
|
+
out = CategoricalParameter()
|
|
595
|
+
out.name = prm_name
|
|
596
|
+
out.value = str(df[prm_name].dropna().values[-1])
|
|
597
|
+
out.choices = df[CorrespondingColumnNameRuler.prm_choices_name(prm_name)].dropna().values[-1]
|
|
598
|
+
|
|
599
|
+
else:
|
|
600
|
+
raise NotImplementedError
|
|
601
|
+
|
|
602
|
+
return out
|
|
603
|
+
|
|
604
|
+
@staticmethod
|
|
605
|
+
def _reconvert_objects(df: pd.DataFrame, meta_columns: list[str]):
|
|
606
|
+
for column, meta_column in zip(df.columns, meta_columns):
|
|
607
|
+
# messages は df の段階で _RECORD_MESSAGE_DELIMITER
|
|
608
|
+
# separated な str なのでここで restore してはいけない
|
|
609
|
+
|
|
610
|
+
# choices list は csv を経由することで str になるので restore
|
|
611
|
+
if meta_column == 'prm.cat.choices':
|
|
612
|
+
df[column] = [ast.literal_eval(d) for d in df[column]]
|
|
613
|
+
|
|
614
|
+
@staticmethod
|
|
615
|
+
def _get_sub_fidelity_names(df: pd.DataFrame) -> list[str]:
|
|
616
|
+
|
|
617
|
+
if 'sub_fidelity_name' not in df.columns:
|
|
618
|
+
return [MAIN_FIDELITY_NAME]
|
|
619
|
+
|
|
620
|
+
else:
|
|
621
|
+
return np.unique(df['sub_fidelity_name'].values).tolist()
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
_RECORD_MESSAGE_DELIMITER = ' | '
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
@dataclasses.dataclass
|
|
628
|
+
class Record:
|
|
629
|
+
""":meta private:"""
|
|
630
|
+
|
|
631
|
+
# x, y, c のみ特殊で、データの展開や関連情報の
|
|
632
|
+
# 列への展開を必要とするが、他の field は
|
|
633
|
+
# ここに定義すればよい
|
|
634
|
+
|
|
635
|
+
trial: int = None
|
|
636
|
+
trial_id: int = None
|
|
637
|
+
sub_sampling: SubSampling | None = None
|
|
638
|
+
sub_fidelity_name: str = None
|
|
639
|
+
fidelity: Fidelity = None
|
|
640
|
+
x: TrialInput = dataclasses.field(default_factory=TrialInput)
|
|
641
|
+
y: TrialOutput = dataclasses.field(default_factory=TrialOutput)
|
|
642
|
+
c: TrialConstraintOutput = dataclasses.field(default_factory=TrialConstraintOutput)
|
|
643
|
+
state: TrialState = TrialState.undefined
|
|
644
|
+
datetime_start: datetime.datetime = dataclasses.field(default_factory=datetime.datetime.now)
|
|
645
|
+
datetime_end: datetime.datetime = dataclasses.field(default_factory=datetime.datetime.now)
|
|
646
|
+
messages: list = dataclasses.field(default_factory=list)
|
|
647
|
+
hypervolume: float | None = None
|
|
648
|
+
feasibility: bool | None = None
|
|
649
|
+
optimality: bool | None = None
|
|
650
|
+
|
|
651
|
+
def as_df(self, dtypes: dict = None):
|
|
652
|
+
|
|
653
|
+
# noinspection PyUnresolvedReferences
|
|
654
|
+
keys = self.__dataclass_fields__.copy().keys()
|
|
655
|
+
d = {key: getattr(self, key) for key in keys if getattr(self, key) is not None}
|
|
656
|
+
|
|
657
|
+
x: TrialInput = d.pop('x')
|
|
658
|
+
y: TrialOutput = d.pop('y')
|
|
659
|
+
c: TrialConstraintOutput = d.pop('c')
|
|
660
|
+
|
|
661
|
+
# prm
|
|
662
|
+
for prm_name, param in x.items():
|
|
663
|
+
d.update({prm_name: param.value})
|
|
664
|
+
if isinstance(param, NumericParameter):
|
|
665
|
+
f = CorrespondingColumnNameRuler.prm_lower_bound_name
|
|
666
|
+
d.update({f(prm_name): param.lower_bound})
|
|
667
|
+
f = CorrespondingColumnNameRuler.prm_upper_bound_name
|
|
668
|
+
d.update({f(prm_name): param.upper_bound})
|
|
669
|
+
f = CorrespondingColumnNameRuler.prm_step_name
|
|
670
|
+
d.update({f(prm_name): param.step})
|
|
671
|
+
elif isinstance(param, CategoricalParameter):
|
|
672
|
+
f = CorrespondingColumnNameRuler.prm_choices_name
|
|
673
|
+
d.update({f(prm_name): param.choices})
|
|
674
|
+
else:
|
|
675
|
+
raise NotImplementedError
|
|
676
|
+
|
|
677
|
+
# messages to str
|
|
678
|
+
messages_str = _RECORD_MESSAGE_DELIMITER.join(d['messages'])
|
|
679
|
+
d.update({'messages': messages_str})
|
|
680
|
+
|
|
681
|
+
d.update(**{k: v.value for k, v in y.items()})
|
|
682
|
+
d.update(**{f'{k}_direction': v.direction for k, v in y.items()})
|
|
683
|
+
d.update(**{k: v.value for k, v in c.items()})
|
|
684
|
+
|
|
685
|
+
df = pd.DataFrame(
|
|
686
|
+
{k: [v] for k, v in d.items()},
|
|
687
|
+
columns=tuple(dtypes.keys())
|
|
688
|
+
)
|
|
689
|
+
|
|
690
|
+
if dtypes:
|
|
691
|
+
df = df.astype(dtypes)
|
|
692
|
+
|
|
693
|
+
return df
|
|
694
|
+
|
|
695
|
+
@staticmethod
|
|
696
|
+
def get_state_str_from_series(row: pd.Series):
|
|
697
|
+
state: TrialState = TrialState.undefined
|
|
698
|
+
if 'state' in row:
|
|
699
|
+
state = row['state']
|
|
700
|
+
return state
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
class EntireDependentValuesCalculator:
|
|
704
|
+
""":meta private:"""
|
|
705
|
+
|
|
706
|
+
def __init__(
|
|
707
|
+
self,
|
|
708
|
+
records: Records,
|
|
709
|
+
equality_filters: dict,
|
|
710
|
+
entire_df: pd.DataFrame,
|
|
711
|
+
):
|
|
712
|
+
|
|
713
|
+
self.records = records
|
|
714
|
+
self.equality_filters = equality_filters
|
|
715
|
+
self.entire_df: pd.DataFrame = entire_df
|
|
716
|
+
self.partial_df: pd.DataFrame = get_partial_df(entire_df, equality_filters)
|
|
717
|
+
|
|
718
|
+
assert self.records.df_wrapper.lock.locked()
|
|
719
|
+
|
|
720
|
+
# get column names
|
|
721
|
+
obj_names = self.records.column_manager.get_obj_names()
|
|
722
|
+
f = CorrespondingColumnNameRuler.direction_name
|
|
723
|
+
obj_direction_names = [f(name) for name in obj_names]
|
|
724
|
+
|
|
725
|
+
# get values
|
|
726
|
+
all_obj_values = self.partial_df[obj_names].values
|
|
727
|
+
all_obj_directions = self.partial_df[obj_direction_names].values
|
|
728
|
+
feasibility = self.partial_df['feasibility']
|
|
729
|
+
|
|
730
|
+
# convert values as minimization problem
|
|
731
|
+
y_internal = np.empty(all_obj_values.shape)
|
|
732
|
+
for i, (obj_values, obj_directions) \
|
|
733
|
+
in enumerate(zip(all_obj_values.T, all_obj_directions.T)):
|
|
734
|
+
y_internal[:, i] = np.array(
|
|
735
|
+
list(
|
|
736
|
+
map(
|
|
737
|
+
lambda args: Objective._convert(*args),
|
|
738
|
+
zip(obj_values, obj_directions)
|
|
739
|
+
)
|
|
740
|
+
)
|
|
741
|
+
)
|
|
742
|
+
|
|
743
|
+
self.partial_y_internal = y_internal
|
|
744
|
+
self.partial_feasibility = feasibility
|
|
745
|
+
|
|
746
|
+
def update_optimality(self):
|
|
747
|
+
|
|
748
|
+
assert self.records.df_wrapper.lock.locked()
|
|
749
|
+
|
|
750
|
+
# calc optimality
|
|
751
|
+
optimality = calc_optimality(
|
|
752
|
+
self.partial_y_internal,
|
|
753
|
+
self.partial_feasibility,
|
|
754
|
+
)
|
|
755
|
+
|
|
756
|
+
# update
|
|
757
|
+
self.partial_df.loc[:, 'optimality'] = optimality
|
|
758
|
+
|
|
759
|
+
def update_hypervolume(self):
|
|
760
|
+
|
|
761
|
+
assert self.records.df_wrapper.lock.locked()
|
|
762
|
+
|
|
763
|
+
# calc hypervolume
|
|
764
|
+
hv_values = calc_hypervolume(
|
|
765
|
+
self.partial_y_internal,
|
|
766
|
+
self.partial_feasibility,
|
|
767
|
+
ref_point='nadir-up-to-the-point',
|
|
768
|
+
)
|
|
769
|
+
|
|
770
|
+
# update
|
|
771
|
+
self.partial_df.loc[:, 'hypervolume'] = hv_values
|
|
772
|
+
|
|
773
|
+
def update_trial_number(self):
|
|
774
|
+
|
|
775
|
+
assert self.records.df_wrapper.lock.locked()
|
|
776
|
+
|
|
777
|
+
# calc trial
|
|
778
|
+
trial_number = 1 + np.arange(len(self.partial_df)).astype(int)
|
|
779
|
+
|
|
780
|
+
# update
|
|
781
|
+
self.partial_df.loc[:, 'trial'] = trial_number
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
class Records:
|
|
785
|
+
""":meta private:
|
|
786
|
+
|
|
787
|
+
最適化の試行全体の情報を格納するモデルクラス
|
|
788
|
+
"""
|
|
789
|
+
df_wrapper: DataFrameWrapper
|
|
790
|
+
column_manager: ColumnManager
|
|
791
|
+
|
|
792
|
+
def __init__(self):
|
|
793
|
+
self.df_wrapper = DataFrameWrapper(pd.DataFrame())
|
|
794
|
+
self.column_manager = ColumnManager()
|
|
795
|
+
self.loaded_meta_columns = None
|
|
796
|
+
self.loaded_df = None
|
|
797
|
+
|
|
798
|
+
def __str__(self):
|
|
799
|
+
return self.df_wrapper.__str__()
|
|
800
|
+
|
|
801
|
+
def __len__(self):
|
|
802
|
+
return len(self.df_wrapper)
|
|
803
|
+
|
|
804
|
+
def initialize(self):
|
|
805
|
+
with self.df_wrapper.lock:
|
|
806
|
+
# 新しく始まる場合に備えカラムを設定
|
|
807
|
+
# load の場合はあとで上書きされる
|
|
808
|
+
df = pd.DataFrame([], columns=list(self.column_manager.column_dtypes.keys()))
|
|
809
|
+
self.df_wrapper.set_df(df)
|
|
810
|
+
|
|
811
|
+
def load(self, path: str):
|
|
812
|
+
|
|
813
|
+
for encoding in (ENCODING, 'utf-8'):
|
|
814
|
+
try:
|
|
815
|
+
with open(path, 'r', encoding=encoding, newline='\n') as f:
|
|
816
|
+
reader = csv.reader(f, delimiter=',')
|
|
817
|
+
# load meta_column
|
|
818
|
+
loaded_meta_columns = reader.__next__()
|
|
819
|
+
reader.__next__() # empty line
|
|
820
|
+
# load df from line 3
|
|
821
|
+
loaded_df = pd.read_csv(f, encoding=encoding, header=0)
|
|
822
|
+
break
|
|
823
|
+
|
|
824
|
+
except UnicodeDecodeError:
|
|
825
|
+
continue
|
|
826
|
+
|
|
827
|
+
# df を csv にする過程で失われる list などのオブジェクトを restore
|
|
828
|
+
ColumnManager._reconvert_objects(loaded_df, loaded_meta_columns)
|
|
829
|
+
|
|
830
|
+
# この段階では column_dtypes が setup されていない可能性があるので
|
|
831
|
+
# compatibility check をしない。よって set_df しない。
|
|
832
|
+
self.loaded_meta_columns = loaded_meta_columns
|
|
833
|
+
self.loaded_df = loaded_df
|
|
834
|
+
|
|
835
|
+
def check_problem_compatibility(self):
|
|
836
|
+
|
|
837
|
+
# 読み込んだデータがないのであれば何もしない
|
|
838
|
+
if self.loaded_df is None:
|
|
839
|
+
return
|
|
840
|
+
|
|
841
|
+
# 順番が違ってもいいが、
|
|
842
|
+
# 構成に変更がないこと。
|
|
843
|
+
# ただし obj は減っていてもいい。
|
|
844
|
+
loaded_columns, loaded_meta_columns = self.loaded_df.columns, self.loaded_meta_columns
|
|
845
|
+
|
|
846
|
+
# prm_names が過不足ないか
|
|
847
|
+
loaded_prm_names = set(
|
|
848
|
+
self.column_manager._filter_prm_names(
|
|
849
|
+
loaded_columns, loaded_meta_columns
|
|
850
|
+
)
|
|
851
|
+
)
|
|
852
|
+
prm_names = set(self.column_manager.get_prm_names())
|
|
853
|
+
if not (len(loaded_prm_names - prm_names) == len(prm_names - loaded_prm_names) == 0):
|
|
854
|
+
raise RuntimeError('Incompatible parameter setting.')
|
|
855
|
+
|
|
856
|
+
# obj_names が増えていないか
|
|
857
|
+
loaded_obj_names = set(self.column_manager._filter_columns('obj', loaded_columns, loaded_meta_columns))
|
|
858
|
+
obj_names = set(self.column_manager.get_obj_names())
|
|
859
|
+
if len(obj_names - loaded_obj_names) > 0:
|
|
860
|
+
raise RuntimeError('Incompatible objective setting.')
|
|
861
|
+
|
|
862
|
+
# cns_names が過不足ないか
|
|
863
|
+
# TODO: cns の上下限は変更されてはならない。
|
|
864
|
+
loaded_cns_names = set(self.column_manager._filter_columns('cns', loaded_columns, loaded_meta_columns))
|
|
865
|
+
cns_names = set(self.column_manager.get_cns_names())
|
|
866
|
+
if not (len(loaded_cns_names - cns_names) == len(cns_names - loaded_cns_names) == 0):
|
|
867
|
+
raise RuntimeError('Incompatible constraint setting.')
|
|
868
|
+
|
|
869
|
+
def reinitialize_record_with_loaded_data(self, column_order_mode: str = ColumnOrderMode.per_category):
|
|
870
|
+
|
|
871
|
+
# 読み込んだデータがないのであれば何もしない
|
|
872
|
+
if self.loaded_df is None:
|
|
873
|
+
return
|
|
874
|
+
|
|
875
|
+
loaded_columns, loaded_meta_columns = self.loaded_df.columns, self.loaded_meta_columns
|
|
876
|
+
loaded_prm_names = set(self.column_manager._filter_prm_names(loaded_columns, loaded_meta_columns))
|
|
877
|
+
loaded_obj_names = set(self.column_manager._filter_columns('obj', loaded_columns, loaded_meta_columns))
|
|
878
|
+
loaded_cns_names = set(self.column_manager._filter_columns('cns', loaded_columns, loaded_meta_columns))
|
|
879
|
+
|
|
880
|
+
# loaded df に存在するが Record に存在しないカラムを Record に追加
|
|
881
|
+
extra_parameters = {}
|
|
882
|
+
extra_y_names = []
|
|
883
|
+
extra_c_names = []
|
|
884
|
+
for l_col, l_meta in zip(loaded_columns, loaded_meta_columns):
|
|
885
|
+
|
|
886
|
+
# 現在の Record に含まれないならば
|
|
887
|
+
if l_col not in self.column_manager.column_dtypes.keys():
|
|
888
|
+
|
|
889
|
+
# それが prm_name ならば
|
|
890
|
+
if l_col in loaded_prm_names:
|
|
891
|
+
|
|
892
|
+
# それが Categorical ならば
|
|
893
|
+
if CorrespondingColumnNameRuler.prm_choices_name(l_col) in loaded_columns:
|
|
894
|
+
param = CategoricalParameter()
|
|
895
|
+
param.name = l_col
|
|
896
|
+
param.value = ''
|
|
897
|
+
param.choices = []
|
|
898
|
+
|
|
899
|
+
# それが Numeric ならば
|
|
900
|
+
elif CorrespondingColumnNameRuler.prm_lower_bound_name(l_col) in loaded_columns:
|
|
901
|
+
param = NumericParameter()
|
|
902
|
+
param.name = l_col
|
|
903
|
+
param.value = np.nan
|
|
904
|
+
param.lower_bound = np.nan
|
|
905
|
+
param.upper_bound = np.nan
|
|
906
|
+
|
|
907
|
+
else:
|
|
908
|
+
raise NotImplementedError
|
|
909
|
+
|
|
910
|
+
extra_parameters.update({l_col: param})
|
|
911
|
+
|
|
912
|
+
# obj_name ならば
|
|
913
|
+
elif l_col in loaded_obj_names:
|
|
914
|
+
extra_y_names.append(l_col)
|
|
915
|
+
|
|
916
|
+
# cns_name ならば
|
|
917
|
+
elif l_col in loaded_cns_names:
|
|
918
|
+
extra_c_names.append(l_col)
|
|
919
|
+
|
|
920
|
+
# additional data を取得
|
|
921
|
+
a_data = self.column_manager._get_additional_data(loaded_columns, loaded_meta_columns)
|
|
922
|
+
|
|
923
|
+
self.column_manager.set_full_sorted_column_information(
|
|
924
|
+
extra_parameters=extra_parameters,
|
|
925
|
+
extra_y_names=extra_y_names,
|
|
926
|
+
extra_c_names=extra_c_names,
|
|
927
|
+
additional_data=a_data,
|
|
928
|
+
column_order_mode=column_order_mode,
|
|
929
|
+
)
|
|
930
|
+
|
|
931
|
+
# worker に影響しないように loaded_df のコピーを作成
|
|
932
|
+
df: pd.DataFrame = self.loaded_df.copy()
|
|
933
|
+
|
|
934
|
+
# loaded df に存在しないが Record に存在するカラムを追加
|
|
935
|
+
for col in self.column_manager.column_dtypes.keys():
|
|
936
|
+
if col not in df.columns:
|
|
937
|
+
# column ごとの default 値を追加
|
|
938
|
+
if col == 'sub_fidelity_name':
|
|
939
|
+
df[col] = MAIN_FIDELITY_NAME
|
|
940
|
+
else:
|
|
941
|
+
df[col] = np.nan
|
|
942
|
+
|
|
943
|
+
# column_dtypes を設定
|
|
944
|
+
# 与える column_dtypes のほうが多い場合
|
|
945
|
+
# エラーになるので余分なものを削除
|
|
946
|
+
# 与える column_dtypes が少ない分には
|
|
947
|
+
# (pandas としては) 問題ない
|
|
948
|
+
dtypes = {k: v for k, v in self.column_manager.column_dtypes.items() if k in self.loaded_df.columns}
|
|
949
|
+
df = df.astype(dtypes)
|
|
950
|
+
|
|
951
|
+
# 並べ替え
|
|
952
|
+
df = df[list(self.column_manager.column_dtypes.keys())].astype(self.column_manager.column_dtypes)
|
|
953
|
+
|
|
954
|
+
# OK なので読み込んだデータを set_df する
|
|
955
|
+
self.df_wrapper.set_df(df)
|
|
956
|
+
|
|
957
|
+
def remove_nan_columns(
|
|
958
|
+
self, df, meta_columns, columns_to_keep: str | list[str] = None
|
|
959
|
+
) -> tuple[pd.DataFrame, tuple[str]]:
|
|
960
|
+
"""
|
|
961
|
+
|
|
962
|
+
Args:
|
|
963
|
+
df:
|
|
964
|
+
meta_columns:
|
|
965
|
+
columns_to_keep: Allowing these columns to all NaN values.
|
|
966
|
+
|
|
967
|
+
Returns:
|
|
968
|
+
Removed DataFrame and corresponding meta_columns.
|
|
969
|
+
|
|
970
|
+
"""
|
|
971
|
+
|
|
972
|
+
df = df.replace('', None)
|
|
973
|
+
|
|
974
|
+
nan_columns = df.isna().all(axis=0)
|
|
975
|
+
if columns_to_keep is None:
|
|
976
|
+
columns_to_keep = self.column_manager.columns_to_keep_even_if_nan()
|
|
977
|
+
nan_columns[columns_to_keep] = False
|
|
978
|
+
|
|
979
|
+
fdf = df.loc[:, ~nan_columns]
|
|
980
|
+
f_meta_columns = (np.array(meta_columns)[~nan_columns]).tolist()
|
|
981
|
+
|
|
982
|
+
return fdf, f_meta_columns
|
|
983
|
+
|
|
984
|
+
def save(self, path: str):
|
|
985
|
+
|
|
986
|
+
# filter NaN columns
|
|
987
|
+
df, meta_columns = self.remove_nan_columns(
|
|
988
|
+
self.df_wrapper.get_df(), self.column_manager.meta_columns,
|
|
989
|
+
)
|
|
990
|
+
|
|
991
|
+
try:
|
|
992
|
+
with open(path, 'w', encoding=ENCODING) as f:
|
|
993
|
+
writer = csv.writer(f, delimiter=',', lineterminator="\n")
|
|
994
|
+
# write meta_columns
|
|
995
|
+
writer.writerow(meta_columns)
|
|
996
|
+
writer.writerow([''] * len(meta_columns)) # empty line
|
|
997
|
+
# write df from line 3
|
|
998
|
+
df.to_csv(f, index=False, encoding=ENCODING, lineterminator='\n')
|
|
999
|
+
except PermissionError:
|
|
1000
|
+
logger.warning(
|
|
1001
|
+
_(
|
|
1002
|
+
en_message='History csv file ({path}) is in use and cannot be written to. '
|
|
1003
|
+
'Please free this file before exiting the program, '
|
|
1004
|
+
'otherwise history data will be lost.',
|
|
1005
|
+
jp_message='履歴のCSVファイル({path})が使用中のため書き込みできません。'
|
|
1006
|
+
'プログラムを終了する前にこのファイルを閉じてください。'
|
|
1007
|
+
'そうしない場合、履歴データが失われます。',
|
|
1008
|
+
path=path,
|
|
1009
|
+
)
|
|
1010
|
+
)
|
|
1011
|
+
|
|
1012
|
+
def append(self, record: Record) -> pd.Series:
|
|
1013
|
+
|
|
1014
|
+
# get row
|
|
1015
|
+
row = record.as_df(dtypes=self.column_manager.column_dtypes)
|
|
1016
|
+
|
|
1017
|
+
# concat
|
|
1018
|
+
dfw = self.df_wrapper
|
|
1019
|
+
|
|
1020
|
+
# append
|
|
1021
|
+
with dfw.lock:
|
|
1022
|
+
|
|
1023
|
+
df = dfw.get_df()
|
|
1024
|
+
|
|
1025
|
+
if len(df) == 0:
|
|
1026
|
+
# ここで空のカラムを削除しては
|
|
1027
|
+
# データの並びがおかしくなるケースが出る
|
|
1028
|
+
new_df = row
|
|
1029
|
+
else:
|
|
1030
|
+
# pandas の型推定の仕様変更対策で
|
|
1031
|
+
# 空のカラムは削除する
|
|
1032
|
+
row.dropna(axis=1, inplace=True, how='all')
|
|
1033
|
+
|
|
1034
|
+
new_df = pd.concat(
|
|
1035
|
+
[df, row],
|
|
1036
|
+
axis=0,
|
|
1037
|
+
ignore_index=True,
|
|
1038
|
+
)
|
|
1039
|
+
|
|
1040
|
+
# calc entire-dependent values
|
|
1041
|
+
# must be in with block to keep
|
|
1042
|
+
# the entire data compatibility
|
|
1043
|
+
# during processing.
|
|
1044
|
+
self.update_entire_dependent_values(new_df)
|
|
1045
|
+
|
|
1046
|
+
dfw.set_df(new_df)
|
|
1047
|
+
|
|
1048
|
+
# postprocess after recording で使うために
|
|
1049
|
+
# 計算済み最終行を返す
|
|
1050
|
+
return new_df.iloc[-1]
|
|
1051
|
+
|
|
1052
|
+
def update_entire_dependent_values(self, processing_df: pd.DataFrame):
|
|
1053
|
+
|
|
1054
|
+
with self.df_wrapper.lock_if_not_locked:
|
|
1055
|
+
|
|
1056
|
+
# update main fidelity
|
|
1057
|
+
equality_filters = MAIN_FILTER
|
|
1058
|
+
mgr = EntireDependentValuesCalculator(
|
|
1059
|
+
self,
|
|
1060
|
+
equality_filters,
|
|
1061
|
+
processing_df,
|
|
1062
|
+
)
|
|
1063
|
+
mgr.update_optimality()
|
|
1064
|
+
mgr.update_hypervolume()
|
|
1065
|
+
mgr.update_trial_number()
|
|
1066
|
+
pdf = mgr.partial_df
|
|
1067
|
+
apply_partial_df(df=processing_df, partial_df=pdf, equality_filters=equality_filters)
|
|
1068
|
+
|
|
1069
|
+
# update sub fidelity
|
|
1070
|
+
entire_df = self.df_wrapper.get_df()
|
|
1071
|
+
sub_fidelity_names: list = np.unique(entire_df['sub_fidelity_name']).tolist()
|
|
1072
|
+
if MAIN_FIDELITY_NAME in sub_fidelity_names:
|
|
1073
|
+
sub_fidelity_names.remove(MAIN_FIDELITY_NAME)
|
|
1074
|
+
for sub_fidelity_name in sub_fidelity_names:
|
|
1075
|
+
equality_filters = {'sub_fidelity_name': sub_fidelity_name}
|
|
1076
|
+
mgr = EntireDependentValuesCalculator(
|
|
1077
|
+
self,
|
|
1078
|
+
equality_filters,
|
|
1079
|
+
processing_df
|
|
1080
|
+
)
|
|
1081
|
+
mgr.update_trial_number()
|
|
1082
|
+
pdf = mgr.partial_df
|
|
1083
|
+
apply_partial_df(df=processing_df, partial_df=pdf, equality_filters=equality_filters)
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
class History:
|
|
1087
|
+
"""最適化の試行の履歴を管理します。"""
|
|
1088
|
+
_records: Records
|
|
1089
|
+
prm_names: list[str]
|
|
1090
|
+
obj_names: list[str]
|
|
1091
|
+
cns_names: list[str]
|
|
1092
|
+
sub_fidelity_names: list[str]
|
|
1093
|
+
is_restart: bool
|
|
1094
|
+
additional_data: dict
|
|
1095
|
+
|
|
1096
|
+
path: str
|
|
1097
|
+
"""The existing or destination CSV path.
|
|
1098
|
+
|
|
1099
|
+
If not specified, the CSV file is saved in the format
|
|
1100
|
+
"pyfemtet.opt_%Y%m%d_%H%M%S.csv"
|
|
1101
|
+
when the optimization process starts.
|
|
1102
|
+
"""
|
|
1103
|
+
|
|
1104
|
+
MAIN_FILTER = MAIN_FILTER
|
|
1105
|
+
|
|
1106
|
+
def __init__(self):
|
|
1107
|
+
self._records = Records()
|
|
1108
|
+
self.path: str | None = None
|
|
1109
|
+
self._finalized: bool = False
|
|
1110
|
+
self.is_restart = False
|
|
1111
|
+
self.additional_data = dict(version=pyfemtet.__version__)
|
|
1112
|
+
self.column_order_mode: ColumnOrderMode | ColumnOrderModeStr = ColumnOrderMode.per_category
|
|
1113
|
+
|
|
1114
|
+
def __str__(self):
|
|
1115
|
+
return self._records.__str__()
|
|
1116
|
+
|
|
1117
|
+
def __enter__(self):
|
|
1118
|
+
self._records.df_wrapper.start_dask()
|
|
1119
|
+
|
|
1120
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
1121
|
+
self._records.df_wrapper.end_dask()
|
|
1122
|
+
|
|
1123
|
+
def load_csv(self, path, with_finalize=False):
|
|
1124
|
+
""":meta private:"""
|
|
1125
|
+
|
|
1126
|
+
self.is_restart = True
|
|
1127
|
+
self.path = path
|
|
1128
|
+
self._records.load(self.path)
|
|
1129
|
+
|
|
1130
|
+
if with_finalize:
|
|
1131
|
+
self._finalize_from_loaded_data()
|
|
1132
|
+
|
|
1133
|
+
def _finalize_from_loaded_data(self):
|
|
1134
|
+
assert self.is_restart
|
|
1135
|
+
|
|
1136
|
+
if not self._finalized:
|
|
1137
|
+
|
|
1138
|
+
df = self._records.loaded_df
|
|
1139
|
+
meta_columns = self._records.loaded_meta_columns
|
|
1140
|
+
|
|
1141
|
+
self.prm_names = ColumnManager._filter_prm_names(df.columns, meta_columns)
|
|
1142
|
+
self.obj_names = ColumnManager._filter_columns('obj', df.columns, meta_columns)
|
|
1143
|
+
self.cns_names = ColumnManager._filter_columns('cns', df.columns, meta_columns)
|
|
1144
|
+
self.sub_fidelity_names = ColumnManager._get_sub_fidelity_names(df)
|
|
1145
|
+
self.additional_data = ColumnManager._get_additional_data(df.columns, meta_columns)
|
|
1146
|
+
|
|
1147
|
+
parameters: TrialInput = {}
|
|
1148
|
+
for prm_name in self.prm_names:
|
|
1149
|
+
param = ColumnManager._get_parameter(prm_name, df)
|
|
1150
|
+
parameters.update({prm_name: param})
|
|
1151
|
+
|
|
1152
|
+
self.finalize(
|
|
1153
|
+
parameters,
|
|
1154
|
+
self.obj_names,
|
|
1155
|
+
self.cns_names,
|
|
1156
|
+
self.sub_fidelity_names,
|
|
1157
|
+
self.additional_data,
|
|
1158
|
+
)
|
|
1159
|
+
|
|
1160
|
+
def finalize(
|
|
1161
|
+
self,
|
|
1162
|
+
parameters: TrialInput,
|
|
1163
|
+
obj_names,
|
|
1164
|
+
cns_names,
|
|
1165
|
+
sub_fidelity_names,
|
|
1166
|
+
additional_data,
|
|
1167
|
+
):
|
|
1168
|
+
""":meta private:"""
|
|
1169
|
+
|
|
1170
|
+
self.prm_names = list(parameters.keys())
|
|
1171
|
+
self.obj_names = list(obj_names)
|
|
1172
|
+
self.cns_names = list(cns_names)
|
|
1173
|
+
self.sub_fidelity_names = list(sub_fidelity_names)
|
|
1174
|
+
self.additional_data.update(additional_data)
|
|
1175
|
+
|
|
1176
|
+
if not self._finalized:
|
|
1177
|
+
# ここで column_dtypes が決定する
|
|
1178
|
+
self._records.column_manager.initialize(
|
|
1179
|
+
parameters, self.obj_names, self.cns_names, self.additional_data, self.column_order_mode
|
|
1180
|
+
)
|
|
1181
|
+
|
|
1182
|
+
# initialize
|
|
1183
|
+
self._records.initialize()
|
|
1184
|
+
|
|
1185
|
+
if self.path is None:
|
|
1186
|
+
self.path = datetime.datetime.now().strftime("pyfemtet.opt_%Y%m%d_%H%M%S.csv")
|
|
1187
|
+
|
|
1188
|
+
# load
|
|
1189
|
+
if os.path.isfile(self.path):
|
|
1190
|
+
self.load_csv(self.path)
|
|
1191
|
+
self._records.check_problem_compatibility()
|
|
1192
|
+
self._records.reinitialize_record_with_loaded_data(self.column_order_mode)
|
|
1193
|
+
|
|
1194
|
+
self._finalized = True
|
|
1195
|
+
|
|
1196
|
+
def get_df(self, equality_filters: dict = None) -> pd.DataFrame:
|
|
1197
|
+
"""Returns the optimization history.
|
|
1198
|
+
|
|
1199
|
+
Args:
|
|
1200
|
+
equality_filters (dict, optional):
|
|
1201
|
+
The {column: value} というフォーマットの
|
|
1202
|
+
matching filter.
|
|
1203
|
+
|
|
1204
|
+
Returns: The optimization history.
|
|
1205
|
+
|
|
1206
|
+
"""
|
|
1207
|
+
return self._records.df_wrapper.get_df(equality_filters)
|
|
1208
|
+
|
|
1209
|
+
@staticmethod
|
|
1210
|
+
def get_trial_name(trial=None, fidelity=None, sub_sampling=None, row: pd.Series = None):
|
|
1211
|
+
if row is not None:
|
|
1212
|
+
assert not math.isnan(row['trial'])
|
|
1213
|
+
trial = row['trial']
|
|
1214
|
+
fidelity = row['fidelity'] if not math.isnan(row['fidelity']) else None
|
|
1215
|
+
sub_sampling = row['sub_sampling'] if not math.isnan(row['sub_sampling']) else None
|
|
1216
|
+
|
|
1217
|
+
name_parts = ['trial']
|
|
1218
|
+
if fidelity is not None:
|
|
1219
|
+
fid = str(fidelity)
|
|
1220
|
+
if fid != MAIN_FIDELITY_NAME:
|
|
1221
|
+
name_parts.append(fid)
|
|
1222
|
+
|
|
1223
|
+
name_parts.append(str(trial))
|
|
1224
|
+
|
|
1225
|
+
if sub_sampling is not None:
|
|
1226
|
+
name_parts.append(str(sub_sampling))
|
|
1227
|
+
|
|
1228
|
+
trial_name = '_'.join(name_parts)
|
|
1229
|
+
|
|
1230
|
+
return trial_name
|
|
1231
|
+
|
|
1232
|
+
def recording(self, fem: AbstractFEMInterface):
|
|
1233
|
+
""":meta private:"""
|
|
1234
|
+
|
|
1235
|
+
# noinspection PyMethodParameters
|
|
1236
|
+
class RecordContext:
|
|
1237
|
+
|
|
1238
|
+
def __init__(self_):
|
|
1239
|
+
self_.record = Record()
|
|
1240
|
+
self_.record_as_df = None
|
|
1241
|
+
|
|
1242
|
+
def __enter__(self_):
|
|
1243
|
+
return self_.record
|
|
1244
|
+
|
|
1245
|
+
def append(self_):
|
|
1246
|
+
self_.record.datetime_end = self_.record.datetime_end \
|
|
1247
|
+
if self_.record.datetime_end is not None \
|
|
1248
|
+
else datetime.datetime.now()
|
|
1249
|
+
return self._records.append(self_.record)
|
|
1250
|
+
|
|
1251
|
+
@staticmethod
|
|
1252
|
+
def postprocess_after_recording(row):
|
|
1253
|
+
|
|
1254
|
+
client = get_client()
|
|
1255
|
+
|
|
1256
|
+
trial_name = self.get_trial_name(row=row)
|
|
1257
|
+
|
|
1258
|
+
# FIXME: メインフィデリティだけでなく、FEM に
|
|
1259
|
+
# 対応するフィデリティ又はサブサンプリングのみ
|
|
1260
|
+
# フィルタした情報を提供するようにする。
|
|
1261
|
+
# フィデリティの話は現在解析を実行している opt が
|
|
1262
|
+
# 必要なので、recording メソッドの引数に
|
|
1263
|
+
# それを追加する
|
|
1264
|
+
df = self.get_df(equality_filters=self.MAIN_FILTER)
|
|
1265
|
+
|
|
1266
|
+
if client is not None:
|
|
1267
|
+
client.run_on_scheduler(
|
|
1268
|
+
fem._postprocess_after_recording,
|
|
1269
|
+
trial_name=trial_name,
|
|
1270
|
+
df=df,
|
|
1271
|
+
**(fem._create_postprocess_args()),
|
|
1272
|
+
)
|
|
1273
|
+
|
|
1274
|
+
else:
|
|
1275
|
+
fem._postprocess_after_recording(
|
|
1276
|
+
dask_scheduler=None,
|
|
1277
|
+
trial_name=trial_name,
|
|
1278
|
+
df=df,
|
|
1279
|
+
**(fem._create_postprocess_args())
|
|
1280
|
+
)
|
|
1281
|
+
|
|
1282
|
+
def __exit__(self_, exc_type, exc_val, exc_tb):
|
|
1283
|
+
|
|
1284
|
+
row: pd.Series | None = None
|
|
1285
|
+
|
|
1286
|
+
# record feasibility
|
|
1287
|
+
# skipped -> None (empty)
|
|
1288
|
+
# succeeded -> True
|
|
1289
|
+
# else -> False
|
|
1290
|
+
if self_.record.state == TrialState.skipped:
|
|
1291
|
+
self_.record.feasibility = None
|
|
1292
|
+
|
|
1293
|
+
elif self_.record.state == TrialState.succeeded:
|
|
1294
|
+
self_.record.feasibility = True
|
|
1295
|
+
|
|
1296
|
+
else:
|
|
1297
|
+
self_.record.feasibility = False
|
|
1298
|
+
|
|
1299
|
+
# append
|
|
1300
|
+
if exc_type is None:
|
|
1301
|
+
row = self_.append()
|
|
1302
|
+
# 1st argument of issubclass cannot be None
|
|
1303
|
+
elif issubclass(exc_type, ExceptionDuringOptimization):
|
|
1304
|
+
row = self_.append()
|
|
1305
|
+
|
|
1306
|
+
# if append is succeeded,
|
|
1307
|
+
# do fem.post_processing
|
|
1308
|
+
if row is not None:
|
|
1309
|
+
self_.postprocess_after_recording(row)
|
|
1310
|
+
|
|
1311
|
+
# save history
|
|
1312
|
+
client = get_client()
|
|
1313
|
+
if client is None:
|
|
1314
|
+
self.save()
|
|
1315
|
+
|
|
1316
|
+
return RecordContext()
|
|
1317
|
+
|
|
1318
|
+
def save(self):
|
|
1319
|
+
"""Export the optimization history.
|
|
1320
|
+
|
|
1321
|
+
The destination path is :class:`History.path`.
|
|
1322
|
+
"""
|
|
1323
|
+
self._records.save(self.path)
|
|
1324
|
+
|
|
1325
|
+
def _create_optuna_study_for_visualization(self):
|
|
1326
|
+
import optuna
|
|
1327
|
+
|
|
1328
|
+
# create study
|
|
1329
|
+
kwargs: dict[str, ...] = dict(
|
|
1330
|
+
# storage='sqlite:///' + os.path.basename(self.path) + '_dummy.db',
|
|
1331
|
+
sampler=None, pruner=None, study_name='dummy',
|
|
1332
|
+
)
|
|
1333
|
+
if len(self.obj_names) == 1:
|
|
1334
|
+
kwargs.update(dict(direction='minimize'))
|
|
1335
|
+
else:
|
|
1336
|
+
kwargs.update(dict(directions=['minimize']*len(self.obj_names)))
|
|
1337
|
+
study = optuna.create_study(**kwargs)
|
|
1338
|
+
|
|
1339
|
+
# add trial to study
|
|
1340
|
+
df = self.get_df(equality_filters=MAIN_FILTER)
|
|
1341
|
+
|
|
1342
|
+
for i, row in df.iterrows():
|
|
1343
|
+
|
|
1344
|
+
# trial
|
|
1345
|
+
trial_kwargs: dict = dict()
|
|
1346
|
+
|
|
1347
|
+
# state
|
|
1348
|
+
state_str = Record.get_state_str_from_series(row)
|
|
1349
|
+
if state_str != TrialState.succeeded:
|
|
1350
|
+
continue
|
|
1351
|
+
state = optuna.trial.TrialState.COMPLETE
|
|
1352
|
+
trial_kwargs.update(dict(state=state))
|
|
1353
|
+
|
|
1354
|
+
# params
|
|
1355
|
+
params = {prm_name: row[prm_name] for prm_name in self.prm_names}
|
|
1356
|
+
trial_kwargs.update(dict(params=params))
|
|
1357
|
+
|
|
1358
|
+
# distribution
|
|
1359
|
+
distributions: dict[str, optuna.distributions.BaseDistribution] = dict()
|
|
1360
|
+
for prm_name in params.keys():
|
|
1361
|
+
|
|
1362
|
+
# float
|
|
1363
|
+
if self._records.column_manager.is_numerical_parameter(prm_name):
|
|
1364
|
+
lb_name = CorrespondingColumnNameRuler.prm_lower_bound_name(prm_name)
|
|
1365
|
+
ub_name = CorrespondingColumnNameRuler.prm_upper_bound_name(prm_name)
|
|
1366
|
+
dist = optuna.distributions.FloatDistribution(
|
|
1367
|
+
low=row[lb_name],
|
|
1368
|
+
high=row[ub_name],
|
|
1369
|
+
)
|
|
1370
|
+
|
|
1371
|
+
# categorical
|
|
1372
|
+
elif self._records.column_manager.is_categorical_parameter(prm_name):
|
|
1373
|
+
choices_name = CorrespondingColumnNameRuler.prm_choices_name(prm_name)
|
|
1374
|
+
dist = optuna.distributions.CategoricalDistribution(
|
|
1375
|
+
choices=row[choices_name]
|
|
1376
|
+
)
|
|
1377
|
+
|
|
1378
|
+
else:
|
|
1379
|
+
raise NotImplementedError
|
|
1380
|
+
|
|
1381
|
+
distributions.update(
|
|
1382
|
+
{prm_name: dist}
|
|
1383
|
+
)
|
|
1384
|
+
trial_kwargs.update(dict(distributions=distributions))
|
|
1385
|
+
|
|
1386
|
+
# objective
|
|
1387
|
+
if len(self.obj_names) == 1:
|
|
1388
|
+
trial_kwargs.update(dict(value=row[self.obj_names].values[0]))
|
|
1389
|
+
else:
|
|
1390
|
+
trial_kwargs.update(dict(values=row[self.obj_names].values))
|
|
1391
|
+
|
|
1392
|
+
# add to study
|
|
1393
|
+
trial = optuna.create_trial(**trial_kwargs)
|
|
1394
|
+
study.add_trial(trial)
|
|
1395
|
+
|
|
1396
|
+
return study
|
|
1397
|
+
|
|
1398
|
+
def is_numerical_parameter(self, prm_name: str) -> bool:
|
|
1399
|
+
""":meta private:"""
|
|
1400
|
+
return self._records.column_manager.is_numerical_parameter(prm_name)
|
|
1401
|
+
|
|
1402
|
+
def is_categorical_parameter(self, prm_name) -> bool:
|
|
1403
|
+
""":meta private:"""
|
|
1404
|
+
return self._records.column_manager.is_categorical_parameter(prm_name)
|