// File: /workspace/github_cpp_makefile_star2_O2/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
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x1610, %rsp           # imm = 0x1610
movq %rsi, %r14
movl %edi, %ebp
callq 0x4130
movq %rax, %rbx
leaq 0x2797d(%rip), %rdi     # 0x2c2bc
callq 0x43a0
leaq 0x3496d(%rip), %rdi     # 0x392b8
callq 0x7532
leaq 0x460(%rsp), %rdx
leaq 0x60(%rsp), %rcx
leaq 0x1210(%rsp), %r8
movl %ebp, %edi
movq %r14, %rsi
callq 0x4e04
cmpl $0x0, 0x349aa(%rip)     # 0x39320
je 0x498e
leaq 0x34939(%rip), %rsi     # 0x392b8
leaq 0x460(%rsp), %rdi
callq 0xbcbe
jmp 0x49a2
leaq 0x34923(%rip), %rsi     # 0x392b8
leaq 0x460(%rsp), %rdi
callq 0xb002
leaq 0x2769b(%rip), %rsi     # 0x2c044
leaq 0x60(%rsp), %rdi
callq 0x4280
testq %rax, %rax
je 0x4d97
movq %rax, %r14
leaq 0x3c(%rsp), %r15
andl $0x0, (%r15)
leaq 0x868(%rsp), %r12
movq %r12, %rdi
callq 0x7532
movq %r14, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0x7a11
movb 0x35185(%rip), %cl      # 0x39b71
testb %cl, %cl
jne 0x49fd
movb 0x1121(%rsp), %cl
movb %cl, 0x35174(%rip)      # 0x39b71
movzbl 0x8a6(%rsp), %eax
movb %al, 0x348eb(%rip)      # 0x392f6
movzwl 0x8a7(%rsp), %edx
movw %dx, 0x348dd(%rip)      # 0x392f7
movb 0x1120(%rsp), %dl
movb %dl, 0x35149(%rip)      # 0x39b70
cmpb $0x3, %cl
setge %cl
cmpb $0x3, %dl
setge %dl
orb %cl, %dl
cmpb $0x1, %dl
jne 0x4a41
movb $0x1, 0x348a9(%rip)     # 0x392ea
movb 0x1130(%rsp), %cl
movb %cl, 0x35132(%rip)      # 0x39b80
andq $0x0, 0x30(%rsp)
decl %eax
leaq 0x275b3(%rip), %rcx     # 0x2c010
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x90, %edi
callq 0x4220
movq %rax, %r15
leaq 0x3483e(%rip), %rsi     # 0x392b8
movq %rax, %rdi
callq 0xd978
jmp 0x4b7e
movl $0xa0, %edi
callq 0x4220
movq %rax, %r15
leaq 0x3481d(%rip), %rsi     # 0x392b8
movq %rax, %rdi
callq 0x1ae94
jmp 0x4b7e
movl $0xa8, %edi
callq 0x4220
movq %rax, %r15
leaq 0x347fc(%rip), %rsi     # 0x392b8
movq %rax, %rdi
callq 0x24c46
jmp 0x4b7e
movl $0x98, %edi
callq 0x4220
movq %rax, %r15
leaq 0x347db(%rip), %rsi     # 0x392b8
movq %rax, %rdi
callq 0x15b6c
jmp 0x4b7e
movl $0xa0, %edi
callq 0x4220
movq %rax, %r15
leaq 0x347ba(%rip), %rsi     # 0x392b8
movq %rax, %rdi
callq 0x176c8
jmp 0x4b7e
movl $0xd0, %edi
callq 0x4220
movq %rax, %r15
leaq 0x3479c(%rip), %rsi     # 0x392b8
movq %rax, %rdi
callq 0x1f450
jmp 0x4b7e
movl $0xa0, %edi
callq 0x4220
movq %rax, %r15
leaq 0x3477e(%rip), %rsi     # 0x392b8
movq %rax, %rdi
callq 0x29df4
jmp 0x4b7e
movl $0xa8, %edi
callq 0x4220
movq %rax, %r15
leaq 0x34760(%rip), %rsi     # 0x392b8
movq %rax, %rdi
callq 0x1cf1c
jmp 0x4b7e
movl $0x98, %edi
callq 0x4220
movq %rax, %r15
leaq 0x34742(%rip), %rsi     # 0x392b8
movq %rax, %rdi
callq 0x191cc
movq %r15, 0x30(%rsp)
movq (%r15), %rax
leaq 0x868(%rsp), %rdx
leaq 0x3c(%rsp), %rcx
movq %r15, %rdi
movq %r14, %rsi
xorl %r8d, %r8d
callq *0x68(%rax)
movq %r14, %rdi
callq 0x4210
cmpb $0x0, 0x34746(%rip)     # 0x392f4
jne 0x4be0
movsbl 0x34fba(%rip), %esi     # 0x39b71
movl 0x34fb7(%rip), %edx     # 0x39b74
movl 0x34fb5(%rip), %ecx     # 0x39b78
movl 0x34fb2(%rip), %r8d     # 0x39b7c
movsbl 0x34fae(%rip), %r9d     # 0x39b80
leaq 0x27487(%rip), %rdi     # 0x2c060
xorl %eax, %eax
callq 0x4050
callq 0x4130
movq %rax, %r14
pushq $0x7
popq %rdi
pushq $0x8
popq %rsi
callq 0x4120
movq %rax, 0x35066(%rip)     # 0x39c60
movq 0x34f27(%rip), %rdx     # 0x39b28
movq 0x34f28(%rip), %rcx     # 0x39b30
movq 0x34f29(%rip), %r8      # 0x39b38
movq 0x34f2a(%rip), %r9      # 0x39b40
movupd 0x34f2a(%rip), %xmm0    # 0x39b48
leaq 0x30(%rsp), %rsi
movq %rsi, 0x10(%rsp)
movupd %xmm0, (%rsp)
andq $0x0, 0x20(%rsp)
movl $0x1, 0x18(%rsp)
leaq 0x1210(%rsp), %rsi
movq %rax, %rdi
callq 0xfcd8
cmpb $0x0, 0x346a2(%rip)     # 0x392f4
jne 0x4c77
callq 0x4130
subq %r14, %rax
cvtsi2sd %rax, %xmm0
divsd 0x2739f(%rip), %xmm0    # 0x2c008
leaq 0x2741f(%rip), %rdi     # 0x2c08f
movb $0x1, %al
callq 0x4050
movq 0x34fe2(%rip), %rax     # 0x39c60
movsd (%rax), %xmm0
movsd %xmm0, 0x58(%rsp)
movsd 0x8(%rax), %xmm0
movsd %xmm0, 0x50(%rsp)
movq 0x30(%rsp), %rdi
callq 0x10b2c
addl %eax, %eax
cvtsi2sd %eax, %xmm0
movq 0x34fb6(%rip), %rax     # 0x39c60
movsd (%rax), %xmm1
addsd %xmm1, %xmm1
addsd %xmm0, %xmm1
movsd %xmm1, 0x48(%rsp)
movq 0x30(%rsp), %rdi
callq 0x10b2c
cvtsi2sd %eax, %xmm0
movsd %xmm0, 0x40(%rsp)
leaq 0x345e1(%rip), %r14     # 0x392b8
cvtsi2sdl 0x34e89(%rip), %xmm0 # 0x39b68
callq 0x67ff
movq 0x34f75(%rip), %rax     # 0x39c60
movsd (%rax), %xmm1
movsd 0x10(%rax), %xmm4
addsd %xmm1, %xmm1
movsd 0x40(%rsp), %xmm3
mulsd %xmm0, %xmm3
addsd %xmm1, %xmm3
movsd 0x18(%rax), %xmm5
movsd 0x20(%rax), %xmm6
movsd 0x28(%rax), %xmm7
leaq 0x27398(%rip), %rdi     # 0x2c0b4
movsd 0x58(%rsp), %xmm0
movsd 0x50(%rsp), %xmm1
movsd 0x48(%rsp), %xmm2
movb $0x8, %al
callq 0x4050
movq 0x34f24(%rip), %rdi     # 0x39c60
callq 0x4290
movq %r14, %rdi
callq 0x7726
movq 0x30(%rsp), %rdi
testq %rdi, %rdi
je 0x4d59
movq (%rdi), %rax
callq *0x8(%rax)
cmpb $0x0, 0x34594(%rip)     # 0x392f4
jne 0x4d85
callq 0x4130
subq %rbx, %rax
cvtsi2sd %rax, %xmm0
divsd 0x27291(%rip), %xmm0    # 0x2c008
leaq 0x27395(%rip), %rdi     # 0x2c113
movb $0x1, %al
callq 0x4050
xorl %eax, %eax
addq $0x1610, %rsp           # imm = 0x1610
popq %rbx
popq %r12
popq %r14
popq %r15
popq %rbp
retq
movq 0x3423a(%rip), %rax     # 0x38fd8
movq (%rax), %rdi
leaq 0x2729e(%rip), %rsi     # 0x2c046
leaq 0x60(%rsp), %rdx
xorl %eax, %eax
callq 0x4350
pushq $0x1
popq %rdi
callq 0x42a0
jmp 0x4dd8
jmp 0x4de2
jmp 0x4dec
movq %rax, %rbx
movl $0xd0, %esi
jmp 0x4df4
jmp 0x4dec
movq %rax, %rbx
movl $0x90, %esi
jmp 0x4df4
movq %rax, %rbx
movl $0x98, %esi
jmp 0x4df4
movq %rax, %rbx
movl $0xa8, %esi
jmp 0x4df4
movq %rax, %rbx
movl $0xa0, %esi
movq %r15, %rdi
callq 0x4230
movq %rbx, %rdi
callq 0x4450