// File: /workspace/github_cpp_makefile_star2_O2/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, -0x80(%rbp)
movq %r9, -0x38(%rbp)
movq %r8, %r14
movq %rcx, %r15
movq %rdx, %r12
movq %rsi, -0x68(%rbp)
movq %rdi, %r13
leaq -0x1438(%rbp), %rbx
movq %rbx, %rdi
callq 0x3210
movq %rbx, %rdi
callq 0x3350
movl %eax, %esi
leaq -0x27c0(%rbp), %rdi
callq 0x3430
movq 0x30(%rbp), %rbx
movq 0x20(%rbp), %rax
decq %rax
leaq -0xb0(%rbp), %rcx
andq $0x0, (%rcx)
movq %rax, 0x8(%rcx)
pushq $0x1
popq %rdi
leaq -0xa0(%rbp), %rsi
callq 0x3280
movapd -0x50(%rbp), %xmm0
movsd -0x30(%rbp), %xmm1
mulsd %xmm0, %xmm1
movsd %xmm1, -0x30(%rbp)
xorpd 0x16c0(%rip), %xmm0     # 0x5000
movapd %xmm0, -0x50(%rbp)
cvtsi2sdq 0x20(%rbp), %xmm0
movsd %xmm0, -0x78(%rbp)
imulq 0x48(%rbp), %rbx
movq %rbx, -0x60(%rbp)
xorl %eax, %eax
movq 0x28(%rbp), %rdx
testq %rdx, %rdx
movl $0x0, %ecx
cmovgq %rdx, %rcx
movq %rcx, -0x58(%rbp)
movq %rax, -0x70(%rbp)
cqto
idivq 0x48(%rbp)
testq %rdx, %rdx
jne 0x3a11
movq %rax, %rbx
imulq 0x28(%rbp), %rax
movq 0x38(%rbp), %rcx
leaq (%rcx,%rax,8), %rax
xorl %ecx, %ecx
movq -0x58(%rbp), %rdx
cmpq %rcx, %rdx
je 0x39ae
movsd (%r13,%rcx,8), %xmm0
movsd %xmm0, (%rax,%rcx,8)
incq %rcx
jmp 0x3998
pushq $0x1
popq %rdi
leaq -0x90(%rbp), %rsi
callq 0x3280
movq -0x90(%rbp), %rax
movq -0x88(%rbp), %rcx
subq -0xa0(%rbp), %rax
cvtsi2sd %rax, %xmm1
subq -0x98(%rbp), %rcx
cvtsi2sd %rcx, %xmm0
divsd 0x1625(%rip), %xmm0     # 0x5010
addsd %xmm1, %xmm0
movq 0x40(%rbp), %rax
movsd %xmm0, (%rax,%rbx,8)
divsd 0x1618(%rip), %xmm0     # 0x5018
leaq 0x163d(%rip), %rdi      # 0x5044
movq %rbx, %rsi
movb $0x1, %al
callq 0x3050
leaq -0xb0(%rbp), %rdi
leaq -0x27c0(%rbp), %rsi
callq 0x31d0
movq %rax, %rbx
movq -0x38(%rbp), %rcx
movq (%rcx,%rax,8), %rax
movq 0x8(%rcx,%rbx,8), %rcx
xorpd %xmm0, %xmm0
cmpq %rcx, %rax
jge 0x3a57
movq (%r14,%rax,8), %rdx
movsd (%r13,%rdx,8), %xmm1
mulsd (%r15,%rax,8), %xmm1
addsd %xmm1, %xmm0
incq %rax
jmp 0x3a38
movq 0x10(%rbp), %rax
movsd (%rax,%rbx,8), %xmm1
callq 0x30e0
movapd %xmm0, %xmm1
movq -0x68(%rbp), %rax
subsd (%rax,%rbx,8), %xmm1
movsd %xmm0, (%rax,%rbx,8)
movq -0x38(%rbp), %rcx
movq (%rcx,%rbx,8), %rax
movq 0x8(%rcx,%rbx,8), %rcx
cmpq %rcx, %rax
jge 0x3b1e
movq (%r14,%rax,8), %rdx
movq 0x18(%rbp), %rsi
movsd (%rsi,%rdx,8), %xmm0
movsd (%r13,%rdx,8), %xmm2
movsd -0x80(%rbp), %xmm3
mulsd %xmm2, %xmm3
addsd (%r12,%rdx,8), %xmm3
mulsd %xmm0, %xmm3
movsd (%r15,%rax,8), %xmm4
mulsd %xmm1, %xmm4
addsd %xmm3, %xmm4
mulsd -0x50(%rbp), %xmm4
addsd %xmm2, %xmm4
mulsd -0x30(%rbp), %xmm0
movapd %xmm4, %xmm2
subsd %xmm0, %xmm2
xorpd %xmm3, %xmm3
maxsd %xmm3, %xmm2
xorpd 0x1518(%rip), %xmm4     # 0x5000
subsd %xmm0, %xmm4
maxsd %xmm3, %xmm4
subsd %xmm4, %xmm2
movsd %xmm2, (%r13,%rdx,8)
movsd (%r15,%rax,8), %xmm0
mulsd %xmm1, %xmm0
divsd -0x78(%rbp), %xmm0
addsd (%r12,%rdx,8), %xmm0
movsd %xmm0, (%r12,%rdx,8)
incq %rax
jmp 0x3a84
movq -0x70(%rbp), %rax
incq %rax
cmpq -0x60(%rbp), %rax
jl 0x396f
cqto
idivq 0x48(%rbp)
leaq 0x1533(%rip), %rdi      # 0x506f
movq %rax, %rsi
xorl %eax, %eax
callq 0x3050
leaq -0x1438(%rbp), %rdi
callq 0x31c0
addq $0x2798, %rsp           # imm = 0x2798
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x3b66
movq %rax, %rbx
leaq -0x1438(%rbp), %rdi
callq 0x31c0
movq %rbx, %rdi
callq 0x33e0