// File: myudelson[P]hmm-scalable/predicthmm.cpp
// Function: main
int main (int argc, char ** argv) {
	clock_t tm0 = clock();
	printf("predicthmm starting...\n");
	set_param_defaults(&param);
	
	char input_file[1024];
	char model_file[1024];
	char predict_file[1024];
	
	parse_arguments(argc, argv, input_file, model_file, predict_file);
    // param.predictions = 2; // do not force it on

    // read data
    if(param.binaryinput==0) {
        InputUtil::readTxt(input_file, &param);
    } else {
        InputUtil::readBin(input_file, &param);
    }
    
    // read model header
	FILE *fid = fopen(model_file,"r");
	if(fid == NULL)
	{
		fprintf(stderr,"Can't read model file %s\n",model_file);
		exit(1);
	}
	int max_line_length = 1024;
	char *line = Malloc(char,(size_t)max_line_length);
	NDAT line_no = 0;
    struct param param_model;
    set_param_defaults(&param_model);
    bool overwrite = false;
//    if(overwrite)
        readSolverInfo(fid, &param_model, &line_no);
//    else
//        readSolverInfo(fid, &initparam, &line_no);
    
    // copy partial info from param_model to param
    if(param.nO==0) param.nO = param_model.nO;
    param.structure = param_model.structure;
    param.solver = param_model.solver;
    param.solver_setting = param_model.solver_setting;
    
    // copy number of states from the model
    param.nS = param_model.nS;
    
    // if number of states or observations >2, then no check
    if( param.nO>2 || param.nS>2) {
        param.do_not_check_constraints = 1;
    }
    
	// copy number of slices from the model
	param.nZ = param_model.nZ;
    //
    // create hmm Object
    //
    HMMProblem *hmm = NULL;
	switch(param.structure)
	{
		case STRUCTURE_SKILL: // Conjugate Gradient Descent
//            case STRUCTURE_GROUP: // Conjugate Gradient Descent
			hmm = new HMMProblem(&param);
			break;
//            case STRUCTURE_PIg: // Gradient Descent: PI by group, A,B by skill
//                hmm = new HMMProblemPiG(&param);
//                break;
		case STRUCTURE_SKABslc: // Conjugate Gradient Descent
			hmm = new HMMProblemSlicedAB(&param);
			break;
		case STRUCTURE_SKAslc: // Conjugate Gradient Descent
			hmm = new HMMProblemSlicedA(&param);
			break;
		case STRUCTURE_PIgk: // Gradient Descent, pLo=f(K,G), other by K
			hmm = new HMMProblemPiGK(&param);
			break;
		case STRUCTURE_PIgkww: // Gradient Descent, pLo=f(K,G), other by K
			hmm = new HMMProblemPiGKww(&param);
			break;
		case STRUCTURE_PIAgk: // Gradient Descent, pLo=f(K,G), pT=f(K,G), other by K
			hmm = new HMMProblemPiAGK(&param);
			break;
		case STRUCTURE_Agk: // Gradient Descent, pT=f(K,G), other by K
			hmm = new HMMProblemAGK(&param);
			break;
//                case STRUCTURE_Agki: // Gradient Descent, pT=f(K,G), other by K
//                    hmm = new HMMProblemAGKi(&param);
//                    break;
		case STRUCTURE_PIABgk: // Gradient Descent, pT=f(K,G), other by K
			hmm = new HMMProblemPiABGK(&param);
			break;
//            case BKT_GD_T: // Gradient Descent with Transfer
//                hmm = new HMMProblemKT(&param);
//                break;
		case STRUCTURE_COMP: // Gradient Descent, pT=f(K,G), other by K
			hmm = new HMMProblemComp(&param);
			break;
//        case STRUCTURE_ELOK: // Gradient Descent, pT=f(K,G), other by K
//            hmm = new HMMProblemEloK(&param);
//            break;
	}
    // read model body
    hmm->readModelBody(fid, &param_model, &line_no, overwrite);
  	fclose(fid);
	free(line);
	
	if(param.quiet == 0)
        printf("input read, nO=%d, nG=%d, nK=%d, nI=%d, nZ=%d\n",param.nO, param.nG, param.nK, param.nI, param.nZ);
	
	clock_t tm = clock();
//    if(param.metrics>0 || param.predictions>0) {
        metrics = Calloc(NUMBER, (size_t)7);// LL, AIC, BIC, RMSE, RMSEnonull, Acc, Acc_nonull;
//    }
	HMMProblem::predict(metrics, predict_file, param.dat_obs, param.dat_group, param.dat_skill, param.dat_skill_stacked, param.dat_skill_rcount, param.dat_skill_rix, &hmm, 1, NULL);
//    predict(predict_file, hmm);
	if(param.quiet == 0)
		printf("predicting is done in %8.6f seconds\n",(NUMBER)(clock()-tm)/CLOCKS_PER_SEC);
    //if( param.predictions>0 ) {
        printf("trained model LL=%15.7f (%15.7f), AIC=%8.6f, BIC=%8.6f, RMSE=%8.6f (%8.6f), Acc=%8.6f (%8.6f)\n",
               metrics[0], metrics[1], // ll's
               2*hmm->getNparams() + 2*metrics[0], hmm->getNparams()*safelog(param.N) + 2*metrics[0],
               metrics[2], metrics[3], // rmse's
               metrics[4], metrics[5]); // acc's
    //}
    free(metrics);
    
	destroy_input_data(&param);
	
    delete hmm;
	if(param.quiet == 0)
		printf("overall time running is %8.6f seconds\n",(NUMBER)(clock()-tm0)/CLOCKS_PER_SEC);
    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %rbx
subq $0x16a8, %rsp           # imm = 0x16A8
movl $0x0, -0xc(%rbp)
movl %edi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
callq 0x5190
movq %rax, -0x20(%rbp)
leaq 0x49606(%rip), %rdi     # 0x4f160
movb $0x0, %al
callq 0x5060
leaq 0x557d0(%rip), %rdi     # 0x5b338
callq 0xb1d0
movl -0x10(%rbp), %edi
movq -0x18(%rbp), %rsi
leaq -0x420(%rbp), %rdx
leaq -0x820(%rbp), %rcx
leaq -0xc20(%rbp), %r8
callq 0x6330
cmpl $0x0, 0x5580b(%rip)     # 0x5b3a0
jne 0x5bac
leaq -0x420(%rbp), %rdi
leaq 0x55793(%rip), %rsi     # 0x5b338
callq 0x132b0
jmp 0x5bbf
leaq -0x420(%rbp), %rdi
leaq 0x5577e(%rip), %rsi     # 0x5b338
callq 0x14e20
leaq -0x820(%rbp), %rdi
leaq 0x495ab(%rip), %rsi     # 0x4f178
callq 0x5370
movq %rax, -0xc28(%rbp)
cmpq $0x0, -0xc28(%rbp)
jne 0x5c0c
movq 0x553ee(%rip), %rax     # 0x5afd8
movq (%rax), %rdi
leaq -0x820(%rbp), %rdx
leaq 0x4957f(%rip), %rsi     # 0x4f17a
movb $0x0, %al
callq 0x5440
movl $0x1, %edi
callq 0x5390
movl $0x400, -0xc2c(%rbp)    # imm = 0x400
movslq -0xc2c(%rbp), %rdi
shlq $0x0, %rdi
callq 0x53e0
movq %rax, -0xc38(%rbp)
movl $0x0, -0xc3c(%rbp)
leaq -0x15e8(%rbp), %rdi
callq 0xb1d0
movb $0x0, -0x15e9(%rbp)
movq -0xc28(%rbp), %rdi
leaq -0x15e8(%rbp), %rsi
leaq -0xc3c(%rbp), %rdx
callq 0xbd80
movsbl 0x55f86(%rip), %eax     # 0x5bbf1
cmpl $0x0, %eax
jne 0x5c7c
movb -0xd2f(%rbp), %al
movb %al, 0x55f75(%rip)      # 0x5bbf1
movb -0x15aa(%rbp), %al
movb %al, 0x556ee(%rip)      # 0x5b376
movb -0x15a9(%rbp), %al
movb %al, 0x556e3(%rip)      # 0x5b377
movb -0x15a8(%rbp), %al
movb %al, 0x556d8(%rip)      # 0x5b378
movb -0xd30(%rbp), %al
movb %al, 0x55f44(%rip)      # 0x5bbf0
movsbl 0x55f3e(%rip), %eax     # 0x5bbf1
cmpl $0x2, %eax
jg 0x5cc4
movsbl 0x55f31(%rip), %eax     # 0x5bbf0
cmpl $0x2, %eax
jle 0x5ccb
movb $0x1, 0x5569f(%rip)     # 0x5b36a
movb -0xd20(%rbp), %al
movb %al, 0x55f29(%rip)      # 0x5bc00
movq $0x0, -0x15f8(%rbp)
movsbl 0x5568d(%rip), %eax     # 0x5b376
decl %eax
movl %eax, %ecx
movq %rcx, -0x1618(%rbp)
subl $0xc, %eax
ja 0x6071
movq -0x1618(%rbp), %rax
leaq 0x4930d(%rip), %rcx     # 0x4f018
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x90, %edi
callq 0x52d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1620(%rbp)
leaq 0x55606(%rip), %rsi     # 0x5b338
callq 0x19550
jmp 0x5d39
movq -0x1620(%rbp), %rax
movq %rax, -0x15f8(%rbp)
jmp 0x6071
movq -0x1620(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1600(%rbp)
movl %eax, -0x1604(%rbp)
movl $0x90, %esi
callq 0x52e0
jmp 0x6322
movl $0xd0, %edi
callq 0x52d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1628(%rbp)
leaq 0x555a6(%rip), %rsi     # 0x5b338
callq 0x38730
jmp 0x5d99
movq -0x1628(%rbp), %rax
movq %rax, -0x15f8(%rbp)
jmp 0x6071
movq -0x1628(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1600(%rbp)
movl %eax, -0x1604(%rbp)
movl $0xd0, %esi
callq 0x52e0
jmp 0x6322
movl $0xa8, %edi
callq 0x52d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1630(%rbp)
leaq 0x55546(%rip), %rsi     # 0x5b338
callq 0x42440
jmp 0x5df9
movq -0x1630(%rbp), %rax
movq %rax, -0x15f8(%rbp)
jmp 0x6071
movq -0x1630(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1600(%rbp)
movl %eax, -0x1604(%rbp)
movl $0xa8, %esi
callq 0x52e0
jmp 0x6322
movl $0x98, %edi
callq 0x52d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1638(%rbp)
leaq 0x554e6(%rip), %rsi     # 0x5b338
callq 0x27e90
jmp 0x5e59
movq -0x1638(%rbp), %rax
movq %rax, -0x15f8(%rbp)
jmp 0x6071
movq -0x1638(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1600(%rbp)
movl %eax, -0x1604(%rbp)
movl $0x98, %esi
callq 0x52e0
jmp 0x6322
movl $0xa0, %edi
callq 0x52d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1640(%rbp)
leaq 0x55486(%rip), %rsi     # 0x5b338
callq 0x2ad90
jmp 0x5eb9
movq -0x1640(%rbp), %rax
movq %rax, -0x15f8(%rbp)
jmp 0x6071
movq -0x1640(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1600(%rbp)
movl %eax, -0x1604(%rbp)
movl $0xa0, %esi
callq 0x52e0
jmp 0x6322
movl $0xa0, %edi
callq 0x52d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1648(%rbp)
leaq 0x55426(%rip), %rsi     # 0x5b338
callq 0x30da0
jmp 0x5f19
movq -0x1648(%rbp), %rax
movq %rax, -0x15f8(%rbp)
jmp 0x6071
movq -0x1648(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1600(%rbp)
movl %eax, -0x1604(%rbp)
movl $0xa0, %esi
callq 0x52e0
jmp 0x6322
movl $0x98, %edi
callq 0x52d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1650(%rbp)
leaq 0x553c6(%rip), %rsi     # 0x5b338
callq 0x2db70
jmp 0x5f79
movq -0x1650(%rbp), %rax
movq %rax, -0x15f8(%rbp)
jmp 0x6071
movq -0x1650(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1600(%rbp)
movl %eax, -0x1604(%rbp)
movl $0x98, %esi
callq 0x52e0
jmp 0x6322
movl $0xa8, %edi
callq 0x52d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1658(%rbp)
leaq 0x55366(%rip), %rsi     # 0x5b338
callq 0x345e0
jmp 0x5fd9
movq -0x1658(%rbp), %rax
movq %rax, -0x15f8(%rbp)
jmp 0x6071
movq -0x1658(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1600(%rbp)
movl %eax, -0x1604(%rbp)
movl $0xa8, %esi
callq 0x52e0
jmp 0x6322
movl $0xa0, %edi
callq 0x52d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1660(%rbp)
leaq 0x55306(%rip), %rsi     # 0x5b338
callq 0x4b550
jmp 0x6039
movq -0x1660(%rbp), %rax
movq %rax, -0x15f8(%rbp)
jmp 0x6071
movq -0x1660(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1600(%rbp)
movl %eax, -0x1604(%rbp)
movl $0xa0, %esi
callq 0x52e0
jmp 0x6322
movq -0x15f8(%rbp), %rdi
movq -0xc28(%rbp), %rsi
movb -0x15e9(%rbp), %r8b
movq (%rdi), %rax
leaq -0x15e8(%rbp), %rdx
leaq -0xc3c(%rbp), %rcx
andb $0x1, %r8b
movzbl %r8b, %r8d
callq *0x68(%rax)
movq -0xc28(%rbp), %rdi
callq 0x52c0
movq -0xc38(%rbp), %rdi
callq 0x5380
movsbl 0x552b3(%rip), %eax     # 0x5b374
cmpl $0x0, %eax
jne 0x60f6
movsbl 0x55b24(%rip), %esi     # 0x5bbf1
movl 0x55b21(%rip), %edx     # 0x5bbf4
movl 0x55b1f(%rip), %ecx     # 0x5bbf8
movl 0x55b1c(%rip), %r8d     # 0x5bbfc
movsbl 0x55b18(%rip), %r9d     # 0x5bc00
leaq 0x490a5(%rip), %rdi     # 0x4f194
movb $0x0, %al
callq 0x5060
callq 0x5190
movq %rax, -0x1610(%rbp)
movl $0x7, %edi
movl $0x8, %esi
callq 0x5180
movq %rax, 0x55bc8(%rip)     # 0x5bce0
movq 0x55bc1(%rip), %rdi     # 0x5bce0
leaq -0xc20(%rbp), %rsi
movq 0x55a7b(%rip), %rdx     # 0x5bba8
movq 0x55a7c(%rip), %rcx     # 0x5bbb0
movq 0x55a7d(%rip), %r8      # 0x5bbb8
movq 0x55a7e(%rip), %r9      # 0x5bbc0
movq 0x55a7f(%rip), %r11     # 0x5bbc8
movq 0x55a80(%rip), %r10     # 0x5bbd0
leaq -0x15f8(%rbp), %rax
xorl %ebx, %ebx
movq %r11, (%rsp)
movq %r10, 0x8(%rsp)
movq %rax, 0x10(%rsp)
movl $0x1, 0x18(%rsp)
movq $0x0, 0x20(%rsp)
callq 0x1d3c0
movsbl 0x551f0(%rip), %eax     # 0x5b374
cmpl $0x0, %eax
jne 0x61b4
callq 0x5190
subq -0x1610(%rbp), %rax
cvtsi2sd %rax, %xmm0
movsd 0x48e66(%rip), %xmm1    # 0x4f008
divsd %xmm1, %xmm0
leaq 0x49016(%rip), %rdi     # 0x4f1c3
movb $0x1, %al
callq 0x5060
movq 0x55b25(%rip), %rax     # 0x5bce0
movsd (%rax), %xmm0
movsd %xmm0, -0x1670(%rbp)
movq 0x55b12(%rip), %rax     # 0x5bce0
movsd 0x8(%rax), %xmm0
movsd %xmm0, -0x1680(%rbp)
movq -0x15f8(%rbp), %rdi
callq 0x1e710
shll %eax
cvtsi2sd %eax, %xmm1
movq 0x55aec(%rip), %rax     # 0x5bce0
movsd (%rax), %xmm0
addsd %xmm0, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0x1678(%rbp)
movq -0x15f8(%rbp), %rdi
callq 0x1e710
cvtsi2sd %eax, %xmm0
movsd %xmm0, -0x1688(%rbp)
cvtsi2sdl 0x559c0(%rip), %xmm0 # 0x5bbe8
callq 0x9ae0
movsd -0x1688(%rbp), %xmm3
movsd -0x1680(%rbp), %xmm1
movsd -0x1678(%rbp), %xmm2
movaps %xmm0, %xmm5
movsd -0x1670(%rbp), %xmm0
movq 0x55a89(%rip), %rax     # 0x5bce0
movsd 0x48db1(%rip), %xmm4    # 0x4f010
mulsd (%rax), %xmm4
mulsd %xmm5, %xmm3
addsd %xmm4, %xmm3
movq 0x55a6e(%rip), %rax     # 0x5bce0
movsd 0x10(%rax), %xmm4
movq 0x55a62(%rip), %rax     # 0x5bce0
movsd 0x18(%rax), %xmm5
movq 0x55a56(%rip), %rax     # 0x5bce0
movsd 0x20(%rax), %xmm6
movq 0x55a4a(%rip), %rax     # 0x5bce0
movsd 0x28(%rax), %xmm7
leaq 0x48f46(%rip), %rdi     # 0x4f1e8
movb $0x8, %al
callq 0x5060
movq 0x55a30(%rip), %rdi     # 0x5bce0
callq 0x5380
leaq 0x5507c(%rip), %rdi     # 0x5b338
callq 0xb830
movq -0x15f8(%rbp), %rax
movq %rax, -0x1668(%rbp)
cmpq $0x0, %rax
je 0x62e2
movq -0x1668(%rbp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
movsbl 0x5508b(%rip), %eax     # 0x5b374
cmpl $0x0, %eax
jne 0x6316
callq 0x5190
subq -0x20(%rbp), %rax
cvtsi2sd %rax, %xmm0
movsd 0x48d04(%rip), %xmm1    # 0x4f008
divsd %xmm1, %xmm0
leaq 0x48f38(%rip), %rdi     # 0x4f247
movb $0x1, %al
callq 0x5060
xorl %eax, %eax
addq $0x16a8, %rsp           # imm = 0x16A8
popq %rbx
popq %rbp
retq
movq -0x1600(%rbp), %rdi
callq 0x5540
nop