// File: /workspace/github_cpp_makefile_star2_O1/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 0x2e77d(%rip), %rdi     # 0x342bc
callq 0x4380
leaq 0x3a74d(%rip), %rdi     # 0x40298
callq 0x9c08
leaq 0x460(%rsp), %rdx
leaq 0x60(%rsp), %rcx
leaq 0x1210(%rsp), %r8
movl %ebp, %edi
movq %r14, %rsi
callq 0x6013
cmpl $0x0, 0x3a78a(%rip)     # 0x40300
je 0x5b8e
leaq 0x3a719(%rip), %rsi     # 0x40298
leaq 0x460(%rsp), %rdi
callq 0xed50
jmp 0x5ba2
leaq 0x3a703(%rip), %rsi     # 0x40298
leaq 0x460(%rsp), %rdi
callq 0xdbee
leaq 0x2e49b(%rip), %rsi     # 0x34044
leaq 0x60(%rsp), %rdi
callq 0x4290
testq %rax, %rax
je 0x5fc1
movq %rax, %r14
leaq 0x3c(%rsp), %r15
movl $0x0, (%r15)
leaq 0x868(%rsp), %r12
movq %r12, %rdi
callq 0x9c08
movq %r14, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0xa1e6
cmpb $0x0, 0x3af61(%rip)     # 0x40b51
jne 0x5bff
movb 0x1121(%rsp), %al
movb %al, 0x3af52(%rip)      # 0x40b51
movzbl 0x8a6(%rsp), %eax
movb %al, 0x3a6c9(%rip)      # 0x402d6
movzwl 0x8a7(%rsp), %ecx
movw %cx, 0x3a6bb(%rip)      # 0x402d7
movb 0x1120(%rsp), %cl
movb %cl, 0x3af27(%rip)      # 0x40b50
cmpb $0x3, 0x3af21(%rip)     # 0x40b51
setge %dl
cmpb $0x3, %cl
setge %cl
orb %dl, %cl
cmpb $0x1, %cl
jne 0x5c47
movb $0x1, 0x3a683(%rip)     # 0x402ca
movb 0x1130(%rsp), %cl
movb %cl, 0x3af0c(%rip)      # 0x40b60
movq $0x0, 0x30(%rsp)
decl %eax
cmpl $0xc, %eax
ja 0x5d95
leaq 0x2e3a1(%rip), %rcx     # 0x34010
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x90, %edi
callq 0x4210
movq %rax, %r15
leaq 0x3a60c(%rip), %rsi     # 0x40298
movq %rax, %rdi
callq 0x10b3a
jmp 0x5d90
movl $0xa0, %edi
callq 0x4210
movq %rax, %r15
leaq 0x3a5eb(%rip), %rsi     # 0x40298
movq %rax, %rdi
callq 0x1fe30
jmp 0x5d90
movl $0xa0, %edi
callq 0x4210
movq %rax, %r15
leaq 0x3a5ca(%rip), %rsi     # 0x40298
movq %rax, %rdi
callq 0x1bc14
jmp 0x5d90
movl $0x98, %edi
callq 0x4210
movq %rax, %r15
leaq 0x3a5a9(%rip), %rsi     # 0x40298
movq %rax, %rdi
callq 0x19bbc
jmp 0x5d90
movl $0xd0, %edi
callq 0x4210
movq %rax, %r15
leaq 0x3a588(%rip), %rsi     # 0x40298
movq %rax, %rdi
callq 0x24f24
jmp 0x5d90
movl $0xa8, %edi
callq 0x4210
movq %rax, %r15
leaq 0x3a56a(%rip), %rsi     # 0x40298
movq %rax, %rdi
callq 0x2b308
jmp 0x5d90
movl $0x98, %edi
callq 0x4210
movq %rax, %r15
leaq 0x3a54c(%rip), %rsi     # 0x40298
movq %rax, %rdi
callq 0x1dc38
jmp 0x5d90
movl $0xa8, %edi
callq 0x4210
movq %rax, %r15
leaq 0x3a52e(%rip), %rsi     # 0x40298
movq %rax, %rdi
callq 0x22408
jmp 0x5d90
movl $0xa0, %edi
callq 0x4210
movq %rax, %r15
leaq 0x3a510(%rip), %rsi     # 0x40298
movq %rax, %rdi
callq 0x30fd8
movq %r15, 0x30(%rsp)
movq 0x30(%rsp), %rdi
movq (%rdi), %rax
leaq 0x868(%rsp), %rdx
leaq 0x3c(%rsp), %rcx
movq %r14, %rsi
xorl %r8d, %r8d
callq *0x68(%rax)
movq %r14, %rdi
callq 0x4200
cmpb $0x0, 0x3a512(%rip)     # 0x402d4
jne 0x5df4
movsbl 0x3ad86(%rip), %esi     # 0x40b51
movl 0x3ad83(%rip), %edx     # 0x40b54
movl 0x3ad81(%rip), %ecx     # 0x40b58
movl 0x3ad7e(%rip), %r8d     # 0x40b5c
movsbl 0x3ad7a(%rip), %r9d     # 0x40b60
leaq 0x2e273(%rip), %rdi     # 0x34060
xorl %eax, %eax
callq 0x4050
callq 0x4140
movq %rax, %r14
movl $0x7, %edi
movl $0x8, %esi
callq 0x4130
movq %rax, 0x3ae2e(%rip)     # 0x40c40
movq 0x3acef(%rip), %rdx     # 0x40b08
movq 0x3acf0(%rip), %rcx     # 0x40b10
movq 0x3acf1(%rip), %r8      # 0x40b18
movq 0x3acf2(%rip), %r9      # 0x40b20
movupd 0x3acf2(%rip), %xmm0    # 0x40b28
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 0x13326
cmpb $0x0, 0x3a467(%rip)     # 0x402d4
jne 0x5e95
callq 0x4140
subq %r14, %rax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
divsd 0x2e181(%rip), %xmm0    # 0x34008
leaq 0x2e201(%rip), %rdi     # 0x3408f
movb $0x1, %al
callq 0x4050
movq 0x3ada4(%rip), %rax     # 0x40c40
movsd (%rax), %xmm0
movsd %xmm0, 0x58(%rsp)
movsd 0x8(%rax), %xmm0
movsd %xmm0, 0x50(%rsp)
movq 0x30(%rsp), %rdi
callq 0x1439c
addl %eax, %eax
xorps %xmm0, %xmm0
cvtsi2sd %eax, %xmm0
movq 0x3ad75(%rip), %rax     # 0x40c40
movsd (%rax), %xmm1
addsd %xmm1, %xmm1
addsd %xmm0, %xmm1
movsd %xmm1, 0x48(%rsp)
movq 0x30(%rsp), %rdi
callq 0x1439c
xorps %xmm0, %xmm0
cvtsi2sd %eax, %xmm0
movsd %xmm0, 0x40(%rsp)
leaq 0x3a39d(%rip), %r14     # 0x40298
xorps %xmm0, %xmm0
cvtsi2sdl 0x3ac42(%rip), %xmm0 # 0x40b48
callq 0x8dcd
movq 0x3ad2e(%rip), %rax     # 0x40c40
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 0x2e171(%rip), %rdi     # 0x340b4
movsd 0x58(%rsp), %xmm0
movsd 0x50(%rsp), %xmm1
movsd 0x48(%rsp), %xmm2
movb $0x8, %al
callq 0x4050
movq 0x3acdd(%rip), %rdi     # 0x40c40
callq 0x42a0
movq %r14, %rdi
callq 0x9e62
movq 0x30(%rsp), %rdi
testq %rdi, %rdi
je 0x5f80
movq (%rdi), %rax
callq *0x8(%rax)
cmpb $0x0, 0x3a34d(%rip)     # 0x402d4
jne 0x5faf
callq 0x4140
subq %rbx, %rax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
divsd 0x2e067(%rip), %xmm0    # 0x34008
leaq 0x2e16b(%rip), %rdi     # 0x34113
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 0x5ffb
jmp 0x5fd1
jmp 0x5fe5
movq %rax, %rbx
movl $0xa8, %esi
jmp 0x6003
movq %rax, %rbx
movl $0xd0, %esi
jmp 0x6003
movq %rax, %rbx
movl $0x98, %esi
jmp 0x6003
movq %rax, %rbx
movl $0x90, %esi
jmp 0x6003
jmp 0x5ffb
movq %rax, %rbx
movl $0xa0, %esi
movq %r15, %rdi
callq 0x4220
movq %rbx, %rdi
callq 0x4430