// File: lipiji[P]PG_DEEP/train.cpp
// Function: main
int main(int argc, const char *argv[])
{
    string ftx = "./data/test_x.txt";
    string fty = "./data/test_y.txt";
    int epoch = 100;
    int batch_size = 0;
    double gamma = 0.1; // learning rate
    int k = 1; //Contrastive Divergence k

    int hls[] = {500, 500, 900};
    int n_layers = sizeof(hls) / sizeof(hls[0]);
    int n_lables = 10;
    double lbd = 0.0002; // weight cost

    Conf conf(ftx, fty, epoch, batch_size, hls, k, gamma, n_layers, n_lables, lbd);
    Dataset data(conf);

    /*// test rbm
      RBM rbm(data.N, data.n_f, 400, NULL, NULL, NULL, lbd, 0);

      for(int i=0; i<epoch; i++)
      {
      cout << "epoch: " << i << endl;
      for(int j=0; j<data.N; j++)
      {
      double *x = new double[data.n_f];
      for(int f=0; f<data.n_f; f++)
      x[f] = data.X[j][f];
      rbm.train(x, gamma, k);
      delete[] x;


      }
      ofstream fout("./model/W1");
      for(int j=0; j<rbm.n_visible; j++)
      {
      for(int l=0; l<rbm.n_hidden; l++)
      {
      fout << rbm.W[l][j] << " ";
      }
      fout << endl;
      }
      fout << flush;
      fout.close();


      }
      */
    //test lr

    /*
       LR lr(data, conf);
       for(int i=0; i<epoch; i++)
       {
       cout << "epoch: " << i << endl;
       for(int j=0; j<data.N; j++)
       {
       double *x = new double[lr.n_features];
       for(int f=0; f<lr.n_features; f++)
       x[f] = data.X[j][f];
       int *y = new int[lr.n_labels];
       y[int(data.Y[j])] = 1;

       lr.train(x, y, gamma);
       delete[] x;
       delete[] y;
       }
       }
       for(int j=0; j<data.N; j++)
       {
       double *x = new double[lr.n_features];
       for(int f=0; f<lr.n_features; f++)
       x[f] = data.X[j][f];
       double *y = new double[lr.n_labels];

       lr.predict(x, y);
       cout <<data.Y[j]<<": ";
       for(int i=0; i<lr.n_labels; i++)
       cout <<y[i]<<" ";
       cout<<endl;
       delete[] y;
       }
       */


    DBN dbn(data, conf);
    dbn.pretrain(data, conf);
    for(int i=0; i<=n_layers; i++)
    {
        char str[] = "./model/W";
        char W_l[128];
        sprintf(W_l, "%s%d", str, (i+1));

        ofstream fout(W_l);
        if(i < n_layers)
        {
            for(int j=0; j<dbn.rbm_layers[i]->n_visible; j++)
            {
                for(int l=0; l<dbn.rbm_layers[i]->n_hidden; l++)
                {
                    fout << dbn.rbm_layers[i]->W[l][j] << " ";
                }
                fout << endl;
            }
        }
        else
        {
            for(int j=0; j<dbn.lr_layer->n_features; j++)
            {
                for(int l=0; l<dbn.lr_layer->n_labels; l++)
                {
                    fout << dbn.lr_layer->W[l][j] << " ";
                }
                fout << endl;
            }
        }

        fout << flush;
        fout.close();

    }
    dbn.finetune(data, conf);

    ftx = "./data/train_x.txt";
    fty = "./data/train_y.txt";

    Conf conf_(ftx, fty, epoch, batch_size, hls, k, gamma, n_layers, n_lables, lbd);
    Dataset data_(conf_);


    double acc_num = 0;
    for(int j=0; j<data_.N; j++)
    {
        double *x = new double[data_.n_f];
        for(int f=0; f<data_.n_f; f++)
            x[f] = data_.X[j][f];
        double *y = new double[conf.n_labels];
        int true_label = int(data_.Y[j]);

        if(dbn.predict(x, y, true_label) == 1)
            acc_num++;
        delete[] x;
        delete[] y;

        cout << j <<": Accuracy=" << acc_num/(j+1) <<endl;
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xac0, %rsp            # imm = 0xAC0
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
leaq -0x31(%rbp), %rdi
movq %rdi, -0xa48(%rbp)
callq 0x23b0
movq -0xa48(%rbp), %rdx
leaq 0x8a49(%rip), %rsi      # 0xb010
leaq -0x30(%rbp), %rdi
callq 0x30c0
jmp 0x25d2
leaq -0x31(%rbp), %rdi
callq 0x2260
leaq -0x69(%rbp), %rdi
movq %rdi, -0xa50(%rbp)
callq 0x23b0
movq -0xa50(%rbp), %rdx
leaq 0x8a29(%rip), %rsi      # 0xb022
leaq -0x68(%rbp), %rdi
callq 0x30c0
jmp 0x2604
leaq -0x69(%rbp), %rdi
callq 0x2260
movl $0x64, -0x70(%rbp)
movl $0x0, -0x74(%rbp)
movabsq $0x3fb999999999999a, %rax # imm = 0x3FB999999999999A
movq %rax, -0x80(%rbp)
movl $0x1, -0x84(%rbp)
movabsq $0x1f4000001f4, %rax    # imm = 0x1F4000001F4
movq %rax, -0x90(%rbp)
movl $0x384, -0x88(%rbp)     # imm = 0x384
movl $0x3, -0x94(%rbp)
movl $0xa, -0x98(%rbp)
movabsq $0x3f2a36e2eb1c432d, %rax # imm = 0x3F2A36E2EB1C432D
movq %rax, -0xa0(%rbp)
leaq -0x170(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x20f0
jmp 0x2685
leaq -0x190(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x20f0
jmp 0x2697
movl -0x70(%rbp), %ecx
movl -0x74(%rbp), %r8d
movl -0x84(%rbp), %edx
movsd -0x80(%rbp), %xmm0
movl -0x94(%rbp), %esi
movl -0x98(%rbp), %edi
movsd -0xa0(%rbp), %xmm1
movq %rsp, %rax
movl %edi, 0x10(%rax)
movl %esi, 0x8(%rax)
movl %edx, (%rax)
leaq -0x150(%rbp), %rdi
leaq -0x170(%rbp), %rsi
leaq -0x190(%rbp), %rdx
leaq -0x90(%rbp), %r9
callq 0x4b70
jmp 0x26eb
leaq -0x190(%rbp), %rdi
callq 0x2140
leaq -0x170(%rbp), %rdi
callq 0x2140
leaq -0x280(%rbp), %rdi
leaq -0x150(%rbp), %rsi
callq 0x3170
jmp 0x2718
leaq -0x1d0(%rbp), %rdi
leaq -0x280(%rbp), %rsi
callq 0x4d00
jmp 0x272d
leaq -0x280(%rbp), %rdi
callq 0x4cb0
leaq -0x2f8(%rbp), %rdi
leaq -0x1d0(%rbp), %rsi
callq 0x3260
jmp 0x274e
leaq -0x3a8(%rbp), %rdi
leaq -0x150(%rbp), %rsi
callq 0x3170
jmp 0x2763
leaq -0x2b8(%rbp), %rdi
leaq -0x2f8(%rbp), %rsi
leaq -0x3a8(%rbp), %rdx
callq 0x6d50
jmp 0x277f
leaq -0x3a8(%rbp), %rdi
callq 0x4cb0
leaq -0x2f8(%rbp), %rdi
callq 0x5b50
leaq -0x3e8(%rbp), %rdi
leaq -0x1d0(%rbp), %rsi
callq 0x3260
jmp 0x27ac
leaq -0x498(%rbp), %rdi
leaq -0x150(%rbp), %rsi
callq 0x3170
jmp 0x27c1
leaq -0x2b8(%rbp), %rdi
leaq -0x3e8(%rbp), %rsi
leaq -0x498(%rbp), %rdx
callq 0x6ff0
jmp 0x27dd
leaq -0x498(%rbp), %rdi
callq 0x4cb0
leaq -0x3e8(%rbp), %rdi
callq 0x5b50
movl $0x0, -0x49c(%rbp)
movl -0x49c(%rbp), %eax
cmpl -0x94(%rbp), %eax
jg 0x2bd7
movabsq $0x2f6c65646f6d2f2e, %rax # imm = 0x2F6C65646F6D2F2E
movq %rax, -0x4a8(%rbp)
movw $0x57, -0x4a0(%rbp)
movl -0x49c(%rbp), %ecx
incl %ecx
leaq 0x8804(%rip), %rsi      # 0xb03e
xorl %eax, %eax
leaq -0x530(%rbp), %rdi
movq %rdi, -0xa58(%rbp)
leaq -0x4a8(%rbp), %rdx
callq 0x2060
movq -0xa58(%rbp), %rsi
leaq -0x730(%rbp), %rdi
movl $0x10, %edx
callq 0x2270
jmp 0x2870
movl -0x49c(%rbp), %eax
cmpl -0x94(%rbp), %eax
jge 0x2acc
movl $0x0, -0x734(%rbp)
movl -0x734(%rbp), %eax
movq -0x290(%rbp), %rcx
movslq -0x49c(%rbp), %rdx
movq (%rcx,%rdx,8), %rcx
cmpl 0x4(%rcx), %eax
jge 0x2ac7
movl $0x0, -0x738(%rbp)
movl -0x738(%rbp), %eax
movq -0x290(%rbp), %rcx
movslq -0x49c(%rbp), %rdx
movq (%rcx,%rdx,8), %rcx
cmpl 0x8(%rcx), %eax
jge 0x2a9c
movq -0x290(%rbp), %rax
movslq -0x49c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq 0x10(%rax), %rax
movslq -0x738(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movslq -0x734(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
leaq -0x730(%rbp), %rdi
callq 0x23f0
movq %rax, -0xa60(%rbp)
jmp 0x291a
movq -0xa60(%rbp), %rdi
leaq 0x8881(%rip), %rsi      # 0xb1a9
callq 0x2210
jmp 0x292f
jmp 0x2931
movl -0x738(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x738(%rbp)
jmp 0x28b7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x31(%rbp), %rdi
callq 0x2260
jmp 0x30b5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x69(%rbp), %rdi
callq 0x2260
jmp 0x30ac
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x30a3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x29b0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x190(%rbp), %rdi
callq 0x2140
leaq -0x170(%rbp), %rdi
callq 0x2140
jmp 0x30a3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x3097
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x280(%rbp), %rdi
callq 0x4cb0
jmp 0x3097
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x308b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x2a26
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x3a8(%rbp), %rdi
callq 0x4cb0
leaq -0x2f8(%rbp), %rdi
callq 0x5b50
jmp 0x308b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x307f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x2a6e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x498(%rbp), %rdi
callq 0x4cb0
leaq -0x3e8(%rbp), %rdi
callq 0x5b50
jmp 0x307f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x730(%rbp), %rdi
callq 0x2330
jmp 0x307f
movq 0xc51d(%rip), %rsi      # 0xefc0
leaq -0x730(%rbp), %rdi
callq 0x2240
jmp 0x2ab1
jmp 0x2ab3
movl -0x734(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x734(%rbp)
jmp 0x288c
jmp 0x2b94
movl $0x0, -0x73c(%rbp)
movl -0x73c(%rbp), %eax
movq -0x288(%rbp), %rcx
cmpl 0x4(%rcx), %eax
jge 0x2b92
movl $0x0, -0x740(%rbp)
movl -0x740(%rbp), %eax
movq -0x288(%rbp), %rcx
cmpl 0x8(%rcx), %eax
jge 0x2b67
movq -0x288(%rbp), %rax
movq 0x18(%rax), %rax
movslq -0x740(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movslq -0x73c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
leaq -0x730(%rbp), %rdi
callq 0x23f0
movq %rax, -0xa68(%rbp)
jmp 0x2b3f
movq -0xa68(%rbp), %rdi
leaq 0x865c(%rip), %rsi      # 0xb1a9
callq 0x2210
jmp 0x2b54
jmp 0x2b56
movl -0x740(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x740(%rbp)
jmp 0x2af6
movq 0xc452(%rip), %rsi      # 0xefc0
leaq -0x730(%rbp), %rdi
callq 0x2240
jmp 0x2b7c
jmp 0x2b7e
movl -0x73c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x73c(%rbp)
jmp 0x2ad6
jmp 0x2b94
movq 0xc43d(%rip), %rsi      # 0xefd8
leaq -0x730(%rbp), %rdi
callq 0x2240
jmp 0x2ba9
leaq -0x730(%rbp), %rdi
callq 0x2310
jmp 0x2bb7
leaq -0x730(%rbp), %rdi
callq 0x2330
movl -0x49c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x49c(%rbp)
jmp 0x27ff
leaq -0x780(%rbp), %rdi
leaq -0x1d0(%rbp), %rsi
callq 0x3260
jmp 0x2bec
leaq -0x830(%rbp), %rdi
leaq -0x150(%rbp), %rsi
callq 0x3170
jmp 0x2c01
leaq -0x2b8(%rbp), %rdi
leaq -0x780(%rbp), %rsi
leaq -0x830(%rbp), %rdx
callq 0x7bc0
jmp 0x2c1d
leaq -0x830(%rbp), %rdi
callq 0x4cb0
leaq -0x780(%rbp), %rdi
callq 0x5b50
leaq 0x8407(%rip), %rsi      # 0xb043
leaq -0x30(%rbp), %rdi
callq 0x22f0
jmp 0x2c47
leaq 0x8408(%rip), %rsi      # 0xb056
leaq -0x68(%rbp), %rdi
callq 0x22f0
jmp 0x2c59
leaq -0x900(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x20f0
jmp 0x2c6b
leaq -0x920(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x20f0
jmp 0x2c7d
movl -0x70(%rbp), %ecx
movl -0x74(%rbp), %r8d
movl -0x84(%rbp), %edx
movsd -0x80(%rbp), %xmm0
movl -0x94(%rbp), %esi
movl -0x98(%rbp), %edi
movsd -0xa0(%rbp), %xmm1
movq %rsp, %rax
movl %edi, 0x10(%rax)
movl %esi, 0x8(%rax)
movl %edx, (%rax)
leaq -0x8e0(%rbp), %rdi
leaq -0x900(%rbp), %rsi
leaq -0x920(%rbp), %rdx
leaq -0x90(%rbp), %r9
callq 0x4b70
jmp 0x2cd1
leaq -0x920(%rbp), %rdi
callq 0x2140
leaq -0x900(%rbp), %rdi
callq 0x2140
leaq -0xa10(%rbp), %rdi
leaq -0x8e0(%rbp), %rsi
callq 0x3170
jmp 0x2cfe
leaq -0x960(%rbp), %rdi
leaq -0xa10(%rbp), %rsi
callq 0x4d00
jmp 0x2d13
leaq -0xa10(%rbp), %rdi
callq 0x4cb0
xorps %xmm0, %xmm0
movsd %xmm0, -0xa18(%rbp)
movl $0x0, -0xa1c(%rbp)
movl -0xa1c(%rbp), %eax
cmpl -0x960(%rbp), %eax
jge 0x3012
movslq -0x95c(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0x2030
movq %rax, -0xa70(%rbp)
jmp 0x2d71
movq -0xa70(%rbp), %rax
movq %rax, -0xa28(%rbp)
movl $0x0, -0xa2c(%rbp)
movl -0xa2c(%rbp), %eax
cmpl -0x95c(%rbp), %eax
jge 0x2ea2
leaq -0x960(%rbp), %rdi
addq $0x8, %rdi
movslq -0xa1c(%rbp), %rsi
callq 0x32e0
movq %rax, %rdi
movslq -0xa2c(%rbp), %rsi
callq 0x3300
movsd (%rax), %xmm0
movq -0xa28(%rbp), %rax
movslq -0xa2c(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0xa2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa2c(%rbp)
jmp 0x2d89
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x2e0f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x830(%rbp), %rdi
callq 0x4cb0
leaq -0x780(%rbp), %rdi
callq 0x5b50
jmp 0x307f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x2e46
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x920(%rbp), %rdi
callq 0x2140
leaq -0x900(%rbp), %rdi
callq 0x2140
jmp 0x307f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x3073
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0xa10(%rbp), %rdi
callq 0x4cb0
jmp 0x3073
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x960(%rbp), %rdi
callq 0x5b50
jmp 0x3073
movslq -0xac(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0x2030
movq %rax, -0xa78(%rbp)
jmp 0x2ecd
movq -0xa78(%rbp), %rax
movq %rax, -0xa38(%rbp)
leaq -0x940(%rbp), %rdi
movslq -0xa1c(%rbp), %rsi
callq 0x3300
cvttsd2si (%rax), %eax
movl %eax, -0xa3c(%rbp)
movq -0xa28(%rbp), %rsi
movq -0xa38(%rbp), %rdx
movl -0xa3c(%rbp), %ecx
leaq -0x2b8(%rbp), %rdi
callq 0x8af0
movl %eax, -0xa7c(%rbp)
jmp 0x2f20
movl -0xa7c(%rbp), %eax
cmpl $0x1, %eax
jne 0x2f43
movsd 0x80d5(%rip), %xmm0     # 0xb008
addsd -0xa18(%rbp), %xmm0
movsd %xmm0, -0xa18(%rbp)
movq -0xa28(%rbp), %rax
movq %rax, -0xa88(%rbp)
cmpq $0x0, %rax
je 0x2f63
movq -0xa88(%rbp), %rdi
callq 0x22e0
movq -0xa38(%rbp), %rax
movq %rax, -0xa90(%rbp)
cmpq $0x0, %rax
je 0x2f83
movq -0xa90(%rbp), %rdi
callq 0x22e0
movl -0xa1c(%rbp), %esi
movq 0xc040(%rip), %rdi      # 0xefd0
callq 0x2380
movq %rax, -0xa98(%rbp)
jmp 0x2f9e
movq -0xa98(%rbp), %rdi
leaq 0x80bd(%rip), %rsi      # 0xb069
callq 0x2210
movq %rax, -0xaa0(%rbp)
jmp 0x2fba
movq -0xaa0(%rbp), %rdi
movsd -0xa18(%rbp), %xmm0
movl -0xa1c(%rbp), %eax
incl %eax
cvtsi2sd %eax, %xmm1
divsd %xmm1, %xmm0
callq 0x23f0
movq %rax, -0xaa8(%rbp)
jmp 0x2fe7
movq -0xaa8(%rbp), %rdi
movq 0xbfcb(%rip), %rsi      # 0xefc0
callq 0x2240
jmp 0x2ffc
jmp 0x2ffe
movl -0xa1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa1c(%rbp)
jmp 0x2d34
movl $0x0, -0x4(%rbp)
leaq -0x960(%rbp), %rdi
callq 0x5b50
leaq -0x8e0(%rbp), %rdi
callq 0x4cb0
leaq -0x2b8(%rbp), %rdi
callq 0x8df0
leaq -0x1d0(%rbp), %rdi
callq 0x5b50
leaq -0x150(%rbp), %rdi
callq 0x4cb0
leaq -0x68(%rbp), %rdi
callq 0x2140
leaq -0x30(%rbp), %rdi
callq 0x2140
movl -0x4(%rbp), %eax
addq $0xac0, %rsp            # imm = 0xAC0
popq %rbp
retq
leaq -0x8e0(%rbp), %rdi
callq 0x4cb0
leaq -0x2b8(%rbp), %rdi
callq 0x8df0
leaq -0x1d0(%rbp), %rdi
callq 0x5b50
leaq -0x150(%rbp), %rdi
callq 0x4cb0
leaq -0x68(%rbp), %rdi
callq 0x2140
leaq -0x30(%rbp), %rdi
callq 0x2140
movq -0x40(%rbp), %rdi
callq 0x23a0
nop