// File: /workspace/github_cpp_makefile_star2_O2/fabianp[P]ProxASAGA/proxasaga_atomic.cpp
// Function: saga_single_thread(std::atomic<double>*, std::atomic<double>*, std::atomic<double>*, double*, long*, long*, double*, double*, long, long, double, double, double, long, double*, double*, int, long)
void saga_single_thread(
        std::atomic<double>* x, std::atomic<double>* memory_gradient, std::atomic<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, int thread_id, 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 && thread_id == 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].load();
      while (!memory_gradient[i].compare_exchange_weak(old_grad, 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]);
          add_atomic(&gradient_average[j_idx], incr * A_data[j] / n_samples);
      }
      local_counter ++;
      if (local_counter >= iter_freq * max_iter){
          if (thread_id == 0) {
              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 $0x27c8, %rsp           # imm = 0x27C8
movapd %xmm2, -0x60(%rbp)
movsd %xmm1, -0x38(%rbp)
movsd %xmm0, -0xa8(%rbp)
movq %r9, %rbx
movq %r8, -0x40(%rbp)
movq %rcx, %r15
movq %rdx, -0xa0(%rbp)
movq %rsi, -0x88(%rbp)
movq %rdi, %r13
leaq -0x1460(%rbp), %r14
movq %r14, %rdi
callq 0x3210
movq %r14, %rdi
callq 0x3350
movl %eax, %esi
leaq -0x27e8(%rbp), %rdi
callq 0x3430
movq 0x30(%rbp), %r12
movq 0x28(%rbp), %r14
movq 0x20(%rbp), %rax
decq %rax
leaq -0xd8(%rbp), %rcx
andq $0x0, (%rcx)
movq %rax, 0x8(%rcx)
pushq $0x1
popq %rdi
leaq -0xc8(%rbp), %rsi
callq 0x3280
movapd -0x60(%rbp), %xmm0
movsd -0x38(%rbp), %xmm1
mulsd %xmm0, %xmm1
movsd %xmm1, -0x38(%rbp)
xorpd 0x1a06(%rip), %xmm0     # 0x5000
movapd %xmm0, -0x60(%rbp)
cvtsi2sdq 0x20(%rbp), %xmm0
movsd %xmm0, -0x98(%rbp)
imulq 0x50(%rbp), %r12
movq %r12, -0x80(%rbp)
xorl %eax, %eax
testq %r14, %r14
movl $0x0, %ecx
cmovgq %r14, %rcx
movq %rcx, %r14
movq %rcx, -0x78(%rbp)
movq %rbx, -0x70(%rbp)
movq %r15, -0x68(%rbp)
movq %rax, -0x90(%rbp)
cqto
idivq 0x50(%rbp)
cmpl $0x0, 0x48(%rbp)
jne 0x36dc
testq %rdx, %rdx
jne 0x36dc
movq %rax, %r12
imulq 0x28(%rbp), %rax
movq 0x38(%rbp), %rcx
leaq (%rcx,%rax,8), %rax
xorl %ecx, %ecx
cmpq %rcx, %r14
je 0x3678
movq (%r13,%rcx,8), %rdx
movq %rdx, (%rax,%rcx,8)
incq %rcx
jmp 0x3665
pushq $0x1
popq %rdi
leaq -0xb8(%rbp), %rsi
callq 0x3280
movq -0xb8(%rbp), %rax
movq -0xb0(%rbp), %rcx
subq -0xc8(%rbp), %rax
cvtsi2sd %rax, %xmm1
subq -0xc0(%rbp), %rcx
cvtsi2sd %rcx, %xmm0
divsd 0x195b(%rip), %xmm0     # 0x5010
addsd %xmm1, %xmm0
movq 0x40(%rbp), %rax
movsd %xmm0, (%rax,%r12,8)
divsd 0x194d(%rip), %xmm0     # 0x5018
leaq 0x1972(%rip), %rdi      # 0x5044
movq %r12, %rsi
movb $0x1, %al
callq 0x3050
leaq -0xd8(%rbp), %rdi
leaq -0x27e8(%rbp), %rsi
callq 0x31d0
movq %rax, %r12
movq (%rbx,%rax,8), %rax
xorpd %xmm0, %xmm0
cmpq 0x8(%rbx,%r12,8), %rax
jge 0x371f
movq -0x40(%rbp), %rcx
movq (%rcx,%rax,8), %rcx
movsd (%r13,%rcx,8), %xmm1
mulsd (%r15,%rax,8), %xmm1
addsd %xmm1, %xmm0
incq %rax
jmp 0x36fa
movq 0x10(%rbp), %rax
movsd (%rax,%r12,8), %xmm1
callq 0x30e0
movq -0x88(%rbp), %rax
leaq (%rax,%r12,8), %r14
movq (%rax,%r12,8), %rax
movq %rax, -0x48(%rbp)
leaq -0x48(%rbp), %rbx
pushq $0x5
popq %r15
movsd %xmm0, -0x30(%rbp)
movq %r14, %rdi
movq %rbx, %rsi
movsd -0x30(%rbp), %xmm0
movl %r15d, %edx
callq 0x3060
movsd -0x30(%rbp), %xmm0
testb %al, %al
je 0x374e
subsd -0x48(%rbp), %xmm0
movsd %xmm0, -0x30(%rbp)
movq -0x70(%rbp), %rbx
movq (%rbx,%r12,8), %r14
movq -0x68(%rbp), %r15
cmpq 0x8(%rbx,%r12,8), %r14
jge 0x3834
movq -0x40(%rbp), %rax
movq (%rax,%r14,8), %rax
movq -0xa0(%rbp), %rcx
leaq (%rcx,%rax,8), %rdi
movsd (%r15,%r14,8), %xmm0
movsd -0x30(%rbp), %xmm4
mulsd %xmm4, %xmm0
movsd (%rdi), %xmm1
movsd (%r13,%rax,8), %xmm2
mulsd -0xa8(%rbp), %xmm2
addsd %xmm1, %xmm2
movq 0x18(%rbp), %rcx
mulsd (%rcx,%rax,8), %xmm2
addsd %xmm0, %xmm2
mulsd -0x60(%rbp), %xmm2
addsd (%r13,%rax,8), %xmm2
movsd (%rcx,%rax,8), %xmm0
mulsd -0x38(%rbp), %xmm0
movapd %xmm2, %xmm1
subsd %xmm0, %xmm1
xorpd %xmm3, %xmm3
maxsd %xmm3, %xmm1
xorpd 0x1801(%rip), %xmm2     # 0x5000
subsd %xmm0, %xmm2
maxsd %xmm3, %xmm2
subsd %xmm2, %xmm1
movq %xmm1, %rcx
xchgq %rcx, (%r13,%rax,8)
movsd (%r15,%r14,8), %xmm0
mulsd %xmm4, %xmm0
divsd -0x98(%rbp), %xmm0
callq 0x31a0
incq %r14
jmp 0x3780
movq -0x90(%rbp), %rax
incq %rax
cmpq -0x80(%rbp), %rax
movq -0x78(%rbp), %r14
jl 0x3633
cmpl $0x0, 0x48(%rbp)
jne 0x3869
cqto
idivq 0x50(%rbp)
leaq 0x1810(%rip), %rdi      # 0x506f
movq %rax, %rsi
xorl %eax, %eax
callq 0x3050
leaq -0x1460(%rbp), %rdi
callq 0x31c0
addq $0x27c8, %rsp           # imm = 0x27C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x3889
movq %rax, %rbx
leaq -0x1460(%rbp), %rdi
callq 0x31c0
movq %rbx, %rdi
callq 0x33e0