<commit_before>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!> A module for computing eigenvalues using the Jacobi method.
MODULE JacobiEigenSolverModule
  USE DataTypesModule, ONLY : NTREAL, MPINTREAL
  USE DenseMatrixModule, ONLY : DenseEigenDecomposition
  USE DistributedSparseMatrixModule, ONLY : DistributedSparseMatrix_t, &
       & ConstructEmptyDistributedSparseMatrix, FillDistributedIdentity, &
       & FillFromTripletList, GetTripletList
  USE IterativeSolversModule, ONLY : IterativeSolverParameters_t
  USE LoggingModule, ONLY : EnterSubLog, ExitSubLog, WriteElement, &
       & WriteListElement
  USE MatrixBroadcastModule, ONLY : BroadcastMatrix
  USE MatrixGatherModule, ONLY : BlockingMatrixGather
  USE MatrixSendRecvModule, ONLY : SendRecvHelper_t, RecvMatrixSizes, &
       & RecvMatrixData, SendMatrixSizes, SendMatrixData, &
       & TestSendRecvSizeRequest, TestSendRecvOuterRequest, &
       & TestSendRecvInnerRequest, TestSendRecvDataRequest
  USE SparseMatrixModule, ONLY : SparseMatrix_t, ComposeSparseMatrix, &
       & ConstructFromTripletList, CopySparseMatrix, DestructSparseMatrix, &
       & MatrixToTripletList, SplitSparseMatrix, TransposeSparseMatrix
  USE SparseMatrixAlgebraModule, ONLY : Gemm, IncrementSparseMatrix, &
       & SparseMatrixNorm
  USE TripletListModule, ONLY : TripletList_t, AppendToTripletList, &
       & ConstructTripletList, DestructTripletList, GetTripletAt, &
       & RedistributeTripletLists, ShiftTripletList, SortTripletList
  USE TripletModule, ONLY : Triplet_t
  USE MPI
  IMPLICIT NONE
  PRIVATE
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  PUBLIC :: JacobiSolve
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  TYPE, PRIVATE :: SwapData_t
     !> Which process to send the left matrix to.
     INTEGER :: send_left_partner
     !> Which process to send the right matrix to.
     INTEGER :: send_right_partner
     !> A tag to identify where the left matrix is sent to.
     INTEGER :: send_left_tag
     !> A tag to identify where the right matrix is sent to.
     INTEGER :: send_right_tag
     !> Which process to receive the left matrix from.
     INTEGER :: recv_left_partner
     !> Which process to receive the right matrix from.
     INTEGER :: recv_right_partner
     !> A tag to identify the left matrix being received.
     INTEGER :: recv_left_tag
     !> A tag to identify the right matrix being received.
     INTEGER :: recv_right_tag
     !> A full list of the permutation that needs to be performed at each step.
     INTEGER, DIMENSION(:), ALLOCATABLE :: swap_array
  END TYPE SwapData_t
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  TYPE, PRIVATE :: JacobiData_t
     !! Process Information
     !> Total processors involved in the calculation
     INTEGER :: num_processes
     !> Rank within the 1D process communicator.
     INTEGER :: rank
     !> A communicator for performing the calculation on.
     INTEGER :: communicator
     !! Blocking Information
     INTEGER :: block_start
     INTEGER :: block_end
     INTEGER :: block_rows
     INTEGER :: block_columns
     INTEGER :: rows
     INTEGER :: columns
     INTEGER :: start_row
     INTEGER :: start_column
     INTEGER :: column_divisor
     !! For Inter Process Swaps
     INTEGER, DIMENSION(:), ALLOCATABLE :: phase_array
     !> During the first num_proc rounds
     TYPE(SwapData_t) :: left_swap
     !> After round num_proc+1, we need to do a special swap to maintain the
     !! correct within process order.
     TYPE(SwapData_t) :: mid_swap
     !> In the last num_proc+2->end rounds, we change direction when sending.
     TYPE(SwapData_t) :: right_swap
     !> After the sweeps are finished, this swaps the data back to the original
     !! permutation.
     TYPE(SwapData_t) :: final_swap
  END TYPE JacobiData_t
CONTAINS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> Compute the eigenvectors of a matrix using the Block Jacobi Eigenvalue
  !! method.
  !! @param[in] this the matrix to compute the eigendecomposition of.
  !! @param[out] eigenvecotrs the eigenvectors of this.
  !! @param[in] solver_parameters for controlling the solve.
  SUBROUTINE JacobiSolve(this, eigenvectors, solver_parameters)
    !! Parameters
    TYPE(DistributedSparseMatrix_t), INTENT(IN) :: this
    TYPE(DistributedSparseMatrix_t), INTENT(INOUT) :: eigenvectors
    TYPE(IterativeSolverParameters_t), INTENT(IN) :: solver_parameters
    !! Local Blocking
    TYPE(SparseMatrix_t), DIMENSION(:,:), ALLOCATABLE :: ABlocks
    TYPE(SparseMatrix_t), DIMENSION(:,:), ALLOCATABLE :: VBlocks
    TYPE(SparseMatrix_t) :: local_a
    TYPE(SparseMatrix_t) :: last_a
    TYPE(JacobiData_t) :: jacobi_data
    !! Temporary
    REAL(NTREAL) :: norm_value
    INTEGER :: counter, iteration
    INTEGER :: ierr

    !! Setup Communication
    CALL InitializeJacobi(jacobi_data, this)

    !! Initialize the eigenvectors to the identity.
    CALL ConstructEmptyDistributedSparseMatrix(eigenvectors, &
         & this%actual_matrix_dimension)
    CALL FillDistributedIdentity(eigenvectors)

    !! Extract to local dense blocks
    ALLOCATE(ABlocks(2,jacobi_data%block_rows))
    CALL GetLocalBlocks(this, jacobi_data, ABlocks)
    ALLOCATE(VBlocks(2,jacobi_data%block_rows))
    CALL GetLocalBlocks(eigenvectors, jacobi_data, VBlocks)
    CALL ComposeSparseMatrix(ABlocks, jacobi_data%block_rows, &
         & jacobi_data%block_columns, local_a)
    DO iteration = 1, solver_parameters%max_iterations
       IF (solver_parameters%be_verbose .AND. iteration .GT. 1) THEN
          CALL WriteListElement(key="Round", int_value_in=iteration-1)
          CALL EnterSubLog
          CALL WriteListElement(key="Convergence", float_value_in=norm_value)
          CALL ExitSubLog
       END IF

       !! Loop Over One Jacobi Sweep
       CALL JacobiSweep(ABlocks, VBlocks, jacobi_data, &
            & solver_parameters%threshold)

       !! Compute Norm Value
       CALL CopySparseMatrix(local_a, last_a)
       CALL ComposeSparseMatrix(ABlocks, jacobi_data%block_rows, &
            & jacobi_data%block_columns, local_a)
       CALL IncrementSparseMatrix(local_a,last_a,alpha_in=REAL(-1.0,NTREAL), &
            & threshold_in=solver_parameters%threshold)
       norm_value = SparseMatrixNorm(last_a)
       CALL MPI_Allreduce(MPI_IN_PLACE, norm_value, 1, MPINTREAL, MPI_SUM,&
            & jacobi_data%communicator, ierr)

       !! Test early exit
       IF (norm_value .LE. solver_parameters%converge_diff) THEN
          EXIT
       END IF
    END DO

    !! Convert to global matrix
    CALL FillGlobalMatrix(VBlocks, jacobi_data, eigenvectors)

    ! Cleanup
    DO counter = 1, jacobi_data%num_processes*2<commit_msg>Verbose output for jacobi<commit_after>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!> A module for computing eigenvalues using the Jacobi method.
MODULE JacobiEigenSolverModule
  USE DataTypesModule, ONLY : NTREAL, MPINTREAL
  USE DenseMatrixModule, ONLY : DenseEigenDecomposition
  USE DistributedSparseMatrixModule, ONLY : DistributedSparseMatrix_t, &
       & ConstructEmptyDistributedSparseMatrix, FillDistributedIdentity, &
       & FillFromTripletList, GetTripletList
  USE IterativeSolversModule, ONLY : IterativeSolverParameters_t, &
       & PrintIterativeSolverParameters
  USE LoggingModule, ONLY : EnterSubLog, ExitSubLog, WriteElement, &
       & WriteListElement, WriteHeader, WriteCitation
  USE MatrixBroadcastModule, ONLY : BroadcastMatrix
  USE MatrixGatherModule, ONLY : BlockingMatrixGather
  USE MatrixSendRecvModule, ONLY : SendRecvHelper_t, RecvMatrixSizes, &
       & RecvMatrixData, SendMatrixSizes, SendMatrixData, &
       & TestSendRecvSizeRequest, TestSendRecvOuterRequest, &
       & TestSendRecvInnerRequest, TestSendRecvDataRequest
  USE SparseMatrixModule, ONLY : SparseMatrix_t, ComposeSparseMatrix, &
       & ConstructFromTripletList, CopySparseMatrix, DestructSparseMatrix, &
       & MatrixToTripletList, SplitSparseMatrix, TransposeSparseMatrix
  USE SparseMatrixAlgebraModule, ONLY : Gemm, IncrementSparseMatrix, &
       & SparseMatrixNorm
  USE TripletListModule, ONLY : TripletList_t, AppendToTripletList, &
       & ConstructTripletList, DestructTripletList, GetTripletAt, &
       & RedistributeTripletLists, ShiftTripletList, SortTripletList
  USE TripletModule, ONLY : Triplet_t
  USE MPI
  IMPLICIT NONE
  PRIVATE
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  PUBLIC :: JacobiSolve
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  TYPE, PRIVATE :: SwapData_t
     !> Which process to send the left matrix to.
     INTEGER :: send_left_partner
     !> Which process to send the right matrix to.
     INTEGER :: send_right_partner
     !> A tag to identify where the left matrix is sent to.
     INTEGER :: send_left_tag
     !> A tag to identify where the right matrix is sent to.
     INTEGER :: send_right_tag
     !> Which process to receive the left matrix from.
     INTEGER :: recv_left_partner
     !> Which process to receive the right matrix from.
     INTEGER :: recv_right_partner
     !> A tag to identify the left matrix being received.
     INTEGER :: recv_left_tag
     !> A tag to identify the right matrix being received.
     INTEGER :: recv_right_tag
     !> A full list of the permutation that needs to be performed at each step.
     INTEGER, DIMENSION(:), ALLOCATABLE :: swap_array
  END TYPE SwapData_t
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  TYPE, PRIVATE :: JacobiData_t
     !! Process Information
     !> Total processors involved in the calculation
     INTEGER :: num_processes
     !> Rank within the 1D process communicator.
     INTEGER :: rank
     !> A communicator for performing the calculation on.
     INTEGER :: communicator
     !! Blocking Information
     !> First block row to work on locally..
     INTEGER :: block_start
     !> Second block row to work on locally.
     INTEGER :: block_end
     !> How many block rows there are.
     INTEGER :: block_rows
     !> How many block columsn there are.
     INTEGER :: block_columns
     !> Local rows.
     INTEGER :: rows
     !> Local columns.
     INTEGER :: columns
     !> First row stored locally.
     INTEGER :: start_row
     !> First column stored locally.
     INTEGER :: start_column
     !> For evenly dividing the columns.
     INTEGER :: column_divisor
     !! For Inter Process Swaps
     INTEGER, DIMENSION(:), ALLOCATABLE :: phase_array
     !> During the first num_proc rounds
     TYPE(SwapData_t) :: left_swap
     !> After round num_proc+1, we need to do a special swap to maintain the
     !! correct within process order.
     TYPE(SwapData_t) :: mid_swap
     !> In the last num_proc+2->end rounds, we change direction when sending.
     TYPE(SwapData_t) :: right_swap
     !> After the sweeps are finished, this swaps the data back to the original
     !! permutation.
     TYPE(SwapData_t) :: final_swap
  END TYPE JacobiData_t
CONTAINS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> Compute the eigenvectors of a matrix using the Block Jacobi Eigenvalue
  !! method.
  !! @param[in] this the matrix to compute the eigendecomposition of.
  !! @param[out] eigenvecotrs the eigenvectors of this.
  !! @param[in] solver_parameters for controlling the solve.
  SUBROUTINE JacobiSolve(this, eigenvectors, solver_parameters)
    !! Parameters
    TYPE(DistributedSparseMatrix_t), INTENT(IN) :: this
    TYPE(DistributedSparseMatrix_t), INTENT(INOUT) :: eigenvectors
    TYPE(IterativeSolverParameters_t), INTENT(IN) :: solver_parameters
    !! Local Blocking
    TYPE(SparseMatrix_t), DIMENSION(:,:), ALLOCATABLE :: ABlocks
    TYPE(SparseMatrix_t), DIMENSION(:,:), ALLOCATABLE :: VBlocks
    TYPE(SparseMatrix_t) :: local_a
    TYPE(SparseMatrix_t) :: last_a
    TYPE(JacobiData_t) :: jacobi_data
    !! Temporary
    REAL(NTREAL) :: norm_value
    INTEGER :: counter, iteration
    INTEGER :: ierr

    !! Write info about the solver
    IF (solver_parameters%be_verbose) THEN
       CALL WriteHeader("Eigen Solver")
       CALL EnterSubLog
       CALL WriteElement(key="Method", text_value_in="Jacobi")
       CALL WriteCitation("golub2012matrix")
       CALL PrintIterativeSolverParameters(solver_parameters)
    END IF

    !! Setup Communication
    CALL InitializeJacobi(jacobi_data, this)

    !! Initialize the eigenvectors to the identity.
    CALL ConstructEmptyDistributedSparseMatrix(eigenvectors, &
         & this%actual_matrix_dimension)
    CALL FillDistributedIdentity(eigenvectors)

    !! Extract to local dense blocks
    ALLOCATE(ABlocks(2,jacobi_data%block_rows))
    CALL GetLocalBlocks(this, jacobi_data, ABlocks)
    ALLOCATE(VBlocks(2,jacobi_data%block_rows))
    CALL GetLocalBlocks(eigenvectors, jacobi_data, VBlocks)
    CALL ComposeSparseMatrix(ABlocks, jacobi_data%block_rows, &
         & jacobi_data%block_columns, local_a)
    DO iteration = 1, solver_parameters%max_iterations
       IF (solver_parameters%be_verbose .AND. iteration .GT. 1) THEN
          CALL WriteListElement(key="Round", int_value_in=iteration-1)
          CALL EnterSubLog
          CALL WriteListElement(key="Convergence", float_value_in=norm_value)
          CALL ExitSubLog
       END IF

       !! Loop Over One Jacobi Sweep
       CALL JacobiSweep(ABlocks, VBlocks, jacobi_data, &
            & solver_parameters%threshold)

       !! Compute Norm Value
       CALL CopySparseMatrix(local_a, last_a)
       CALL ComposeSparseMatrix(ABlocks, jacobi_data%block_rows, &
            & jacobi_data%block_columns, local_a)
       CALL IncrementSparseMatrix(local_a,last_a,alpha_in=REAL(-1.0,NTREAL), &
            & threshold_in=solver_parameters%threshold)
       norm_value = SparseMatrixNorm(last_a)
       CALL MPI_Allreduce(MPI_IN_PLACE, norm_value, 1, MPINTREAL, MPI_SUM,&
            & jacobi_data%communicator, ierr)

       !! Test early exit
       IF (norm_value .LE. solver_parameters%converge_diff) THEN
          EXIT
       END IF
    END DO

    !! Convert to global matrix
    CALL FillGlobalMatrix(VBlocks, jacobi_data, eigenvectors)

    IF (solver_parameters%be_verbose) THEN
       CALL ExitSubLog
    END IF

    ! Cleanup
    DO counter = 1, jacobi_data%num_processes*2
{'fraction_non_alphanumeric': 0.12246872624231114, 'fraction_numerical': 0.0020733982998133943, 'mean_word_length': 3.8638655462184874, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 50, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7577557', 'n_tokens_mistral': 4568, 'n_tokens_neox': 4186, 'n_words': 1111}