// File: /workspace/github_cpp_makefile_star2_O3/fabianp[P]ProxASAGA/proxasaga_atomic.cpp
// Function: saga_single_thread_nonatomic(double*, double*, double*, double*, long*, long*, double*, double*, long, long, double, double, double, long, double*, double*, long)
void saga_single_thread_nonatomic(
        double* x, double* memory_gradient, double* gradient_average,
        double* A_data, int64_t* A_indices, int64_t* A_indptr, double* b, double* d, int64_t n_samples,
        int64_t n_features, double alpha, double beta, double step_size, int64_t max_iter,
        double* trace_x, double* trace_time, int64_t iter_freq) {
          int64_t i, j, j_idx, local_counter=0, global_counter;
          double p, grad_i, incr, old_grad, delta;
          std::random_device rd;
          std::mt19937 rng(rd());
          std::uniform_int_distribution<int64_t> uni(0, n_samples-1);
          struct timespec start, finish;
          double elapsed;
          clock_gettime(CLOCK_MONOTONIC, &start);

          while (true) {
            /* take a snapshot of the current vector of iterates in trace_x
               and time in trace_time, in order to plot convergence later on */
            if (local_counter % iter_freq == 0) {
                int64_t c = local_counter / iter_freq;
                for (j=0; j<n_features; j++) {
                    trace_x[n_features * c + j] = x[j];
                }
                clock_gettime(CLOCK_MONOTONIC, &finish);
                elapsed = (finish.tv_sec - start.tv_sec);
                elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0;
                trace_time[c] = (double) elapsed;
                printf(".. iteration %lld, time elapsed %f min ..\n", c, elapsed / 60.);
            }

            i = uni(rng);
            p = 0.;
            for (j=A_indptr[i]; j < A_indptr[i+1]; j++) {
                j_idx = A_indices[j];
                p += x[j_idx] * A_data[j];
            }
            grad_i = partial_gradient(p, b[i]);
            old_grad = memory_gradient[i];
            memory_gradient[i] = grad_i;
            incr = grad_i - old_grad;

            // .. update coefficients ..
            for (j=A_indptr[i]; j < A_indptr[i+1]; j++){
                j_idx = A_indices[j];
                delta = incr * A_data[j] + d[j_idx] * (gradient_average[j_idx] + alpha * x[j_idx]);
                x[j_idx] = prox(x[j_idx] - step_size * delta, beta * step_size * d[j_idx]);
                gradient_average[j_idx] += incr * A_data[j] / n_samples;
            }
            local_counter ++;
            if (local_counter >= iter_freq * max_iter){
                printf("..  done %lld iterations ..\n", local_counter / iter_freq);
                return;
            }
        }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2798, %rsp           # imm = 0x2798
movapd %xmm2, -0x50(%rbp)
movsd %xmm1, -0x30(%rbp)
movsd %xmm0, -0x68(%rbp)
movq %r9, -0x40(%rbp)
movq %r8, %r14
movq %rcx, %r15
movq %rdx, %r12
movq %rsi, -0x60(%rbp)
movq %rdi, %r13
leaq -0x27b8(%rbp), %rbx
movq %rbx, %rdi
callq 0x2140
movq %rbx, %rdi
callq 0x2220
movq 0x30(%rbp), %rbx
movq 0x20(%rbp), %rsi
movl %eax, %eax
movq %rax, -0x1430(%rbp)
movl $0x1, %ecx
movq %rax, %rdx
shrq $0x1e, %rdx
xorl %eax, %edx
imull $0x6c078965, %edx, %eax # imm = 0x6C078965
addl %ecx, %eax
movq %rax, -0x1430(%rbp,%rcx,8)
incq %rcx
cmpq $0x270, %rcx            # imm = 0x270
jne 0x27f1
leaq -0x1430(%rbp), %rax
movq $0x270, 0x1380(%rax) # imm = 0x270
leaq -0x1(%rsi), %rax
leaq -0xa8(%rbp), %rcx
movq $0x0, (%rcx)
movq %rax, 0x8(%rcx)
leaq -0x98(%rbp), %rsi
movl $0x1, %edi
callq 0x21c0
movapd -0x50(%rbp), %xmm0
movsd -0x30(%rbp), %xmm1
mulsd %xmm0, %xmm1
movsd %xmm1, -0x30(%rbp)
xorpd 0x1796(%rip), %xmm0     # 0x4000
movapd %xmm0, -0x50(%rbp)
xorps %xmm0, %xmm0
cvtsi2sdq 0x20(%rbp), %xmm0
movsd %xmm0, -0x58(%rbp)
imulq 0x48(%rbp), %rbx
cmpq $0x2, %rbx
movl $0x1, %eax
cmovgeq %rbx, %rax
movq %rax, -0x38(%rbp)
xorl %eax, %eax
movq %rax, -0x78(%rbp)
cqto
idivq 0x48(%rbp)
testq %rdx, %rdx
jne 0x2941
movq %rax, %rbx
movq 0x28(%rbp), %rdx
testq %rdx, %rdx
jle 0x28d9
movq %rbx, %rax
imulq %rdx, %rax
movq 0x38(%rbp), %rcx
leaq (%rcx,%rax,8), %rax
xorl %ecx, %ecx
movsd (%r13,%rcx,8), %xmm0
movsd %xmm0, (%rax,%rcx,8)
incq %rcx
cmpq %rcx, %rdx
jne 0x28c5
movl $0x1, %edi
leaq -0x88(%rbp), %rsi
callq 0x21c0
movq -0x88(%rbp), %rax
movq -0x80(%rbp), %rcx
subq -0x98(%rbp), %rax
xorps %xmm1, %xmm1
cvtsi2sd %rax, %xmm1
subq -0x90(%rbp), %rcx
xorps %xmm0, %xmm0
cvtsi2sd %rcx, %xmm0
divsd 0x16f5(%rip), %xmm0     # 0x4010
addsd %xmm1, %xmm0
movq 0x40(%rbp), %rax
movsd %xmm0, (%rax,%rbx,8)
divsd 0x16e8(%rip), %xmm0     # 0x4018
leaq 0x1701(%rip), %rdi      # 0x4038
movq %rbx, %rsi
movb $0x1, %al
callq 0x2050
leaq -0xa8(%rbp), %rdi
leaq -0x1430(%rbp), %rsi
movq %rdi, %rdx
callq 0x2090
movq %rax, %rbx
movq -0x40(%rbp), %rcx
movq (%rcx,%rax,8), %rax
movq 0x8(%rcx,%rbx,8), %rcx
xorpd %xmm0, %xmm0
cmpq %rcx, %rax
jge 0x298d
movq (%r14,%rax,8), %rdx
movsd (%r13,%rdx,8), %xmm1
mulsd (%r15,%rax,8), %xmm1
addsd %xmm1, %xmm0
incq %rax
cmpq %rax, %rcx
jne 0x2970
movq 0x10(%rbp), %rax
movsd (%rax,%rbx,8), %xmm1
movsd %xmm1, -0x70(%rbp)
mulsd %xmm1, %xmm0
ucomisd 0x1689(%rip), %xmm0     # 0x4030
jbe 0x29c4
xorpd 0x164f(%rip), %xmm0     # 0x4000
callq 0x2290
movsd 0x1662(%rip), %xmm2     # 0x4020
movapd %xmm2, %xmm1
jmp 0x29d5
callq 0x2290
movapd %xmm0, %xmm1
movsd 0x164b(%rip), %xmm2     # 0x4020
addsd %xmm2, %xmm0
divsd %xmm0, %xmm1
addsd 0x1643(%rip), %xmm1     # 0x4028
movsd -0x70(%rbp), %xmm2
mulsd %xmm1, %xmm2
movapd %xmm2, %xmm0
movq -0x60(%rbp), %rax
subsd (%rax,%rbx,8), %xmm0
movsd %xmm2, (%rax,%rbx,8)
movq -0x40(%rbp), %rcx
movq (%rcx,%rbx,8), %rax
movq 0x8(%rcx,%rbx,8), %rcx
cmpq %rcx, %rax
movapd -0x50(%rbp), %xmm5
movsd -0x30(%rbp), %xmm6
movsd -0x68(%rbp), %xmm7
movq 0x18(%rbp), %rsi
movsd -0x58(%rbp), %xmm8
xorpd %xmm9, %xmm9
movapd 0x15c9(%rip), %xmm10    # 0x4000
jge 0x2ac6
movq (%r14,%rax,8), %rdx
movsd (%rsi,%rdx,8), %xmm1
movsd (%r13,%rdx,8), %xmm2
movapd %xmm7, %xmm3
mulsd %xmm2, %xmm3
addsd (%r12,%rdx,8), %xmm3
mulsd %xmm1, %xmm3
movsd (%r15,%rax,8), %xmm4
mulsd %xmm0, %xmm4
addsd %xmm3, %xmm4
mulsd %xmm5, %xmm4
addsd %xmm2, %xmm4
mulsd %xmm6, %xmm1
movapd %xmm4, %xmm2
subsd %xmm1, %xmm2
maxsd %xmm9, %xmm2
xorpd %xmm10, %xmm4
subsd %xmm1, %xmm4
maxsd %xmm9, %xmm4
subsd %xmm4, %xmm2
movsd %xmm2, (%r13,%rdx,8)
movsd (%r15,%rax,8), %xmm1
mulsd %xmm0, %xmm1
divsd %xmm8, %xmm1
addsd (%r12,%rdx,8), %xmm1
movsd %xmm1, (%r12,%rdx,8)
incq %rax
cmpq %rax, %rcx
jne 0x2a3d
movq -0x78(%rbp), %rax
incq %rax
cmpq -0x38(%rbp), %rax
jne 0x2895
movq -0x38(%rbp), %rax
cqto
idivq 0x48(%rbp)
leaq 0x157b(%rip), %rdi      # 0x4063
movq %rax, %rsi
xorl %eax, %eax
callq 0x2050
leaq -0x27b8(%rbp), %rdi
callq 0x21d0
addq $0x2798, %rsp           # imm = 0x2798
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2b2b
jmp 0x2b14
movq %rax, %rbx
leaq -0x27b8(%rbp), %rdi
callq 0x21d0
movq %rbx, %rdi
callq 0x2280
movq %rax, %rdi
callq 0x31d8