<commit_before>module annihilation

use const
use fciqmc_data

implicit none

contains

    subroutine direct_annihilation(sc0)

        interface
            function sc0(f) result(hmatel)
                use basis, only: basis_length
                use const, only: i0, p
                implicit none
                real(p) :: hmatel
                integer(i0), intent(in) :: f(basis_length)
            end function sc0
        end interface

        ! 1. Sort spawned walkers list.
        call sort_spawned_lists()

        ! 2. Annihilate within spawned walkers list.
        ! Compress the remaining spawned walkers list.
        call annihilate_spawned_list()

        ! 4. Annilate main list.
        call annihilate_main_list()

        ! 5. Insert new walkers into main walker list.
        call insert_new_walkers(sc0)

    end subroutine direct_annihilation

    subroutine annihilate_spawned_list()

        ! Annihilate the spawned walker list and compress the remaining
        ! elements.

        ! The spawned walker list is already sorted, so annihilation amounts to
        ! looping through the list and adding consective walker populations
        ! together if they're the same walker.

        integer :: i, k, nremoved

        nremoved = 0
        i = 1
        k = 0

        ! Go through the sorted spawned_walker lists and compress it by adding
        ! up the populations of duplicate walkers and removing the duplicate
        ! determinants.

        ! Treat the first entry separately to make the subsequent removal of
        ! walkers with 0 population easy.
        if (spawning_head == 1) then
            ! Nothing to do bar ensure spawning_head remains 1.
            k = 1
            i = i + 1
        else if (spawning_head > 1) then
            k = k + 1
            ! Compress.
            i = i + 1
            do while (all(spawned_walker_dets(:,k) == spawned_walker_dets(:,i)))
                ! Annihilate.
                spawned_walker_population(k) = spawned_walker_population(k) + spawned_walker_population(i)
                nremoved = nremoved + 1
                i = i + 1
                if (i > spawning_head) exit
            end do
        end if

        annihilate: do
            if (i > spawning_head) exit annihilate
            if (spawned_walker_population(k) /= 0) then
                ! Go to the next slot.
                k = k + 1
            end if
            ! Compress.
            spawned_walker_dets(:,k) = spawned_walker_dets(:,i)
            spawned_walker_population(k) = spawned_walker_population(i)
            i = i + 1
            do while (all(spawned_walker_dets(:,k) == spawned_walker_dets(:,i)))
                ! Annihilate.
                spawned_walker_population(k) = spawned_walker_population(k) + spawned_walker_population(i)
                nremoved = nremoved + 1
                i = i + 1
                if (i > spawning_head) exit annihilate
            end do
        end do annihilate

        ! The last element in the spawned list is now k.
        spawning_head = k
        
    end subroutine annihilate_spawned_list

    subroutine annihilate_main_list()

        ! Annihilate particles in the main walker list with those in the spawned
        ! walker list.

        use basis, only: basis_length
<commit_msg>Fix compression of spawned walker list.  Results change.<commit_after>module annihilation

use const
use fciqmc_data

implicit none

contains

    subroutine direct_annihilation(sc0)

        interface
            function sc0(f) result(hmatel)
                use basis, only: basis_length
                use const, only: i0, p
                implicit none
                real(p) :: hmatel
                integer(i0), intent(in) :: f(basis_length)
            end function sc0
        end interface

        ! 1. Sort spawned walkers list.
        call sort_spawned_lists()

        ! 2. Annihilate within spawned walkers list.
        ! Compress the remaining spawned walkers list.
        call annihilate_spawned_list()

        ! 4. Annilate main list.
        call annihilate_main_list()

        ! 5. Insert new walkers into main walker list.
        call insert_new_walkers(sc0)

    end subroutine direct_annihilation

    subroutine annihilate_spawned_list()

        ! Annihilate the spawned walker list and compress the remaining
        ! elements.

        ! The spawned walker list is already sorted, so annihilation amounts to
        ! looping through the list and adding consective walker populations
        ! together if they're the same walker.

        integer :: islot, k, nremoved

        ! islot is the current element in the spawned walkers lists.
        islot = 1
        ! k is the current element which is being compressed into islot (if
        ! k and islot refer to the same determinants).
        k = 1
        nremoved = 0
        self_annihilate: do
            ! Set the current free slot to be the next unique spawned walker.
            spawned_walker_dets(:,islot) = spawned_walker_dets(:,k) 
            spawned_walker_population(islot) = spawned_walker_population(k) 
            compress: do
                k = k + 1
                if (k > spawning_head) exit self_annihilate
                if (all(spawned_walker_dets(:,k) == spawned_walker_dets(:,islot))) then
                    ! Add the populations of the subsequent identical walkers.
                    spawned_walker_population(islot) = spawned_walker_population(islot) + spawned_walker_population(k)
                    nremoved = nremoved + 1
                else
                    ! Found the next unique spawned walker.
                    exit compress
                end if
            end do compress
            ! go to the next slot.
            islot = islot + 1
            if (islot > spawning_head) exit self_annihilate
        end do self_annihilate

        ! update spawning_head
        spawning_head = spawning_head - nremoved

    end subroutine annihilate_spawned_list

    subroutine annihilate_main_list()

        ! Annihilate particles in the main walker list with those in the spawned
        ! walker list.

        use basis, only: basis_length

{'fraction_non_alphanumeric': 0.054759220486390724, 'fraction_numerical': 0.007086487357062329, 'mean_word_length': 1.8112267994567677, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, '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': '3584352', 'n_tokens_mistral': 1866, 'n_tokens_neox': 1686, 'n_words': 566}