// File: /workspace/github_cpp_makefile_star2_O3/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 0x6cfc
xorpd %xmm4, %xmm4
testb %al, %al
je 0x4c4f
xorl %r14d, %r14d
movq 0x10(%rbx), %rdi
callq 0x6ce2
cmpl %eax, %r14d
jge 0x4bd0
xorl %ebp, %ebp
movq 0x10(%rbx), %rdi
movl %r14d, %esi
callq 0x6c48
cmpl %eax, %ebp
jge 0x4bc8
movq $0x0, 0x8(%rsp)
movl $0x8, %r13d
xorl %r15d, %r15d
movq 0x10(%rbx), %rdi
callq 0x6cf0
cltq
cmpq %rax, %r15
jge 0x4b91
movq 0x10(%rbx), %rdi
movq 0x18(%rbx), %r12
movl %r14d, %esi
callq 0x6cd2
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 0x4b3b
movq 0x18(%rsp), %rsi
cmpq 0x20(%rsp), %rsi
je 0x4bb2
movsd 0x8(%rsp), %xmm0
movsd %xmm0, (%rsi)
addq $0x8, %rsi
movq %rsi, 0x18(%rsp)
jmp 0x4bc1
leaq 0x10(%rsp), %rdi
leaq 0x8(%rsp), %rdx
callq 0x54a6
incl %ebp
jmp 0x4b15
incl %r14d
jmp 0x4b01
movq 0x10(%rsp), %r14
movq 0x18(%rsp), %r15
cmpq %r15, %r14
je 0x4c11
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 0x5585
movq %r14, %rdi
movq %r15, %rsi
callq 0x567e
movq 0x10(%rsp), %r14
movsd (%r14), %xmm0
xorpd %xmm4, %xmm4
xorl %eax, %eax
movsd 0x948c(%rip), %xmm1     # 0xe0b0
addsd %xmm0, %xmm4
movsd 0x8(%r14,%rax,8), %xmm2
incq %rax
movapd %xmm2, %xmm3
divsd %xmm0, %xmm3
ucomisd %xmm1, %xmm3
movapd %xmm2, %xmm0
jb 0x4c24
xorps %xmm0, %xmm0
cvtsi2sd %eax, %xmm0
divsd %xmm0, %xmm4
movsd %xmm4, (%rsp)
movq 0x10(%rbx), %rdi
callq 0x6cfc
testb %al, %al
je 0x4cc8
movq 0x10(%rbx), %rdi
callq 0x6cfc
testb %al, %al
movsd (%rsp), %xmm2
je 0x4cda
movq 0x10(%rbx), %rdi
callq 0x6d00
movsd 0x943c(%rip), %xmm1     # 0xe0c0
mulsd (%rsp), %xmm1
movsd %xmm1, 0x30(%rsp)
divss 0x9469(%rip), %xmm0     # 0xe100
xorps %xmm1, %xmm1
cvtss2sd %xmm0, %xmm1
movsd 0x940a(%rip), %xmm0     # 0xe0b0
callq 0x3480
movsd (%rsp), %xmm2
mulsd 0x30(%rsp), %xmm0
movsd 0x940a(%rip), %xmm1     # 0xe0c8
mulsd %xmm2, %xmm1
minsd %xmm0, %xmm1
jmp 0x4cd5
movsd 0x93e8(%rip), %xmm1     # 0xe0b8
movsd (%rsp), %xmm2
movsd %xmm1, 0x30(%rbx)
movl 0x24(%rbx), %eax
cmpl $0xa, %eax
jge 0x4cec
movsd 0x93e6(%rip), %xmm0     # 0xe0d0
jmp 0x4d0f
cmpl $0x14, %eax
jae 0x4cfb
movsd 0x93df(%rip), %xmm0     # 0xe0d8
jmp 0x4d0f
xorl %ecx, %ecx
cmpl $0x32, %eax
setb %cl
leaq 0x93fe(%rip), %rax      # 0xe108
movsd (%rax,%rcx,8), %xmm0
mulsd %xmm2, %xmm0
addsd 0x93c5(%rip), %xmm0     # 0xe0e0
movsd %xmm0, (%rsp)
xorl %r14d, %r14d
movabsq $0x3d3c25c268497682, %r15 # imm = 0x3D3C25C268497682
movq 0x10(%rbx), %rdi
callq 0x6ce2
cltq
cmpq %rax, %r14
jge 0x4d66
movq 0x78(%rbx), %rax
movq %r15, (%rax,%r14,8)
movq 0x10(%rbx), %rdi
callq 0x6cfc
testb %al, %al
je 0x4d61
movq 0x78(%rbx), %rax
movsd (%rsp), %xmm0
movsd %xmm0, (%rax,%r14,8)
incq %r14
jmp 0x4d2d
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
je 0x4d7d
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 0x4d96
jmp 0x4d96
jmp 0x4d96
jmp 0x4d96
jmp 0x4d96
movq %rax, %rbx
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
je 0x4db0
movq 0x20(%rsp), %rsi
subq %rdi, %rsi
callq 0x3270
movq %rbx, %rdi
callq 0x3490