// File: /workspace/github_cpp_makefile_star2_O2/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)
andq $0x0, 0x20(%rsp)
andq $0x0, 0x8(%rsp)
movq 0x10(%rdi), %rdi
callq 0x67e4
xorpd %xmm3, %xmm3
testb %al, %al
je 0x49e8
xorl %r14d, %r14d
movq 0x10(%rbx), %rdi
callq 0x67ca
cmpl %eax, %r14d
jge 0x4998
xorl %ebp, %ebp
movq 0x10(%rbx), %rdi
movl %r14d, %esi
callq 0x6730
cmpl %eax, %ebp
jge 0x4990
andq $0x0, 0x8(%rsp)
pushq $0x8
popq %r13
xorl %r15d, %r15d
movq 0x10(%rbx), %rdi
callq 0x67d8
cltq
cmpq %rax, %r15
jge 0x497a
movq 0x10(%rbx), %rdi
movq 0x18(%rbx), %r12
movl %r14d, %esi
callq 0x67ba
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 0x4924
leaq 0x10(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x50d0
incl %ebp
jmp 0x4907
incl %r14d
jmp 0x48f3
movq 0x10(%rsp), %rdi
movq 0x18(%rsp), %rsi
callq 0x5288
xorpd %xmm3, %xmm3
movq 0x10(%rsp), %rcx
xorl %eax, %eax
movsd 0x76f6(%rip), %xmm0     # 0xc0b0
xorl %edx, %edx
testb $0x1, %dl
jne 0x49e0
movsd (%rcx,%rax,8), %xmm1
movsd 0x8(%rcx,%rax,8), %xmm2
addsd %xmm1, %xmm3
incq %rax
divsd %xmm1, %xmm2
ucomisd %xmm0, %xmm2
setae %dl
jmp 0x49bc
cvtsi2sd %eax, %xmm0
divsd %xmm0, %xmm3
movsd %xmm3, (%rsp)
movq 0x10(%rbx), %rdi
callq 0x67e4
testb %al, %al
je 0x4a5e
movq 0x10(%rbx), %rdi
callq 0x67e4
testb %al, %al
movsd (%rsp), %xmm2
je 0x4a70
movq 0x10(%rbx), %rdi
callq 0x67e8
movsd 0x76a3(%rip), %xmm1     # 0xc0c0
mulsd (%rsp), %xmm1
movsd %xmm1, 0x30(%rsp)
divss 0x76d0(%rip), %xmm0     # 0xc100
cvtss2sd %xmm0, %xmm1
movsd 0x7674(%rip), %xmm0     # 0xc0b0
callq 0x3480
movsd (%rsp), %xmm2
mulsd 0x30(%rsp), %xmm0
movsd 0x7674(%rip), %xmm1     # 0xc0c8
mulsd %xmm2, %xmm1
minsd %xmm0, %xmm1
jmp 0x4a6b
movsd 0x7652(%rip), %xmm1     # 0xc0b8
movsd (%rsp), %xmm2
movsd %xmm1, 0x30(%rbx)
movl 0x24(%rbx), %eax
cmpl $0xa, %eax
jge 0x4a82
movsd 0x7650(%rip), %xmm0     # 0xc0d0
jmp 0x4aa5
cmpl $0x14, %eax
jae 0x4a91
movsd 0x7649(%rip), %xmm0     # 0xc0d8
jmp 0x4aa5
xorl %ecx, %ecx
cmpl $0x32, %eax
setb %cl
leaq 0x7668(%rip), %rax      # 0xc108
movsd (%rax,%rcx,8), %xmm0
mulsd %xmm2, %xmm0
addsd 0x762f(%rip), %xmm0     # 0xc0e0
movsd %xmm0, (%rsp)
xorl %r14d, %r14d
movabsq $0x3d3c25c268497682, %r15 # imm = 0x3D3C25C268497682
movq 0x10(%rbx), %rdi
callq 0x67ca
cltq
cmpq %rax, %r14
jge 0x4afc
movq 0x78(%rbx), %rax
movq %r15, (%rax,%r14,8)
movq 0x10(%rbx), %rdi
callq 0x67e4
testb %al, %al
je 0x4af7
movq 0x78(%rbx), %rax
movsd (%rsp), %xmm0
movsd %xmm0, (%rax,%r14,8)
incq %r14
jmp 0x4ac3
leaq 0x10(%rsp), %rdi
callq 0x40fc
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x4b1f
jmp 0x4b1f
jmp 0x4b1f
jmp 0x4b1f
jmp 0x4b1f
movq %rax, %rbx
leaq 0x10(%rsp), %rdi
callq 0x40fc
movq %rbx, %rdi
callq 0x3490