// File: /workspace/github_cpp_makefile_star2_O3/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 0x4140
movq %rax, %rbx
leaq 0x2d85d(%rip), %rdi     # 0x332bc
callq 0x4380
leaq 0x3982d(%rip), %rdi     # 0x3f298
callq 0x9c82
leaq 0x460(%rsp), %rdx
leaq 0x60(%rsp), %rcx
leaq 0x1210(%rsp), %r8
movl %ebp, %edi
movq %r14, %rsi
callq 0x5f25
cmpl $0x0, 0x3986a(%rip)     # 0x3f300
je 0x5aae
leaq 0x397f9(%rip), %rsi     # 0x3f298
leaq 0x460(%rsp), %rdi
callq 0xebe0
jmp 0x5ac2
leaq 0x397e3(%rip), %rsi     # 0x3f298
leaq 0x460(%rsp), %rdi
callq 0xdc26
leaq 0x2d57b(%rip), %rsi     # 0x33044
leaq 0x60(%rsp), %rdi
callq 0x4290
testq %rax, %rax
je 0x5ed3
movq %rax, %r14
leaq 0x3c(%rsp), %r15
movl $0x0, (%r15)
leaq 0x868(%rsp), %r12
movq %r12, %rdi
callq 0x9c82
movq %r14, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0xa1f3
movb 0x3a042(%rip), %cl      # 0x3fb51
testb %cl, %cl
jne 0x5b20
movb 0x1121(%rsp), %cl
movb %cl, 0x3a031(%rip)      # 0x3fb51
movzbl 0x8a6(%rsp), %eax
movb %al, 0x397a8(%rip)      # 0x3f2d6
movzwl 0x8a7(%rsp), %edx
movw %dx, 0x3979a(%rip)      # 0x3f2d7
movb 0x1120(%rsp), %dl
movb %dl, 0x3a006(%rip)      # 0x3fb50
cmpb $0x3, %cl
setge %cl
cmpb $0x3, %dl
setge %dl
orb %cl, %dl
cmpb $0x1, %dl
jne 0x5b64
movb $0x1, 0x39766(%rip)     # 0x3f2ca
movb 0x1130(%rsp), %cl
movb %cl, 0x39fef(%rip)      # 0x3fb60
movq $0x0, 0x30(%rsp)
decl %eax
leaq 0x2d48d(%rip), %rcx     # 0x33010
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x90, %edi
callq 0x4210
movq %rax, %r15
leaq 0x396f8(%rip), %rsi     # 0x3f298
movq %rax, %rdi
callq 0x10972
jmp 0x5ca4
movl $0xa0, %edi
callq 0x4210
movq %rax, %r15
leaq 0x396d7(%rip), %rsi     # 0x3f298
movq %rax, %rdi
callq 0x1faac
jmp 0x5ca4
movl $0xa8, %edi
callq 0x4210
movq %rax, %r15
leaq 0x396b6(%rip), %rsi     # 0x3f298
movq %rax, %rdi
callq 0x2adac
jmp 0x5ca4
movl $0x98, %edi
callq 0x4210
movq %rax, %r15
leaq 0x39695(%rip), %rsi     # 0x3f298
movq %rax, %rdi
callq 0x19984
jmp 0x5ca4
movl $0xa0, %edi
callq 0x4210
movq %rax, %r15
leaq 0x39674(%rip), %rsi     # 0x3f298
movq %rax, %rdi
callq 0x1b9e4
jmp 0x5ca4
movl $0xd0, %edi
callq 0x4210
movq %rax, %r15
leaq 0x39656(%rip), %rsi     # 0x3f298
movq %rax, %rdi
callq 0x24a20
jmp 0x5ca4
movl $0xa0, %edi
callq 0x4210
movq %rax, %r15
leaq 0x39638(%rip), %rsi     # 0x3f298
movq %rax, %rdi
callq 0x30b34
jmp 0x5ca4
movl $0xa8, %edi
callq 0x4210
movq %rax, %r15
leaq 0x3961a(%rip), %rsi     # 0x3f298
movq %rax, %rdi
callq 0x21fc8
jmp 0x5ca4
movl $0x98, %edi
callq 0x4210
movq %rax, %r15
leaq 0x395fc(%rip), %rsi     # 0x3f298
movq %rax, %rdi
callq 0x1d964
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 0x4200
cmpb $0x0, 0x39600(%rip)     # 0x3f2d4
jne 0x5d06
movsbl 0x39e74(%rip), %esi     # 0x3fb51
movl 0x39e71(%rip), %edx     # 0x3fb54
movl 0x39e6f(%rip), %ecx     # 0x3fb58
movl 0x39e6c(%rip), %r8d     # 0x3fb5c
movsbl 0x39e68(%rip), %r9d     # 0x3fb60
leaq 0x2d361(%rip), %rdi     # 0x33060
xorl %eax, %eax
callq 0x4050
callq 0x4140
movq %rax, %r14
movl $0x7, %edi
movl $0x8, %esi
callq 0x4130
movq %rax, 0x39f1c(%rip)     # 0x3fc40
movq 0x39ddd(%rip), %rdx     # 0x3fb08
movq 0x39dde(%rip), %rcx     # 0x3fb10
movq 0x39ddf(%rip), %r8      # 0x3fb18
movq 0x39de0(%rip), %r9      # 0x3fb20
movupd 0x39de0(%rip), %xmm0    # 0x3fb28
leaq 0x30(%rsp), %rsi
movq %rsi, 0x10(%rsp)
movupd %xmm0, (%rsp)
movq $0x0, 0x20(%rsp)
movl $0x1, 0x18(%rsp)
leaq 0x1210(%rsp), %rsi
movq %rax, %rdi
callq 0x1313a
cmpb $0x0, 0x39555(%rip)     # 0x3f2d4
jne 0x5da7
callq 0x4140
subq %r14, %rax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
divsd 0x2d26f(%rip), %xmm0    # 0x33008
leaq 0x2d2ef(%rip), %rdi     # 0x3308f
movb $0x1, %al
callq 0x4050
movq 0x39e92(%rip), %rax     # 0x3fc40
movsd (%rax), %xmm0
movsd %xmm0, 0x58(%rsp)
movsd 0x8(%rax), %xmm0
movsd %xmm0, 0x50(%rsp)
movq 0x30(%rsp), %rdi
callq 0x141fc
addl %eax, %eax
xorps %xmm0, %xmm0
cvtsi2sd %eax, %xmm0
movq 0x39e63(%rip), %rax     # 0x3fc40
movsd (%rax), %xmm1
addsd %xmm1, %xmm1
addsd %xmm0, %xmm1
movsd %xmm1, 0x48(%rsp)
movq 0x30(%rsp), %rdi
callq 0x141fc
xorps %xmm0, %xmm0
cvtsi2sd %eax, %xmm0
movsd %xmm0, 0x40(%rsp)
leaq 0x3948b(%rip), %r14     # 0x3f298
xorps %xmm0, %xmm0
cvtsi2sdl 0x39d30(%rip), %xmm0 # 0x3fb48
callq 0x8e3d
movq 0x39e1c(%rip), %rax     # 0x3fc40
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 0x2d25f(%rip), %rdi     # 0x330b4
movsd 0x58(%rsp), %xmm0
movsd 0x50(%rsp), %xmm1
movsd 0x48(%rsp), %xmm2
movb $0x8, %al
callq 0x4050
movq 0x39dcb(%rip), %rdi     # 0x3fc40
callq 0x42a0
movq %r14, %rdi
callq 0x9e75
movq 0x30(%rsp), %rdi
testq %rdi, %rdi
je 0x5e92
movq (%rdi), %rax
callq *0x8(%rax)
cmpb $0x0, 0x3943b(%rip)     # 0x3f2d4
jne 0x5ec1
callq 0x4140
subq %rbx, %rax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
divsd 0x2d155(%rip), %xmm0    # 0x33008
leaq 0x2d259(%rip), %rdi     # 0x33113
movb $0x1, %al
callq 0x4050
xorl %eax, %eax
addq $0x1610, %rsp           # imm = 0x1610
popq %rbx
popq %r12
popq %r14
popq %r15
popq %rbp
retq
leaq 0x60(%rsp), %rdi
callq 0x44a0
jmp 0x5ef9
jmp 0x5f03
jmp 0x5f0d
movq %rax, %rbx
movl $0xd0, %esi
jmp 0x5f15
jmp 0x5f0d
movq %rax, %rbx
movl $0x90, %esi
jmp 0x5f15
movq %rax, %rbx
movl $0x98, %esi
jmp 0x5f15
movq %rax, %rbx
movl $0xa8, %esi
jmp 0x5f15
movq %rax, %rbx
movl $0xa0, %esi
movq %r15, %rdi
callq 0x4220
movq %rbx, %rdi
callq 0x4430