// File: /workspace/github_cpp_makefile_star2_O1/UCBASiCS[P]SPRIGHT/src/binprocessor.cpp
// Function: BinProcessor::computeThresholds()
void BinProcessor::computeThresholds()
{
    // for computing the histogram for zeroton-singleton-multiton test
    std::vector<double> energyBins;
    double noiseEstimation = 0;
    double tempEnergy = 0;
    int    energyHistogramBinsCounted = 0;

    if ( config->isNoisy() )
    {
        // go over the stages

        for (int stage = 0; stage < config->getBinsNb(); ++stage)
        {
            // go over the bins in the stage
            for (int i = 0; i < config->getBinNumItems(stage); ++i)
            {
                // this is the energy of a bin measurement
                tempEnergy = 0;
                // go over the delays (go over bin measurements)
                for (int j = 0; j < config->getDelaysNb(); j++)
                {
                    // std::norm calculates norm-squared
                    tempEnergy += std::norm(observationMatrix[config->getBinOffset(stage)+i][j]);
                }
                energyBins.push_back(tempEnergy);
            }
        }

        // make histogram below
        // sort the energy bins
        std::sort (energyBins.begin(), energyBins.end());

        bool noiseLevelCrossed = false;
        while (!noiseLevelCrossed)
        {
            noiseEstimation += energyBins[energyHistogramBinsCounted];
            energyHistogramBinsCounted++;

            // if the bin energy is 10 times the previous one, declare it has signal in it
            if ( energyBins[energyHistogramBinsCounted] / energyBins[energyHistogramBinsCounted-1] >= 10 )
            {
                noiseLevelCrossed = true;
            }
        }



        // CHOICE 1: this corresponds to the average energy of the zero-ton bins
        noiseEstimation /= energyHistogramBinsCounted;

        // CHOICE 2: this corresponds to the maximum energy of the zero-ton bins
        // noiseEstimation = energyBins[energyHistogramBinsCounted-1];

    }

    // Minimum energy for the signal to be accepted as non-zero
    // 10 percent of the minimum SNR

    if( !config->isNoisy() ) // noiseless ongrid
    {
        minimumEnergy = pow(10,-8);
    }
    else if ( config->isNoisy() ) // noisy ongrid
    {
        /*
            We want a threshold on the minimum signal energy to eliminate false
            detections. A simple one would be of the sort:
            minimumEnergy = 0.1 * noiseEstimation * pow(10,config->getSNRdB()/10);
            However, for large signal to noise ratio, this is not working since there
            is always a noise floor around 1e-18 due to numerical issues, hence when
            multiplied with high SNR it blows up. Hence, for small SNR we do that, but
            for large SNR we clip it.
            We chose it to clip to 1000 times the noise floor.
        */
        minimumEnergy = std::min( 0.1 * noiseEstimation * pow(10,config->getSNRdB()/10) , 1000 * noiseEstimation );

    }

    /*
        Base threshold for the remaining bin signal to be considered as
        zero-ton after the signal is peeled from it. This value, in theory, is zero
        for noiseless simulations. However, due to machine precision, it needs to be positive
        value. For noiseless simulations we chose it to be 1e-13. If this value is high,
        we start to get false detections. One can decrease the thrsholds or increase the
        number of delays to reduce the false detections.
    */
    ffast_real baseThreshold = pow(10, -13);

    ffast_real factor;

    // Thresholds are obtained using tailbounds of Gaussian random variable
    if (delaysNb < 10)
    {
        factor = 4;
    }
    else if (delaysNb < 20)
    {
        factor = 3;
    }
    else if (delaysNb < 50)
    {
        factor = 2;
    }
    else
    {
        factor = 1.5;
    }

    for (int stage=0; stage<config->getBinsNb(); stage++)
    {
        thresholds[stage] = baseThreshold;

        if (config->isNoisy() )
            thresholds[stage] = pow(10,-10) + (ffast_real) factor * noiseEstimation;
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %rdi, %rbx
xorpd %xmm0, %xmm0
movapd %xmm0, 0x10(%rsp)
xorl %eax, %eax
movq %rax, 0x20(%rsp)
movq %rax, 0x8(%rsp)
movq 0x10(%rdi), %rdi
callq 0x6e36
xorpd %xmm3, %xmm3
testb %al, %al
je 0x4ceb
xorl %r14d, %r14d
movq 0x10(%rbx), %rdi
callq 0x6e1c
cmpl %eax, %r14d
jge 0x4c64
xorl %ebp, %ebp
movq 0x10(%rbx), %rdi
movl %r14d, %esi
callq 0x6d82
cmpl %eax, %ebp
jge 0x4c5c
movq $0x0, 0x8(%rsp)
movl $0x8, %r13d
xorl %r15d, %r15d
movq 0x10(%rbx), %rdi
callq 0x6e2a
cltq
cmpq %rax, %r15
jge 0x4c25
movq 0x10(%rbx), %rdi
movq 0x18(%rbx), %r12
movl %r14d, %esi
callq 0x6e0c
addl %ebp, %eax
cltq
movq (%r12,%rax,8), %rax
movsd -0x8(%rax,%r13), %xmm0
movsd (%rax,%r13), %xmm1
mulsd %xmm1, %xmm1
mulsd %xmm0, %xmm0
addsd %xmm1, %xmm0
addsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
incq %r15
addq $0x10, %r13
jmp 0x4bcf
movq 0x18(%rsp), %rsi
cmpq 0x20(%rsp), %rsi
je 0x4c46
movsd 0x8(%rsp), %xmm0
movsd %xmm0, (%rsi)
addq $0x8, %rsi
movq %rsi, 0x18(%rsp)
jmp 0x4c55
leaq 0x10(%rsp), %rdi
leaq 0x8(%rsp), %rdx
callq 0x558c
incl %ebp
jmp 0x4ba9
incl %r14d
jmp 0x4b95
movq 0x10(%rsp), %r14
movq 0x18(%rsp), %r15
cmpq %r15, %r14
je 0x4ca0
movq %r15, %rax
subq %r14, %rax
sarq $0x3, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
movq %r14, %rdi
movq %r15, %rsi
callq 0x566b
movq %r14, %rdi
movq %r15, %rsi
callq 0x5764
xorpd %xmm3, %xmm3
movq 0x10(%rsp), %rcx
xorl %eax, %eax
movsd 0xa3fd(%rip), %xmm0     # 0xf0b0
xorl %edx, %edx
movsd (%rcx,%rax,8), %xmm1
movsd 0x8(%rcx,%rax,8), %xmm2
divsd %xmm1, %xmm2
ucomisd %xmm0, %xmm2
jb 0x4cd1
movl $0x1, %edx
jmp 0x4cd4
movzbl %dl, %edx
addsd %xmm1, %xmm3
incq %rax
testb $0x1, %dl
je 0x4cb5
xorps %xmm0, %xmm0
cvtsi2sd %eax, %xmm0
divsd %xmm0, %xmm3
movsd %xmm3, (%rsp)
movq 0x10(%rbx), %rdi
callq 0x6e36
testb %al, %al
je 0x4d64
movq 0x10(%rbx), %rdi
callq 0x6e36
testb %al, %al
movsd (%rsp), %xmm2
je 0x4d76
movq 0x10(%rbx), %rdi
callq 0x6e3a
movsd 0xa3a0(%rip), %xmm1     # 0xf0c0
mulsd (%rsp), %xmm1
movsd %xmm1, 0x30(%rsp)
divss 0xa3cd(%rip), %xmm0     # 0xf100
xorps %xmm1, %xmm1
cvtss2sd %xmm0, %xmm1
movsd 0xa36e(%rip), %xmm0     # 0xf0b0
callq 0x3480
movsd (%rsp), %xmm2
mulsd 0x30(%rsp), %xmm0
movsd 0xa36e(%rip), %xmm1     # 0xf0c8
mulsd %xmm2, %xmm1
minsd %xmm0, %xmm1
jmp 0x4d71
movsd 0xa34c(%rip), %xmm1     # 0xf0b8
movsd (%rsp), %xmm2
movsd %xmm1, 0x30(%rbx)
movl 0x24(%rbx), %eax
cmpl $0xa, %eax
jge 0x4d88
movsd 0xa34a(%rip), %xmm0     # 0xf0d0
jmp 0x4dab
cmpl $0x14, %eax
jge 0x4d97
movsd 0xa343(%rip), %xmm0     # 0xf0d8
jmp 0x4dab
xorl %ecx, %ecx
cmpl $0x32, %eax
setl %cl
leaq 0xa362(%rip), %rax      # 0xf108
movsd (%rax,%rcx,8), %xmm0
mulsd %xmm2, %xmm0
addsd 0xa329(%rip), %xmm0     # 0xf0e0
movsd %xmm0, (%rsp)
xorl %r14d, %r14d
movabsq $0x3d3c25c268497682, %r15 # imm = 0x3D3C25C268497682
movq 0x10(%rbx), %rdi
callq 0x6e1c
cltq
cmpq %rax, %r14
jge 0x4e02
movq 0x78(%rbx), %rax
movq %r15, (%rax,%r14,8)
movq 0x10(%rbx), %rdi
callq 0x6e36
testb %al, %al
je 0x4dfd
movq 0x78(%rbx), %rax
movsd (%rsp), %xmm0
movsd %xmm0, (%rax,%r14,8)
incq %r14
jmp 0x4dc9
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
je 0x4e19
movq 0x20(%rsp), %rsi
subq %rdi, %rsi
callq 0x3270
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x4e32
jmp 0x4e32
jmp 0x4e32
jmp 0x4e32
jmp 0x4e32
movq %rax, %rbx
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
je 0x4e4c
movq 0x20(%rsp), %rsi
subq %rdi, %rsi
callq 0x3270
movq %rbx, %rdi
callq 0x3490