MultiOptPy 1.20.2__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.
- multioptpy/Calculator/__init__.py +0 -0
- multioptpy/Calculator/ase_calculation_tools.py +424 -0
- multioptpy/Calculator/ase_tools/__init__.py +0 -0
- multioptpy/Calculator/ase_tools/fairchem.py +28 -0
- multioptpy/Calculator/ase_tools/gamess.py +19 -0
- multioptpy/Calculator/ase_tools/gaussian.py +165 -0
- multioptpy/Calculator/ase_tools/mace.py +28 -0
- multioptpy/Calculator/ase_tools/mopac.py +19 -0
- multioptpy/Calculator/ase_tools/nwchem.py +31 -0
- multioptpy/Calculator/ase_tools/orca.py +22 -0
- multioptpy/Calculator/ase_tools/pygfn0.py +37 -0
- multioptpy/Calculator/dxtb_calculation_tools.py +344 -0
- multioptpy/Calculator/emt_calculation_tools.py +458 -0
- multioptpy/Calculator/gpaw_calculation_tools.py +183 -0
- multioptpy/Calculator/lj_calculation_tools.py +314 -0
- multioptpy/Calculator/psi4_calculation_tools.py +334 -0
- multioptpy/Calculator/pwscf_calculation_tools.py +189 -0
- multioptpy/Calculator/pyscf_calculation_tools.py +327 -0
- multioptpy/Calculator/sqm1_calculation_tools.py +611 -0
- multioptpy/Calculator/sqm2_calculation_tools.py +376 -0
- multioptpy/Calculator/tblite_calculation_tools.py +352 -0
- multioptpy/Calculator/tersoff_calculation_tools.py +818 -0
- multioptpy/Constraint/__init__.py +0 -0
- multioptpy/Constraint/constraint_condition.py +834 -0
- multioptpy/Coordinate/__init__.py +0 -0
- multioptpy/Coordinate/polar_coordinate.py +199 -0
- multioptpy/Coordinate/redundant_coordinate.py +638 -0
- multioptpy/IRC/__init__.py +0 -0
- multioptpy/IRC/converge_criteria.py +28 -0
- multioptpy/IRC/dvv.py +544 -0
- multioptpy/IRC/euler.py +439 -0
- multioptpy/IRC/hpc.py +564 -0
- multioptpy/IRC/lqa.py +540 -0
- multioptpy/IRC/modekill.py +662 -0
- multioptpy/IRC/rk4.py +579 -0
- multioptpy/Interpolation/__init__.py +0 -0
- multioptpy/Interpolation/adaptive_interpolation.py +283 -0
- multioptpy/Interpolation/binomial_interpolation.py +179 -0
- multioptpy/Interpolation/geodesic_interpolation.py +785 -0
- multioptpy/Interpolation/interpolation.py +156 -0
- multioptpy/Interpolation/linear_interpolation.py +473 -0
- multioptpy/Interpolation/savitzky_golay_interpolation.py +252 -0
- multioptpy/Interpolation/spline_interpolation.py +353 -0
- multioptpy/MD/__init__.py +0 -0
- multioptpy/MD/thermostat.py +185 -0
- multioptpy/MEP/__init__.py +0 -0
- multioptpy/MEP/pathopt_bneb_force.py +443 -0
- multioptpy/MEP/pathopt_dmf_force.py +448 -0
- multioptpy/MEP/pathopt_dneb_force.py +130 -0
- multioptpy/MEP/pathopt_ewbneb_force.py +207 -0
- multioptpy/MEP/pathopt_gpneb_force.py +512 -0
- multioptpy/MEP/pathopt_lup_force.py +113 -0
- multioptpy/MEP/pathopt_neb_force.py +225 -0
- multioptpy/MEP/pathopt_nesb_force.py +205 -0
- multioptpy/MEP/pathopt_om_force.py +153 -0
- multioptpy/MEP/pathopt_qsm_force.py +174 -0
- multioptpy/MEP/pathopt_qsmv2_force.py +304 -0
- multioptpy/ModelFunction/__init__.py +7 -0
- multioptpy/ModelFunction/avoiding_model_function.py +29 -0
- multioptpy/ModelFunction/binary_image_ts_search_model_function.py +47 -0
- multioptpy/ModelFunction/conical_model_function.py +26 -0
- multioptpy/ModelFunction/opt_meci.py +50 -0
- multioptpy/ModelFunction/opt_mesx.py +47 -0
- multioptpy/ModelFunction/opt_mesx_2.py +49 -0
- multioptpy/ModelFunction/seam_model_function.py +27 -0
- multioptpy/ModelHessian/__init__.py +0 -0
- multioptpy/ModelHessian/approx_hessian.py +147 -0
- multioptpy/ModelHessian/calc_params.py +227 -0
- multioptpy/ModelHessian/fischer.py +236 -0
- multioptpy/ModelHessian/fischerd3.py +360 -0
- multioptpy/ModelHessian/fischerd4.py +398 -0
- multioptpy/ModelHessian/gfn0xtb.py +633 -0
- multioptpy/ModelHessian/gfnff.py +709 -0
- multioptpy/ModelHessian/lindh.py +165 -0
- multioptpy/ModelHessian/lindh2007d2.py +707 -0
- multioptpy/ModelHessian/lindh2007d3.py +822 -0
- multioptpy/ModelHessian/lindh2007d4.py +1030 -0
- multioptpy/ModelHessian/morse.py +106 -0
- multioptpy/ModelHessian/schlegel.py +144 -0
- multioptpy/ModelHessian/schlegeld3.py +322 -0
- multioptpy/ModelHessian/schlegeld4.py +559 -0
- multioptpy/ModelHessian/shortrange.py +346 -0
- multioptpy/ModelHessian/swartd2.py +496 -0
- multioptpy/ModelHessian/swartd3.py +706 -0
- multioptpy/ModelHessian/swartd4.py +918 -0
- multioptpy/ModelHessian/tshess.py +40 -0
- multioptpy/Optimizer/QHAdam.py +61 -0
- multioptpy/Optimizer/__init__.py +0 -0
- multioptpy/Optimizer/abc_fire.py +83 -0
- multioptpy/Optimizer/adabelief.py +58 -0
- multioptpy/Optimizer/adabound.py +68 -0
- multioptpy/Optimizer/adadelta.py +65 -0
- multioptpy/Optimizer/adaderivative.py +56 -0
- multioptpy/Optimizer/adadiff.py +68 -0
- multioptpy/Optimizer/adafactor.py +70 -0
- multioptpy/Optimizer/adam.py +65 -0
- multioptpy/Optimizer/adamax.py +62 -0
- multioptpy/Optimizer/adamod.py +83 -0
- multioptpy/Optimizer/adamw.py +65 -0
- multioptpy/Optimizer/adiis.py +523 -0
- multioptpy/Optimizer/afire_neb.py +282 -0
- multioptpy/Optimizer/block_hessian_update.py +709 -0
- multioptpy/Optimizer/c2diis.py +491 -0
- multioptpy/Optimizer/component_wise_scaling.py +405 -0
- multioptpy/Optimizer/conjugate_gradient.py +82 -0
- multioptpy/Optimizer/conjugate_gradient_neb.py +345 -0
- multioptpy/Optimizer/coordinate_locking.py +405 -0
- multioptpy/Optimizer/dic_rsirfo.py +1015 -0
- multioptpy/Optimizer/ediis.py +417 -0
- multioptpy/Optimizer/eve.py +76 -0
- multioptpy/Optimizer/fastadabelief.py +61 -0
- multioptpy/Optimizer/fire.py +77 -0
- multioptpy/Optimizer/fire2.py +249 -0
- multioptpy/Optimizer/fire_neb.py +92 -0
- multioptpy/Optimizer/gan_step.py +486 -0
- multioptpy/Optimizer/gdiis.py +609 -0
- multioptpy/Optimizer/gediis.py +203 -0
- multioptpy/Optimizer/geodesic_step.py +433 -0
- multioptpy/Optimizer/gpmin.py +633 -0
- multioptpy/Optimizer/gpr_step.py +364 -0
- multioptpy/Optimizer/gradientdescent.py +78 -0
- multioptpy/Optimizer/gradientdescent_neb.py +52 -0
- multioptpy/Optimizer/hessian_update.py +433 -0
- multioptpy/Optimizer/hybrid_rfo.py +998 -0
- multioptpy/Optimizer/kdiis.py +625 -0
- multioptpy/Optimizer/lars.py +21 -0
- multioptpy/Optimizer/lbfgs.py +253 -0
- multioptpy/Optimizer/lbfgs_neb.py +355 -0
- multioptpy/Optimizer/linesearch.py +236 -0
- multioptpy/Optimizer/lookahead.py +40 -0
- multioptpy/Optimizer/nadam.py +64 -0
- multioptpy/Optimizer/newton.py +200 -0
- multioptpy/Optimizer/prodigy.py +70 -0
- multioptpy/Optimizer/purtubation.py +16 -0
- multioptpy/Optimizer/quickmin_neb.py +245 -0
- multioptpy/Optimizer/radam.py +75 -0
- multioptpy/Optimizer/rfo_neb.py +302 -0
- multioptpy/Optimizer/ric_rfo.py +842 -0
- multioptpy/Optimizer/rl_step.py +627 -0
- multioptpy/Optimizer/rmspropgrave.py +65 -0
- multioptpy/Optimizer/rsirfo.py +1647 -0
- multioptpy/Optimizer/rsprfo.py +1056 -0
- multioptpy/Optimizer/sadam.py +60 -0
- multioptpy/Optimizer/samsgrad.py +63 -0
- multioptpy/Optimizer/tr_lbfgs.py +678 -0
- multioptpy/Optimizer/trim.py +273 -0
- multioptpy/Optimizer/trust_radius.py +207 -0
- multioptpy/Optimizer/trust_radius_neb.py +121 -0
- multioptpy/Optimizer/yogi.py +60 -0
- multioptpy/OtherMethod/__init__.py +0 -0
- multioptpy/OtherMethod/addf.py +1150 -0
- multioptpy/OtherMethod/dimer.py +895 -0
- multioptpy/OtherMethod/elastic_image_pair.py +629 -0
- multioptpy/OtherMethod/modelfunction.py +456 -0
- multioptpy/OtherMethod/newton_traj.py +454 -0
- multioptpy/OtherMethod/twopshs.py +1095 -0
- multioptpy/PESAnalyzer/__init__.py +0 -0
- multioptpy/PESAnalyzer/calc_irc_curvature.py +125 -0
- multioptpy/PESAnalyzer/cmds_analysis.py +152 -0
- multioptpy/PESAnalyzer/koopman_analysis.py +268 -0
- multioptpy/PESAnalyzer/pca_analysis.py +314 -0
- multioptpy/Parameters/__init__.py +0 -0
- multioptpy/Parameters/atomic_mass.py +20 -0
- multioptpy/Parameters/atomic_number.py +22 -0
- multioptpy/Parameters/covalent_radii.py +44 -0
- multioptpy/Parameters/d2.py +61 -0
- multioptpy/Parameters/d3.py +63 -0
- multioptpy/Parameters/d4.py +103 -0
- multioptpy/Parameters/dreiding.py +34 -0
- multioptpy/Parameters/gfn0xtb_param.py +137 -0
- multioptpy/Parameters/gfnff_param.py +315 -0
- multioptpy/Parameters/gnb.py +104 -0
- multioptpy/Parameters/parameter.py +22 -0
- multioptpy/Parameters/uff.py +72 -0
- multioptpy/Parameters/unit_values.py +20 -0
- multioptpy/Potential/AFIR_potential.py +55 -0
- multioptpy/Potential/LJ_repulsive_potential.py +345 -0
- multioptpy/Potential/__init__.py +0 -0
- multioptpy/Potential/anharmonic_keep_potential.py +28 -0
- multioptpy/Potential/asym_elllipsoidal_potential.py +718 -0
- multioptpy/Potential/electrostatic_potential.py +69 -0
- multioptpy/Potential/flux_potential.py +30 -0
- multioptpy/Potential/gaussian_potential.py +101 -0
- multioptpy/Potential/idpp.py +516 -0
- multioptpy/Potential/keep_angle_potential.py +146 -0
- multioptpy/Potential/keep_dihedral_angle_potential.py +105 -0
- multioptpy/Potential/keep_outofplain_angle_potential.py +70 -0
- multioptpy/Potential/keep_potential.py +99 -0
- multioptpy/Potential/mechano_force_potential.py +74 -0
- multioptpy/Potential/nanoreactor_potential.py +52 -0
- multioptpy/Potential/potential.py +896 -0
- multioptpy/Potential/spacer_model_potential.py +221 -0
- multioptpy/Potential/switching_potential.py +258 -0
- multioptpy/Potential/universal_potential.py +34 -0
- multioptpy/Potential/value_range_potential.py +36 -0
- multioptpy/Potential/void_point_potential.py +25 -0
- multioptpy/SQM/__init__.py +0 -0
- multioptpy/SQM/sqm1/__init__.py +0 -0
- multioptpy/SQM/sqm1/sqm1_core.py +1792 -0
- multioptpy/SQM/sqm2/__init__.py +0 -0
- multioptpy/SQM/sqm2/calc_tools.py +95 -0
- multioptpy/SQM/sqm2/sqm2_basis.py +850 -0
- multioptpy/SQM/sqm2/sqm2_bond.py +119 -0
- multioptpy/SQM/sqm2/sqm2_core.py +303 -0
- multioptpy/SQM/sqm2/sqm2_data.py +1229 -0
- multioptpy/SQM/sqm2/sqm2_disp.py +65 -0
- multioptpy/SQM/sqm2/sqm2_eeq.py +243 -0
- multioptpy/SQM/sqm2/sqm2_overlapint.py +704 -0
- multioptpy/SQM/sqm2/sqm2_qm.py +578 -0
- multioptpy/SQM/sqm2/sqm2_rep.py +66 -0
- multioptpy/SQM/sqm2/sqm2_srb.py +70 -0
- multioptpy/Thermo/__init__.py +0 -0
- multioptpy/Thermo/normal_mode_analyzer.py +865 -0
- multioptpy/Utils/__init__.py +0 -0
- multioptpy/Utils/bond_connectivity.py +264 -0
- multioptpy/Utils/calc_tools.py +884 -0
- multioptpy/Utils/oniom.py +96 -0
- multioptpy/Utils/pbc.py +48 -0
- multioptpy/Utils/riemann_curvature.py +208 -0
- multioptpy/Utils/symmetry_analyzer.py +482 -0
- multioptpy/Visualization/__init__.py +0 -0
- multioptpy/Visualization/visualization.py +156 -0
- multioptpy/WFAnalyzer/MO_analysis.py +104 -0
- multioptpy/WFAnalyzer/__init__.py +0 -0
- multioptpy/Wrapper/__init__.py +0 -0
- multioptpy/Wrapper/autots.py +1239 -0
- multioptpy/Wrapper/ieip_wrapper.py +93 -0
- multioptpy/Wrapper/md_wrapper.py +92 -0
- multioptpy/Wrapper/neb_wrapper.py +94 -0
- multioptpy/Wrapper/optimize_wrapper.py +76 -0
- multioptpy/__init__.py +5 -0
- multioptpy/entrypoints.py +916 -0
- multioptpy/fileio.py +660 -0
- multioptpy/ieip.py +340 -0
- multioptpy/interface.py +1086 -0
- multioptpy/irc.py +529 -0
- multioptpy/moleculardynamics.py +432 -0
- multioptpy/neb.py +1267 -0
- multioptpy/optimization.py +1553 -0
- multioptpy/optimizer.py +709 -0
- multioptpy-1.20.2.dist-info/METADATA +438 -0
- multioptpy-1.20.2.dist-info/RECORD +246 -0
- multioptpy-1.20.2.dist-info/WHEEL +5 -0
- multioptpy-1.20.2.dist-info/entry_points.txt +9 -0
- multioptpy-1.20.2.dist-info/licenses/LICENSE +674 -0
- multioptpy-1.20.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import scipy.linalg # Keep for potential future use, though not needed now
|
|
3
|
+
from scipy.optimize import minimize # Keep for potential future use
|
|
4
|
+
from typing import List, Tuple, Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class LineSearch:
|
|
8
|
+
"""
|
|
9
|
+
Stateful line search using simple energy decrease and extrapolation.
|
|
10
|
+
Accepts the last step that showed energy decrease.
|
|
11
|
+
Terminates if energy increases or if gradient becomes orthogonal (cosine < threshold).
|
|
12
|
+
Returns incremental steps compatible with cumulative updates.
|
|
13
|
+
"""
|
|
14
|
+
def __init__(self,
|
|
15
|
+
cos_threshold: float = 0.05, # Threshold for |cos(g_k, p)| to terminate
|
|
16
|
+
maxstep: float = 0.2,
|
|
17
|
+
damping: float = 0.8, # Start with a smaller initial step
|
|
18
|
+
stpmin: float = 1e-8, # Minimum allowed *incremental* alpha for extrapolation
|
|
19
|
+
stpmax: float = 5.0, # Max total alpha allowed
|
|
20
|
+
max_iterations: int = 10,
|
|
21
|
+
extrapolation_factor: float = 1.5 # Factor to increase alpha
|
|
22
|
+
):
|
|
23
|
+
"""Initializes the Simple Extrapolation LineSearch configuration."""
|
|
24
|
+
|
|
25
|
+
# --- Configuration ---
|
|
26
|
+
self.condition_type = 'simple_decrease_and_cosine' # Indicate the strategy
|
|
27
|
+
self.cos_threshold = cos_threshold # Cosine orthogonality condition
|
|
28
|
+
self.maxstep = maxstep
|
|
29
|
+
self.damping = damping
|
|
30
|
+
self.stpmin = stpmin
|
|
31
|
+
self.stpmax = stpmax
|
|
32
|
+
self.max_iterations = max_iterations
|
|
33
|
+
self.extrapolation_factor = extrapolation_factor
|
|
34
|
+
|
|
35
|
+
# --- Internal State ---
|
|
36
|
+
self.active_search = False
|
|
37
|
+
self.p = None # Fixed search direction vector
|
|
38
|
+
self.p_norm = None # Norm of the search direction vector
|
|
39
|
+
self.g0 = None # Gradient at geom0 (stored for info)
|
|
40
|
+
self.e0 = None # Energy at geom0
|
|
41
|
+
self.derphi0 = None # Directional derivative at geom0 (stored for info)
|
|
42
|
+
self.current_total_alpha = 0.0 # Total alpha from geom0 for the point *being evaluated*
|
|
43
|
+
self.current_iteration = 0
|
|
44
|
+
self.ITR = 0
|
|
45
|
+
self.geom0 = None # Coordinates at the start of the line search (x_k)
|
|
46
|
+
self.last_returned_total_alpha = 0.0 # Total alpha corresponding to the previous *returned* step
|
|
47
|
+
|
|
48
|
+
# --- State for this strategy ---
|
|
49
|
+
self.best_valid_total_alpha = 0.0 # Best total alpha found so far (energy decreased)
|
|
50
|
+
self.best_valid_phi = np.inf # Energy corresponding to best_valid_total_alpha
|
|
51
|
+
|
|
52
|
+
# --- Observation Lists (for debugging/record-keeping) ---
|
|
53
|
+
self.observed_alphas = []
|
|
54
|
+
self.observed_phis = []
|
|
55
|
+
self.observed_phi_primes = []
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _add_observation(self, total_alpha: float, phi: float, phi_prime: float) -> bool:
|
|
59
|
+
"""Adds observation (primarily for record keeping/debugging now)."""
|
|
60
|
+
|
|
61
|
+
if any(abs(total_alpha - a_obs) < np.finfo(float).eps * 10 for a_obs in self.observed_alphas):
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
self.observed_alphas.append(total_alpha)
|
|
65
|
+
self.observed_phis.append(phi)
|
|
66
|
+
self.observed_phi_primes.append(phi_prime)
|
|
67
|
+
|
|
68
|
+
data = sorted(zip(self.observed_alphas, self.observed_phis, self.observed_phi_primes))
|
|
69
|
+
self.observed_alphas, self.observed_phis, self.observed_phi_primes = [list(t) for t in zip(*data)]
|
|
70
|
+
|
|
71
|
+
return True
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def run(self, geom_num_list, gradient, prev_gradient, energy, prev_energy, move_vector):
|
|
75
|
+
"""
|
|
76
|
+
Performs one stateful iteration of the simple extrapolation line search.
|
|
77
|
+
Returns the INCREMENTAL step vector.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
if not self.active_search:
|
|
81
|
+
# --- Start a New Line Search ---
|
|
82
|
+
print(f"\n===== Starting Line Search (Cosine Thresh={self.cos_threshold}, damp={self.damping}) =====")
|
|
83
|
+
|
|
84
|
+
self.active_search = True
|
|
85
|
+
self.current_iteration = 0
|
|
86
|
+
self.p = np.asarray(move_vector).reshape(-1)
|
|
87
|
+
self.g0 = np.asarray(prev_gradient).reshape(-1)
|
|
88
|
+
self.e0 = float(prev_energy)
|
|
89
|
+
self.geom0 = np.asarray(geom_num_list).reshape(-1)
|
|
90
|
+
self.derphi0 = np.dot(self.g0, self.p)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# Store the norm of the (final) search direction
|
|
94
|
+
self.p_norm = np.linalg.norm(self.p)
|
|
95
|
+
|
|
96
|
+
# --- Initialize Search State ---
|
|
97
|
+
self.best_valid_total_alpha = 0.0
|
|
98
|
+
self.best_valid_phi = self.e0
|
|
99
|
+
self.last_returned_total_alpha = 0.0
|
|
100
|
+
|
|
101
|
+
self.observed_alphas = []
|
|
102
|
+
self.observed_phis = []
|
|
103
|
+
self.observed_phi_primes = []
|
|
104
|
+
self._add_observation(0.0, self.e0, self.derphi0)
|
|
105
|
+
|
|
106
|
+
# --- Calculate Initial Step ---
|
|
107
|
+
p_norm_max = np.max(np.abs(self.p)) # Use max component for scaling
|
|
108
|
+
if p_norm_max < 1e-10:
|
|
109
|
+
print("Warning: Move vector max component is zero.")
|
|
110
|
+
self.active_search = False
|
|
111
|
+
self.geom0 = None
|
|
112
|
+
return np.zeros_like(self.p.reshape(-1, 1))
|
|
113
|
+
|
|
114
|
+
scale = abs(self.maxstep / p_norm_max)
|
|
115
|
+
|
|
116
|
+
next_total_alpha = min(1.0, scale) * self.damping
|
|
117
|
+
|
|
118
|
+
next_total_alpha = np.clip(next_total_alpha, self.stpmin, self.stpmax)
|
|
119
|
+
|
|
120
|
+
print(f"Start E: {self.e0:.6f}, Deriv (g0.p): {self.derphi0:.6f}")
|
|
121
|
+
print(f"Initial trial total alpha: {next_total_alpha:.6f} (using damping={self.damping})")
|
|
122
|
+
|
|
123
|
+
self.current_total_alpha = next_total_alpha
|
|
124
|
+
incremental_alpha = self.current_total_alpha - self.last_returned_total_alpha
|
|
125
|
+
|
|
126
|
+
return incremental_alpha * self.p.reshape(-1, 1)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# --- Continue Existing Line Search Iteration ---
|
|
130
|
+
print(f"\n--- Line Search Iteration {self.current_iteration} (eval total alpha={self.current_total_alpha:.6f}) ---")
|
|
131
|
+
|
|
132
|
+
self.current_iteration += 1
|
|
133
|
+
current_geom = np.asarray(geom_num_list).reshape(-1)
|
|
134
|
+
e_curr = float(energy)
|
|
135
|
+
g_curr = np.asarray(gradient).reshape(-1)
|
|
136
|
+
|
|
137
|
+
derphi_curr = np.dot(g_curr, self.p)
|
|
138
|
+
|
|
139
|
+
_ = self._add_observation(self.current_total_alpha, e_curr, derphi_curr)
|
|
140
|
+
|
|
141
|
+
print(f"E_curr: {e_curr:.6f}")
|
|
142
|
+
if self.geom0 is not None:
|
|
143
|
+
norm_diff = np.linalg.norm(current_geom - self.geom0)
|
|
144
|
+
print(f" Norm diff from start: {norm_diff:.6f}")
|
|
145
|
+
|
|
146
|
+
terminate = False
|
|
147
|
+
accepted_total_alpha = 0.0
|
|
148
|
+
|
|
149
|
+
# --- Check Conditions ---
|
|
150
|
+
|
|
151
|
+
if e_curr < self.best_valid_phi:
|
|
152
|
+
# --- Energy Decreased: Update best and check cosine condition ---
|
|
153
|
+
print(f"Energy decreased to {e_curr:.6f}.")
|
|
154
|
+
|
|
155
|
+
self.best_valid_total_alpha = self.current_total_alpha
|
|
156
|
+
self.best_valid_phi = e_curr
|
|
157
|
+
|
|
158
|
+
# --- NEW: Check cosine condition (g_k orthogonal to p) ---
|
|
159
|
+
g_norm = np.linalg.norm(g_curr)
|
|
160
|
+
denominator = g_norm * self.p_norm
|
|
161
|
+
|
|
162
|
+
cosine_theta = 0.0
|
|
163
|
+
if denominator < 1e-15:
|
|
164
|
+
# Gradient norm or p norm is zero.
|
|
165
|
+
# If g_norm is zero, we are at a minimum, so accept.
|
|
166
|
+
cosine_theta = 0.0
|
|
167
|
+
print(" Note: Gradient norm is near zero.")
|
|
168
|
+
else:
|
|
169
|
+
# cosine_theta = (g_k . p) / (||g_k|| * ||p||)
|
|
170
|
+
cosine_theta = derphi_curr / denominator
|
|
171
|
+
|
|
172
|
+
print(f" Checking cosine(g_curr, p): |cos(theta)|={abs(cosine_theta):.6f} vs threshold={self.cos_threshold:.6f}")
|
|
173
|
+
|
|
174
|
+
if abs(cosine_theta) < self.cos_threshold:
|
|
175
|
+
print(" Cosine condition met (gradient orthogonal to search). Accepting this step.")
|
|
176
|
+
terminate = True
|
|
177
|
+
accepted_total_alpha = self.current_total_alpha
|
|
178
|
+
|
|
179
|
+
else:
|
|
180
|
+
# --- Cosine NOT met: Extrapolate ---
|
|
181
|
+
print(" Cosine not met. Extrapolating.")
|
|
182
|
+
|
|
183
|
+
next_total_alpha = self.current_total_alpha * self.extrapolation_factor
|
|
184
|
+
next_total_alpha = np.clip(next_total_alpha, self.stpmin, self.stpmax)
|
|
185
|
+
|
|
186
|
+
next_incremental_alpha = next_total_alpha - self.current_total_alpha
|
|
187
|
+
|
|
188
|
+
if abs(next_incremental_alpha) < self.stpmin:
|
|
189
|
+
print(f"Warning: Extrapolation step too small ({next_incremental_alpha:.2e}). Accepting current best step.")
|
|
190
|
+
terminate = True
|
|
191
|
+
accepted_total_alpha = self.best_valid_total_alpha
|
|
192
|
+
elif self.current_iteration >= self.max_iterations:
|
|
193
|
+
print("Warning: Max iterations reached during extrapolation. Accepting last successful step.")
|
|
194
|
+
terminate = True
|
|
195
|
+
accepted_total_alpha = self.best_valid_total_alpha
|
|
196
|
+
|
|
197
|
+
if not terminate:
|
|
198
|
+
self.last_returned_total_alpha = self.current_total_alpha
|
|
199
|
+
self.current_total_alpha = next_total_alpha
|
|
200
|
+
return next_incremental_alpha * self.p.reshape(-1, 1)
|
|
201
|
+
|
|
202
|
+
else:
|
|
203
|
+
# --- Energy Increased: Terminate ---
|
|
204
|
+
print(f"Energy increased or stalled (E_curr={e_curr:.6f} >= E_best={self.best_valid_phi:.6f}). Accepting previous best step.")
|
|
205
|
+
terminate = True
|
|
206
|
+
accepted_total_alpha = self.best_valid_total_alpha
|
|
207
|
+
|
|
208
|
+
# --- Handle Termination ---
|
|
209
|
+
if terminate:
|
|
210
|
+
if accepted_total_alpha <= 0:
|
|
211
|
+
print("No energy decrease found compared to start. Returning zero incremental step.")
|
|
212
|
+
incremental_alpha = 0.0 - self.current_total_alpha
|
|
213
|
+
accepted_phi = self.e0
|
|
214
|
+
else:
|
|
215
|
+
print(f"Accepting total alpha: {accepted_total_alpha:.6f} with E={self.best_valid_phi:.6f}")
|
|
216
|
+
incremental_alpha = accepted_total_alpha - self.current_total_alpha
|
|
217
|
+
accepted_phi = self.best_valid_phi
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
print(f"===== Line Search Complete =====")
|
|
221
|
+
print(f"Final total alpha: {accepted_total_alpha:.6f}")
|
|
222
|
+
print(f"Final energy: {accepted_phi:.6f} (improvement: {self.e0 - accepted_phi:.6f})")
|
|
223
|
+
|
|
224
|
+
self.ITR += 1
|
|
225
|
+
print(f"Total line searches completed: {self.ITR}")
|
|
226
|
+
|
|
227
|
+
self.active_search = False
|
|
228
|
+
self.geom0 = None
|
|
229
|
+
|
|
230
|
+
return incremental_alpha * self.p.reshape(-1, 1)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
print("Error: Line search reached unexpected state.")
|
|
234
|
+
self.active_search = False
|
|
235
|
+
self.geom0 = None
|
|
236
|
+
return np.zeros_like(self.p.reshape(-1, 1))
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import copy
|
|
3
|
+
|
|
4
|
+
class LookAhead:
|
|
5
|
+
def __init__(self, k=10, alpha=0.5, **config):
|
|
6
|
+
#LookAhead algorithm
|
|
7
|
+
#ref. arXiv:1907.08610
|
|
8
|
+
self.iter = 0
|
|
9
|
+
self.alpha = alpha
|
|
10
|
+
self.k = k
|
|
11
|
+
self.config = config
|
|
12
|
+
self.slow_geom_num_list = []
|
|
13
|
+
self.fast_geom_num_list_history = []
|
|
14
|
+
self.fast_energy_history = []
|
|
15
|
+
|
|
16
|
+
return
|
|
17
|
+
|
|
18
|
+
def run(self, geom_num_list, B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_move_vector, initial_geom_num_list, g, pre_g, move_vector):
|
|
19
|
+
print("LookAhead")
|
|
20
|
+
if self.iter % self.k != 0 or self.iter == 0:
|
|
21
|
+
self.slow_geom_num_list = geom_num_list
|
|
22
|
+
self.fast_geom_num_list_history.append(geom_num_list)
|
|
23
|
+
self.fast_energy_history.append(B_e)
|
|
24
|
+
|
|
25
|
+
else:
|
|
26
|
+
print("update slow geometry...")
|
|
27
|
+
move_vector = []
|
|
28
|
+
self.fast_geom_num_list_history.append(geom_num_list)
|
|
29
|
+
self.fast_energy_history.append(B_e)
|
|
30
|
+
best_fast_geom_num_list = self.fast_geom_num_list_history[np.argmin(self.fast_energy_history)]
|
|
31
|
+
new_geom_num_list = self.alpha * self.slow_geom_num_list + (1.0-self.alpha) * best_fast_geom_num_list
|
|
32
|
+
|
|
33
|
+
move_vector = -1 * (new_geom_num_list - geom_num_list)
|
|
34
|
+
|
|
35
|
+
self.slow_geom_num_list = best_fast_geom_num_list
|
|
36
|
+
self.fast_geom_num_list_history = []
|
|
37
|
+
self.fast_energy_history = []
|
|
38
|
+
|
|
39
|
+
self.iter += 1
|
|
40
|
+
return move_vector#Bohr
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import copy
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class NAdam:
|
|
7
|
+
def __init__(self, **config):
|
|
8
|
+
#https://cs229.stanford.edu/proj2015/054_report.pdf
|
|
9
|
+
self.adam_count = 1
|
|
10
|
+
self.DELTA = 0.06
|
|
11
|
+
self.beta_m = 0.9
|
|
12
|
+
self.beta_v = 0.999
|
|
13
|
+
self.Epsilon = 1e-8
|
|
14
|
+
self.Initialization = True
|
|
15
|
+
self.mu = 0.975
|
|
16
|
+
self.nu = 0.999
|
|
17
|
+
self.config = config
|
|
18
|
+
self.hessian = None
|
|
19
|
+
self.bias_hessian = None
|
|
20
|
+
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
def run(self, geom_num_list, B_g, pre_B_g=[], pre_geom=[], B_e=0.0, pre_B_e=0.0, pre_move_vector=[], initial_geom_num_list=[], g=[], pre_g=[]):
|
|
24
|
+
print("NAdam")
|
|
25
|
+
if self.Initialization:
|
|
26
|
+
self.adam_m = geom_num_list * 0.0
|
|
27
|
+
self.adam_v = geom_num_list * 0.0
|
|
28
|
+
self.Initialization = False
|
|
29
|
+
|
|
30
|
+
adam_count = self.adam_count
|
|
31
|
+
adam_m = self.adam_m
|
|
32
|
+
adam_v = self.adam_v
|
|
33
|
+
new_adam_m = adam_m*0.0
|
|
34
|
+
new_adam_v = adam_v*0.0
|
|
35
|
+
|
|
36
|
+
new_adam_m_hat = []
|
|
37
|
+
new_adam_v_hat = []
|
|
38
|
+
for i in range(len(geom_num_list)):
|
|
39
|
+
new_adam_m[i] = copy.copy(self.mu*adam_m[i] + (1.0 - self.mu)*(B_g[i]))
|
|
40
|
+
new_adam_v[i] = copy.copy((self.nu*adam_v[i]) + (1.0 - self.nu)*(B_g[i]) ** 2)
|
|
41
|
+
new_adam_m_hat.append(np.array(new_adam_m[i], dtype="float64") * ( self.mu / (1.0 - self.mu ** adam_count)) + np.array(B_g[i], dtype="float64") * ((1.0 - self.mu)/(1.0 - self.mu ** adam_count)))
|
|
42
|
+
new_adam_v_hat.append(np.array(new_adam_v[i], dtype="float64") * (self.nu / (1.0 - self.nu ** adam_count)))
|
|
43
|
+
|
|
44
|
+
move_vector = []
|
|
45
|
+
for i in range(len(geom_num_list)):
|
|
46
|
+
move_vector.append( (self.DELTA*new_adam_m_hat[i]) / (np.sqrt(new_adam_v_hat[i] + self.Epsilon)))
|
|
47
|
+
self.adam_m = new_adam_m
|
|
48
|
+
self.adam_v = new_adam_v
|
|
49
|
+
self.adam_count += 1
|
|
50
|
+
|
|
51
|
+
return move_vector#Bohr
|
|
52
|
+
def set_hessian(self, hessian):
|
|
53
|
+
self.hessian = hessian
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
def set_bias_hessian(self, bias_hessian):
|
|
57
|
+
self.bias_hessian = bias_hessian
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
def get_hessian(self):
|
|
61
|
+
return self.hessian
|
|
62
|
+
|
|
63
|
+
def get_bias_hessian(self):
|
|
64
|
+
return self.bias_hessian
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
from .linesearch import LineSearch
|
|
2
|
+
from .hessian_update import ModelHessianUpdate
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
class Newton:
|
|
6
|
+
def __init__(self, **config):
|
|
7
|
+
self.config = config
|
|
8
|
+
self.hess_update = ModelHessianUpdate()
|
|
9
|
+
self.Initialization = True
|
|
10
|
+
self.linesearchflag = False
|
|
11
|
+
self.optimal_step_flag = False
|
|
12
|
+
self.DELTA = 0.5
|
|
13
|
+
self.FC_COUNT = -1 #
|
|
14
|
+
self.saddle_order = 0 #
|
|
15
|
+
self.iter = 0 #
|
|
16
|
+
self.beta = 0.5
|
|
17
|
+
self.hessian = None
|
|
18
|
+
self.bias_hessian = None
|
|
19
|
+
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
def project_out_hess_tr_and_rot_for_coord(self, hessian, geomerty):#do not consider atomic mass
|
|
23
|
+
natoms = len(geomerty)
|
|
24
|
+
|
|
25
|
+
geomerty -= self.calc_center(geomerty)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
tr_x = (np.tile(np.array([1, 0, 0]), natoms)).reshape(-1, 3)
|
|
29
|
+
tr_y = (np.tile(np.array([0, 1, 0]), natoms)).reshape(-1, 3)
|
|
30
|
+
tr_z = (np.tile(np.array([0, 0, 1]), natoms)).reshape(-1, 3)
|
|
31
|
+
|
|
32
|
+
rot_x = np.cross(geomerty, tr_x).flatten()
|
|
33
|
+
rot_y = np.cross(geomerty, tr_y).flatten()
|
|
34
|
+
rot_z = np.cross(geomerty, tr_z).flatten()
|
|
35
|
+
tr_x = tr_x.flatten()
|
|
36
|
+
tr_y = tr_y.flatten()
|
|
37
|
+
tr_z = tr_z.flatten()
|
|
38
|
+
|
|
39
|
+
TR_vectors = np.vstack([tr_x, tr_y, tr_z, rot_x, rot_y, rot_z])
|
|
40
|
+
|
|
41
|
+
Q, R = np.linalg.qr(TR_vectors.T)
|
|
42
|
+
keep_indices = ~np.isclose(np.diag(R), 0, atol=1e-6, rtol=0)
|
|
43
|
+
TR_vectors = Q.T[keep_indices]
|
|
44
|
+
n_tr = len(TR_vectors)
|
|
45
|
+
|
|
46
|
+
P = np.identity(natoms * 3)
|
|
47
|
+
for vector in TR_vectors:
|
|
48
|
+
P -= np.outer(vector, vector)
|
|
49
|
+
|
|
50
|
+
hess_proj = np.dot(np.dot(P.T, hessian), P)
|
|
51
|
+
|
|
52
|
+
return hess_proj
|
|
53
|
+
|
|
54
|
+
def calc_center(self, geomerty, element_list=[]):#geomerty:Bohr
|
|
55
|
+
center = np.array([0.0, 0.0, 0.0], dtype="float64")
|
|
56
|
+
for i in range(len(geomerty)):
|
|
57
|
+
|
|
58
|
+
center += geomerty[i]
|
|
59
|
+
center /= float(len(geomerty))
|
|
60
|
+
|
|
61
|
+
return center
|
|
62
|
+
|
|
63
|
+
def set_hessian(self, hessian):
|
|
64
|
+
self.hessian = hessian
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
def set_bias_hessian(self, bias_hessian):
|
|
68
|
+
self.bias_hessian = bias_hessian
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
def get_hessian(self):
|
|
72
|
+
return self.hessian
|
|
73
|
+
|
|
74
|
+
def get_bias_hessian(self):
|
|
75
|
+
return self.bias_hessian
|
|
76
|
+
|
|
77
|
+
def hessian_update(self, displacement, delta_grad):
|
|
78
|
+
if "msp" in self.config["method"].lower():
|
|
79
|
+
print("MSP_quasi_newton_method")
|
|
80
|
+
delta_hess = self.hess_update.MSP_hessian_update(self.hessian, displacement, delta_grad)
|
|
81
|
+
elif "bfgs" in self.config["method"].lower():
|
|
82
|
+
print("BFGS_quasi_newton_method")
|
|
83
|
+
delta_hess = self.hess_update.BFGS_hessian_update(self.hessian, displacement, delta_grad)
|
|
84
|
+
elif "fsb" in self.config["method"].lower():
|
|
85
|
+
print("FSB_quasi_newton_method")
|
|
86
|
+
delta_hess = self.hess_update.FSB_hessian_update(self.hessian, displacement, delta_grad)
|
|
87
|
+
elif "bofill" in self.config["method"].lower():
|
|
88
|
+
print("Bofill_quasi_newton_method")
|
|
89
|
+
delta_hess = self.hess_update.Bofill_hessian_update(self.hessian, displacement, delta_grad)
|
|
90
|
+
else:
|
|
91
|
+
raise "method error"
|
|
92
|
+
return delta_hess
|
|
93
|
+
|
|
94
|
+
def normal(self, geom_num_list, B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_g, g):
|
|
95
|
+
|
|
96
|
+
if self.linesearchflag:
|
|
97
|
+
print("linesearch mode")
|
|
98
|
+
else:
|
|
99
|
+
print("normal mode")
|
|
100
|
+
if self.Initialization:
|
|
101
|
+
self.Initialization = False
|
|
102
|
+
return self.DELTA*B_g
|
|
103
|
+
|
|
104
|
+
delta_grad = (g - pre_g).reshape(len(geom_num_list), 1)
|
|
105
|
+
displacement = (geom_num_list - pre_geom).reshape(len(geom_num_list), 1)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
delta_hess = self.hessian_update(displacement, delta_grad)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if self.iter % self.FC_COUNT != 0 or self.FC_COUNT == -1:
|
|
112
|
+
new_hess = self.hessian + delta_hess + self.bias_hessian
|
|
113
|
+
else:
|
|
114
|
+
new_hess = self.hessian + self.bias_hessian
|
|
115
|
+
|
|
116
|
+
DELTA_for_QNM = self.DELTA
|
|
117
|
+
|
|
118
|
+
move_vector = DELTA_for_QNM * np.linalg.solve(new_hess, B_g.reshape(len(geom_num_list), 1))
|
|
119
|
+
|
|
120
|
+
if self.iter > 1 and self.linesearchflag:
|
|
121
|
+
if self.FC_COUNT != -1:
|
|
122
|
+
tmp_hess = self.project_out_hess_tr_and_rot_for_coord(new_hess, geom_num_list.reshape(-1, 3))
|
|
123
|
+
else:
|
|
124
|
+
tmp_hess = None
|
|
125
|
+
if self.optimal_step_flag or self.iter == 2:
|
|
126
|
+
self.LS = LineSearch(self.prev_move_vector, move_vector, B_g, pre_B_g, B_e, pre_B_e, tmp_hess)
|
|
127
|
+
|
|
128
|
+
new_move_vector, self.optimal_step_flag = self.LS.linesearch(self.prev_move_vector, move_vector, B_g, pre_B_g, B_e, pre_B_e, tmp_hess)
|
|
129
|
+
else:
|
|
130
|
+
new_move_vector = move_vector
|
|
131
|
+
self.optimal_step_flag = True
|
|
132
|
+
|
|
133
|
+
print("step size: ",DELTA_for_QNM,"\n")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
if self.iter > 0 and self.linesearchflag:
|
|
137
|
+
move_vector = -new_move_vector
|
|
138
|
+
if self.optimal_step_flag or self.iter == 1:
|
|
139
|
+
self.prev_move_vector = move_vector
|
|
140
|
+
|
|
141
|
+
if not self.linesearchflag or np.linalg.norm(move_vector) > 1e-4:
|
|
142
|
+
self.hessian += delta_hess
|
|
143
|
+
|
|
144
|
+
self.iter += 1
|
|
145
|
+
return move_vector#Bohr
|
|
146
|
+
|
|
147
|
+
# arXiv:2307.13744v1
|
|
148
|
+
def moment(self, geom_num_list, B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_g, g):
|
|
149
|
+
print("moment mode")
|
|
150
|
+
if self.Initialization:
|
|
151
|
+
self.momentum_disp = geom_num_list * 0.0
|
|
152
|
+
self.momentum_grad = geom_num_list * 0.0
|
|
153
|
+
self.Initialization = False
|
|
154
|
+
return self.DELTA*B_g
|
|
155
|
+
|
|
156
|
+
if self.iter == 1:
|
|
157
|
+
self.momentum_disp = geom_num_list - pre_geom
|
|
158
|
+
self.momentum_grad = B_g - pre_B_g
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
delta_grad = (B_g - pre_B_g).reshape(len(geom_num_list), 1)
|
|
162
|
+
displacement = (geom_num_list - pre_geom).reshape(len(geom_num_list), 1)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
new_momentum_disp = self.beta * self.momentum_disp + (1.0 - self.beta) * geom_num_list
|
|
167
|
+
new_momentum_grad = self.beta * self.momentum_grad + (1.0 - self.beta) * B_g
|
|
168
|
+
|
|
169
|
+
delta_momentum_disp = (new_momentum_disp - self.momentum_disp).reshape(len(geom_num_list), 1)
|
|
170
|
+
delta_momentum_grad = (new_momentum_grad - self.momentum_grad).reshape(len(geom_num_list), 1)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
delta_hess = self.hessian_update(delta_momentum_disp, delta_momentum_grad)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
if self.iter % self.FC_COUNT != 0 or self.FC_COUNT == -1:
|
|
177
|
+
new_hess = self.hessian + delta_hess + self.bias_hessian
|
|
178
|
+
else:
|
|
179
|
+
new_hess = self.hessian + self.bias_hessian
|
|
180
|
+
|
|
181
|
+
DELTA_for_QNM = self.DELTA
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
#move_vector = (DELTA_for_QNM*np.dot(np.linalg.inv(new_hess), B_g.reshape(len(geom_num_list), 1))).reshape(len(geom_num_list), 3)
|
|
185
|
+
move_vector = DELTA_for_QNM * np.linalg.solve(new_hess, B_g.reshape(len(geom_num_list), 1))
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
print("step size: ",DELTA_for_QNM,"\n")
|
|
189
|
+
self.hessian += delta_hess
|
|
190
|
+
self.iter += 1
|
|
191
|
+
self.momentum_disp = new_momentum_disp
|
|
192
|
+
self.momentum_grad = new_momentum_grad
|
|
193
|
+
return move_vector
|
|
194
|
+
|
|
195
|
+
def run(self, geom_num_list, B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_move_vector, initial_geom_num_list, g, pre_g):
|
|
196
|
+
if self.config["method"] == "mBFGS" or self.config["method"] == "mFSB" or self.config["method"] == "mMSP" or self.config["method"] == "mBofill":
|
|
197
|
+
move_vector = self.moment(geom_num_list, B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_g, g)
|
|
198
|
+
else:
|
|
199
|
+
move_vector = self.normal(geom_num_list, B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_g, g)
|
|
200
|
+
return move_vector
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import copy
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Prodigy:
|
|
6
|
+
def __init__(self, **config):
|
|
7
|
+
#Prodigy
|
|
8
|
+
#arXiv:2306.06101v1
|
|
9
|
+
self.adam_count = 1
|
|
10
|
+
self.d = 0.03
|
|
11
|
+
self.beta_m = 0.9
|
|
12
|
+
self.beta_v = 0.999
|
|
13
|
+
self.DELTA = 0.1
|
|
14
|
+
self.Epsilon = 1e-12
|
|
15
|
+
self.Initialization = True
|
|
16
|
+
self.config = config
|
|
17
|
+
self.hessian = None
|
|
18
|
+
self.bias_hessian = None
|
|
19
|
+
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
def run(self, geom_num_list, B_g, pre_B_g, pre_geom, B_e, pre_B_e, pre_move_vector, initial_geom_num_list, g=[], pre_g=[]):
|
|
23
|
+
print("Prodigy")
|
|
24
|
+
|
|
25
|
+
if self.Initialization:
|
|
26
|
+
self.adam_m = geom_num_list * 0.0
|
|
27
|
+
self.adam_v = geom_num_list * 0.0
|
|
28
|
+
self.adam_s = geom_num_list * 0.0
|
|
29
|
+
self.adam_r = 0.0
|
|
30
|
+
new_d = self.d
|
|
31
|
+
self.initial_geom_num_list = geom_num_list
|
|
32
|
+
self.Initialization = False
|
|
33
|
+
|
|
34
|
+
new_adam_m = self.adam_m*0.0
|
|
35
|
+
new_adam_v = self.adam_v*0.0
|
|
36
|
+
new_adam_s = self.adam_s*0.0
|
|
37
|
+
|
|
38
|
+
for i in range(len(geom_num_list)):
|
|
39
|
+
new_adam_m[i] = copy.copy(self.beta_m*self.adam_m[i] + (1.0-self.beta_m)*(B_g[i]*self.d))
|
|
40
|
+
new_adam_v[i] = copy.copy(self.beta_v*self.adam_v[i] + (1.0-self.beta_v)*(B_g[i]*self.d)**2)
|
|
41
|
+
new_adam_s[i] = np.sqrt(self.beta_v)*self.adam_s[i] + (1.0 - np.sqrt(self.beta_v))*self.DELTA*B_g[i]*self.d**2
|
|
42
|
+
|
|
43
|
+
new_adam_r = np.sqrt(self.beta_v)*self.adam_r + (1.0 - np.sqrt(self.beta_v))*(np.dot(B_g.reshape(1,len(B_g)), (self.initial_geom_num_list - geom_num_list).reshape(len(B_g),1)))*self.DELTA*self.d**2
|
|
44
|
+
|
|
45
|
+
new_d = float(max((new_adam_r / np.linalg.norm(new_adam_s ,ord=1)), self.d))
|
|
46
|
+
move_vector = []
|
|
47
|
+
|
|
48
|
+
for i in range(len(geom_num_list)):
|
|
49
|
+
move_vector.append(self.DELTA*new_d*new_adam_m[i]/(np.sqrt(new_adam_v[i])+self.Epsilon*self.d))
|
|
50
|
+
|
|
51
|
+
self.adam_m = new_adam_m
|
|
52
|
+
self.adam_v = new_adam_v
|
|
53
|
+
self.adam_r = new_adam_r
|
|
54
|
+
self.d = new_d
|
|
55
|
+
self.adam_count += 1
|
|
56
|
+
return move_vector
|
|
57
|
+
|
|
58
|
+
def set_hessian(self, hessian):
|
|
59
|
+
self.hessian = hessian
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
def set_bias_hessian(self, bias_hessian):
|
|
63
|
+
self.bias_hessian = bias_hessian
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
def get_hessian(self):
|
|
67
|
+
return self.hessian
|
|
68
|
+
|
|
69
|
+
def get_bias_hessian(self):
|
|
70
|
+
return self.bias_hessian
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
class Perturbation:
|
|
4
|
+
def __init__(self, **config):
|
|
5
|
+
self.config = config
|
|
6
|
+
self.DELTA = 0.06
|
|
7
|
+
self.Boltzmann_constant = 3.16681*10**(-6) # hartree/K
|
|
8
|
+
self.damping_coefficient = 10.0
|
|
9
|
+
self.temperature = self.config["temperature"]
|
|
10
|
+
return
|
|
11
|
+
def boltzmann_dist_perturb(self, move_vector):#This function is just for fun. Thus, it is no scientific basis.
|
|
12
|
+
|
|
13
|
+
temperature = self.temperature
|
|
14
|
+
perturbation = self.DELTA * np.sqrt(2.0 * self.damping_coefficient * self.Boltzmann_constant * temperature) * np.random.normal(loc=0.0, scale=1.0, size=len(move_vector)).reshape(len(move_vector), 1)
|
|
15
|
+
|
|
16
|
+
return perturbation
|