* Algorithm for the trust region step_in_trust_region: Computes the step in the trust region (delta) (automatically sets at the iteration 0 and which evolves during the process in function of the evolution of rho). The step is computing by constraining its norm with a lagrange multiplier. Since the calculation of the step is based on the Newton method, an estimation of the gain in energy is given using the Taylors series truncated at the second order (criterion_model). If (DABS(criterion-criterion_model) < 1d-12) then must_exit = .True. else must_exit = .False. This estimation of the gain in energy is used by is_step_cancel_trust_region to say if the step is accepted or cancelled. If the step must be cancelled, the calculation restart from the same hessian and gradient and recomputes the step but in a smaller trust region and so on until the step is accepted. If the step is accepted the hessian and the gradient are recomputed to produce a new step. Example: #+BEGIN_SRC f90 :comments org :tangle algo_trust.irp.f ! !### Initialization ### ! delta = 0d0 ! nb_iter = 0 ! Must start at 0 !!! ! rho = 0.5d0 ! not_converged = .True. ! ! ! ### TODO ### ! ! Compute the criterion before the loop ! call #your_criterion(prev_criterion) ! ! do while (not_converged) ! ! ### TODO ## ! ! Call your gradient ! ! Call you hessian ! call #your_gradient(v_grad) (1D array) ! call #your_hessian(H) (2D array) ! ! ! ### TODO ### ! ! Diagonalization of the hessian ! call diagonalization_hessian(n,H,e_val,w) ! ! cancel_step = .True. ! To enter in the loop just after ! ! Loop to Reduce the trust radius until the criterion decreases and rho >= thresh_rho ! do while (cancel_step) ! ! ! Hessian,gradient,Criterion -> x ! call trust_region_step_w_expected_e(tmp_n,W,e_val,v_grad,prev_criterion,rho,nb_iter,delta,criterion_model,tmp_x,must_exit) ! ! if (must_exit) then ! ! ### Message ### ! ! if step_in_trust_region sets must_exit on true for numerical reasons ! print*,'algo_trust1 sends the message : Exit' ! !### exit ### ! endif ! ! !### TODO ### ! ! Compute x -> m_x ! ! Compute m_x -> R ! ! Apply R and keep the previous MOs... ! ! Update/touch ! ! Compute the new criterion/energy -> criterion ! ! call #your_routine_1D_to_2D_antisymmetric_array(x,m_x) ! call #your_routine_2D_antisymmetric_array_to_rotation_matrix(m_x,R) ! call #your_routine_to_apply_the_rotation_matrix(R,prev_mos) ! ! TOUCH #your_variables ! ! call #your_criterion(criterion) ! ! ! Criterion -> step accepted or rejected ! call trust_region_is_step_cancelled(nb_iter,prev_criterion, criterion, criterion_model,rho,cancel_step) ! ! ! ### TODO ### ! !if (cancel_step) then ! ! Cancel the previous step (mo_coef = prev_mos if you keep them...) ! !endif ! #if (cancel_step) then ! #mo_coef = prev_mos ! #endif ! ! enddo ! ! !call save_mos() !### depend of the time for 1 iteration ! ! ! To exit the external loop if must_exit = .True. ! if (must_exit) then ! !### exit ### ! endif ! ! ! Step accepted, nb iteration + 1 ! nb_iter = nb_iter + 1 ! ! ! ### TODO ### ! !if (###Conditions###) then ! ! no_converged = .False. ! !endif ! #if (#your_conditions) then ! # not_converged = .False. ! #endif ! ! enddo #+END_SRC Variables: Input: | n | integer | m*(m-1)/2 | | m | integer | number of mo in the mo_class | | H(n,n) | double precision | Hessian | | v_grad(n) | double precision | Gradient | | W(n,n) | double precision | Eigenvectors of the hessian | | e_val(n) | double precision | Eigenvalues of the hessian | | criterion | double precision | Actual criterion | | prev_criterion | double precision | Value of the criterion before the first iteration/after the previous iteration | | rho | double precision | Given by is_step_cancel_trus_region | | | | Agreement between the real function and the Taylor series (2nd order) | | nb_iter | integer | Actual number of iterations | Input/output: | delta | double precision | Radius of the trust region | Output: | criterion_model | double precision | Predicted criterion after the rotation | | x(n) | double precision | Step | | must_exit | logical | If the program must exit the loop | #+BEGIN_SRC f90 :comments org :tangle algo_trust.irp.f subroutine trust_region_step_w_expected_e(n,n2,H,W,e_val,v_grad,prev_criterion,rho,nb_iter,delta,criterion_model,x,must_exit) include 'pi.h' !BEGIN_DOC ! Compute the step and the expected criterion/energy after the step !END_DOC implicit none ! in integer, intent(in) :: n,n2, nb_iter double precision, intent(in) :: H(n,n2), W(n,n2), v_grad(n) double precision, intent(in) :: rho, prev_criterion ! inout double precision, intent(inout) :: delta, e_val(n) ! out double precision, intent(out) :: criterion_model, x(n) logical, intent(out) :: must_exit ! internal integer :: info must_exit = .False. call trust_region_step(n,n2,nb_iter,v_grad,rho,e_val,W,x,delta) call trust_region_expected_e(n,n2,v_grad,H,x,prev_criterion,criterion_model) ! exit if DABS(prev_criterion - criterion_model) < 1d-12 if (DABS(prev_criterion - criterion_model) < thresh_model) then print*,'' print*,'###############################################################################' print*,'DABS(prev_criterion - criterion_model) <', thresh_model, 'stop the trust region' print*,'###############################################################################' print*,'' must_exit = .True. endif if (delta < thresh_delta) then print*,'' print*,'##############################################' print*,'Delta <', thresh_delta, 'stop the trust region' print*,'##############################################' print*,'' must_exit = .True. endif ! Add after the call to this subroutine, a statement: ! "if (must_exit) then ! exit ! endif" ! in order to exit the optimization loop end subroutine #+END_SRC Variables: Input: | nb_iter | integer | actual number of iterations | | prev_criterion | double precision | criterion before the application of the step x | | criterion | double precision | criterion after the application of the step x | | criterion_model | double precision | predicted criterion after the application of x | Output: | rho | double precision | Agreement between the predicted criterion and the real new criterion | | cancel_step | logical | If the step must be cancelled | #+BEGIN_SRC f90 :comments org :tangle algo_trust.irp.f subroutine trust_region_is_step_cancelled(nb_iter,prev_criterion, criterion, criterion_model,rho,cancel_step) include 'pi.h' !BEGIN_DOC ! Compute if the step should be cancelled !END_DOC implicit none ! in double precision, intent(in) :: prev_criterion, criterion, criterion_model ! inout integer, intent(inout) :: nb_iter ! out logical, intent(out) :: cancel_step double precision, intent(out) :: rho ! Computes rho call trust_region_rho(prev_criterion,criterion,criterion_model,rho) if (nb_iter == 0) then nb_iter = 1 ! in order to enable the change of delta if the first iteration is cancelled endif ! If rho < thresh_rho -> give something in output to cancel the step if (rho >= thresh_rho) then !0.1d0) then ! The step is accepted cancel_step = .False. else ! The step is rejected cancel_step = .True. print*, '***********************' print*, 'Step cancel : rho <', thresh_rho print*, '***********************' endif end subroutine #+END_SRC ** Template for MOs #+BEGIN_SRC f90 :comments org :tangle trust_region_template_mos.txt subroutine algo_trust_template(tmp_n, tmp_list_size, tmp_list) implicit none ! Variables ! In integer, intent(in) :: tmp_n, tmp_list_size, tmp_list(tmp_list_size) ! Out ! Rien ou un truc pour savoir si ça c'est bien passé ! Internal double precision, allocatable :: e_val(:), W(:,:), tmp_R(:,:), R(:,:), tmp_x(:), tmp_m_x(:,:) double precision, allocatable :: prev_mos(:,:) double precision :: criterion, prev_criterion, criterion_model double precision :: delta, rho logical :: not_converged, cancel_step, must_exit, enforce_step_cancellation integer :: nb_iter, info, nb_sub_iter integer :: i,j,tmp_i,tmp_j allocate(W(tmp_n, tmp_n),e_val(tmp_n),tmp_x(tmp_n),tmp_m_x(tmp_list_size, tmp_list_size)) allocate(tmp_R(tmp_list_size, tmp_list_size), R(mo_num, mo_num)) allocate(prev_mos(ao_num, mo_num)) ! Provide the criterion, but unnecessary because it's done ! automatically PROVIDE C_PROVIDER H_PROVIDER g_PROVIDER cc_PROVIDER ! Initialization delta = 0d0 nb_iter = 0 ! Must start at 0 !!! rho = 0.5d0 ! Must start at 0.5 not_converged = .True. ! Must be true ! Compute the criterion before the loop prev_criterion = C_PROVIDER do while (not_converged) print*,'' print*,'******************' print*,'Iteration', nb_iter print*,'******************' print*,'' ! The new hessian and gradient are computed at the end of the previous iteration ! Diagonalization of the hessian call diagonalization_hessian(tmp_n, H_PROVIDER, e_val, W) cancel_step = .True. ! To enter in the loop just after nb_sub_iter = 0 ! Loop to Reduce the trust radius until the criterion decreases and rho >= thresh_rho do while (cancel_step) print*,'-----------------------------' print*,'Iteration:', nb_iter print*,'Sub iteration:', nb_sub_iter print*,'-----------------------------' ! Hessian,gradient,Criterion -> x call trust_region_step_w_expected_e(tmp_n,tmp_n, H_PROVIDER, W, e_val, g_PROVIDER, & prev_criterion, rho, nb_iter, delta, criterion_model, tmp_x, must_exit) if (must_exit) then ! if step_in_trust_region sets must_exit on true for numerical reasons print*,'trust_region_step_w_expected_e sent the message : Exit' exit endif ! 1D tmp -> 2D tmp call vec_to_mat_v2(tmp_n, tmp_list_size, tmp_x, tmp_m_x) ! Rotation submatrix (square matrix tmp_list_size by tmp_list_size) call rotation_matrix(tmp_m_x, tmp_list_size, tmp_R, tmp_list_size, tmp_list_size, info, enforce_step_cancellation) if (enforce_step_cancellation) then print*, 'Forces the step cancellation, too large error in the rotation matrix' rho = 0d0 cycle endif ! tmp_R to R, subspace to full space call sub_to_full_rotation_matrix(tmp_list_size, tmp_list, tmp_R, R) ! Rotation of the MOs call apply_mo_rotation(R, prev_mos) ! touch mo_coef call clear_mo_map ! Only if you are using the bi-electronic integrals ! mo_coef becomes valid ! And avoid the recomputation of the providers which depend of mo_coef TOUCH mo_coef C_PROVIDER H_PROVIDER g_PROVIDER cc_PROVIDER ! To update the other parameters if needed call #update_parameters() ! To enforce the program to provide new criterion after the update ! of the parameters FREE C_PROVIDER PROVIDE C_PROVIDER criterion = C_PROVIDER ! Criterion -> step accepted or rejected call trust_region_is_step_cancelled(nb_iter, prev_criterion, criterion, criterion_model, rho, cancel_step) ! Cancellation of the step ? if (cancel_step) then ! Replacement by the previous MOs mo_coef = prev_mos ! call save_mos() ! depends of the time for 1 iteration ! No need to clear_mo_map since we don't recompute the gradient and the hessian ! mo_coef becomes valid ! Avoid the recomputation of the providers which depend of mo_coef TOUCH mo_coef H_PROVIDER g_PROVIDER C_PROVIDER cc_PROVIDER else ! The step is accepted: ! criterion -> prev criterion ! The replacement "criterion -> prev criterion" is already done ! in trust_region_rho, so if the criterion does not have a reason ! to change, it will change nothing for the criterion and will ! force the program to provide the new hessian, gradient and ! convergence criterion for the next iteration. ! But in the case of orbital optimization we diagonalize the CI ! matrix after the "FREE" statement, so the criterion will change FREE C_PROVIDER H_PROVIDER g_PROVIDER cc_PROVIDER PROVIDE C_PROVIDER H_PROVIDER g_PROVIDER cc_PROVIDER prev_criterion = C_PROVIDER endif nb_sub_iter = nb_sub_iter + 1 enddo ! call save_mos() ! depends of the time for 1 iteration ! To exit the external loop if must_exit = .True. if (must_exit) then exit endif ! Step accepted, nb iteration + 1 nb_iter = nb_iter + 1 ! Provide the convergence criterion ! Provide the gradient and the hessian for the next iteration PROVIDE cc_PROVIDER ! To exit if (dabs(cc_PROVIDER) < thresh_opt_max_elem_grad) then not_converged = .False. endif if (nb_iter > optimization_max_nb_iter) then not_converged = .False. endif if (delta < thresh_delta) then not_converged = .False. endif enddo ! Save the final MOs call save_mos() ! Diagonalization of the hessian ! (To see the eigenvalues at the end of the optimization) call diagonalization_hessian(tmp_n, H_PROVIDER, e_val, W) deallocate(e_val, W, tmp_R, R, tmp_x, prev_mos) end #+END_SRC ** Cartesian version #+BEGIN_SRC f90 :comments org :tangle trust_region_template_xyz.txt subroutine algo_trust_cartesian_template(tmp_n) implicit none ! Variables ! In integer, intent(in) :: tmp_n ! Out ! Rien ou un truc pour savoir si ça c'est bien passé ! Internal double precision, allocatable :: e_val(:), W(:,:), tmp_x(:) double precision :: criterion, prev_criterion, criterion_model double precision :: delta, rho logical :: not_converged, cancel_step, must_exit integer :: nb_iter, nb_sub_iter integer :: i,j allocate(W(tmp_n, tmp_n),e_val(tmp_n),tmp_x(tmp_n)) PROVIDE C_PROVIDER X_PROVIDER H_PROVIDER g_PROVIDER ! Initialization delta = 0d0 nb_iter = 0 ! Must start at 0 !!! rho = 0.5d0 ! Must start at 0.5 not_converged = .True. ! Must be true ! Compute the criterion before the loop prev_criterion = C_PROVIDER do while (not_converged) print*,'' print*,'******************' print*,'Iteration', nb_iter print*,'******************' print*,'' if (nb_iter > 0) then PROVIDE H_PROVIDER g_PROVIDER endif ! Diagonalization of the hessian call diagonalization_hessian(tmp_n, H_PROVIDER, e_val, W) cancel_step = .True. ! To enter in the loop just after nb_sub_iter = 0 ! Loop to Reduce the trust radius until the criterion decreases and rho >= thresh_rho do while (cancel_step) print*,'-----------------------------' print*,'Iteration:', nb_iter print*,'Sub iteration:', nb_sub_iter print*,'-----------------------------' ! Hessian,gradient,Criterion -> x call trust_region_step_w_expected_e(tmp_n,tmp_n, H_PROVIDER, W, e_val, g_PROVIDER, & prev_criterion, rho, nb_iter, delta, criterion_model, tmp_x, must_exit) if (must_exit) then ! if step_in_trust_region sets must_exit on true for numerical reasons print*,'trust_region_step_w_expected_e sent the message : Exit' exit endif ! New coordinates, check the sign X_PROVIDER = X_PROVIDER - tmp_x ! touch X_PROVIDER TOUCH X_PROVIDER H_PROVIDER g_PROVIDER cc_PROVIDER ! To update the other parameters if needed call #update_parameters() ! New criterion PROVIDE C_PROVIDER ! Unnecessary criterion = C_PROVIDER ! Criterion -> step accepted or rejected call trust_region_is_step_cancelled(nb_iter, prev_criterion, criterion, criterion_model, rho, cancel_step) ! Cancel the previous step if (cancel_step) then ! Replacement by the previous coordinates, check the sign X_PROVIDER = X_PROVIDER + tmp_x ! Avoid the recomputation of the hessian and the gradient TOUCH X_PROVIDER H_PROVIDER g_PROVIDER C_PROVIDER cc_PROVIDER endif nb_sub_iter = nb_sub_iter + 1 enddo ! To exit the external loop if must_exit = .True. if (must_exit) then exit endif ! Step accepted, nb iteration + 1 nb_iter = nb_iter + 1 PROVIDE cc_PROVIDER ! To exit if (dabs(cc_PROVIDER) < thresh_opt_max_elem_grad) then not_converged = .False. endif if (nb_iter > optimization_max_nb_iter) then not_converged = .False. endif if (delta < thresh_delta) then not_converged = .False. endif enddo deallocate(e_val, W, tmp_x) end #+END_SRC ** Script template #+BEGIN_SRC bash :tangle script_template_mos.sh #!/bin/bash your_file= your_C_PROVIDER= your_H_PROVIDER= your_g_PROVIDER= your_cc_PROVIDER= sed "s/C_PROVIDER/$your_C_PROVIDER/g" trust_region_template_mos.txt > $your_file sed -i "s/H_PROVIDER/$your_H_PROVIDER/g" $your_file sed -i "s/g_PROVIDER/$your_g_PROVIDER/g" $your_file sed -i "s/cc_PROVIDER/$your_cc_PROVIDER/g" $your_file #+END_SRC #+BEGIN_SRC bash :tangle script_template_xyz.sh #!/bin/bash your_file= your_C_PROVIDER= your_X_PROVIDER= your_H_PROVIDER= your_g_PROVIDER= your_cc_PROVIDER= sed "s/C_PROVIDER/$your_C_PROVIDER/g" trust_region_template_xyz.txt > $your_file sed -i "s/X_PROVIDER/$your_X_PROVIDER/g" $your_file sed -i "s/H_PROVIDER/$your_H_PROVIDER/g" $your_file sed -i "s/g_PROVIDER/$your_g_PROVIDER/g" $your_file sed -i "s/cc_PROVIDER/$your_cc_PROVIDER/g" $your_file #+END_SRC