// Copyright 2015 Yutaro Konta #include "LambdaCalculator.hh" #include "cbrc_linalg.hh" #include #include #include #include //#include using namespace std; static bool calculate_inv_sum(double **matrix, int alpha_size, double tau, double* inv_sum, double **tmpMat, double *tmpVec) { for (int i=0; i r_max) r_max = matrix[i][j]; if (matrix[i][j] < r_min) r_min = matrix[i][j]; } if (r_max == 0 && r_min == 0) l_r++; else if (r_max <= 0 || r_min >= 0) return false; else if (r_max < r_max_min) r_max_min = r_max; } for (int j=0; j c_max) c_max = matrix[i][j]; if (matrix[i][j] < c_min) c_min = matrix[i][j]; } if (c_max == 0 && c_min == 0) l_c++; else if (c_max <= 0 || c_min >= 0) return false; else if (c_max < c_max_min) c_max_min = c_max; } if (l_r == alpha_size) return false; // the multiplication by 1.1 is sometimes necessary, presumably to // prevent the upper bound from being too tight: if (r_max_min > c_max_min) *ub = 1.1 * log(1.0 * (alpha_size - l_r))/r_max_min; else *ub = 1.1 * log(1.0 * (alpha_size - l_c))/c_max_min; return true; } bool LambdaCalculator::binary_search(double** matrix, int alpha_size, double lb, double ub, vector& letprob1, vector& letprob2, double* lambda, int maxiter) { double l=0; double r=0; double l_sum=0; double r_sum=0; int iter=0; std::vector tmpVals(alpha_size * alpha_size); std::vector tmpPtrs(alpha_size); for (int i = 0; i < alpha_size; ++i) tmpPtrs[i] = &tmpVals[i * alpha_size]; double **tmpMat = &tmpPtrs[0]; double *tmpVec = &letprob2[0]; while (iter < maxiter && (l>=r || (l_sum < 1.0 && r_sum < 1.0) || (l_sum > 1.0 && r_sum > 1.0))) { l = lb + (ub - lb)*rand()/RAND_MAX; r = lb + (ub - lb)*rand()/RAND_MAX; if (!calculate_inv_sum(matrix, alpha_size, l, &l_sum, tmpMat, tmpVec) || !calculate_inv_sum(matrix, alpha_size, r, &r_sum, tmpMat, tmpVec)) { l = 0; r = 0; } iter++; } if (iter >= maxiter) return false; while (l_sum != 1.0 && r_sum != 1.0 && (l+r)/2.0 != l && (l+r)/2.0 != r) { double mid = (l + r)/2.0; double mid_sum; if (!calculate_inv_sum(matrix, alpha_size, mid, &mid_sum, tmpMat, tmpVec)) return false; if (fabs(mid_sum) >= DBL_MAX) return false; if ((l_sum < 1.0 && mid_sum >= 1.0) || (l_sum > 1.0 && mid_sum <= 1.0)) { r = mid; r_sum = mid_sum; } else if ((r_sum < 1.0 && mid_sum >= 1.0) || (r_sum > 1.0 && mid_sum <= 1.0)) { l = mid; l_sum = mid_sum; } else return false; } if (fabs(l_sum - 1.0) < fabs(r_sum - 1.0)) { if (check_lambda(matrix, l, alpha_size, letprob1, letprob2, tmpMat)) { *lambda = l; return true; } return false; } if (check_lambda(matrix, r, alpha_size, letprob1, letprob2, tmpMat)) { *lambda = r; return true; } return false; } double LambdaCalculator::calculate_lambda(double** matrix, int alpha_size, vector& letprob1, vector& letprob2, int maxiter, int max_boundary_search_iter, double lb_ratio) { double ub; if (!find_ub(matrix, alpha_size, &ub)) return -1; double lb = ub*lb_ratio; double lambda = -1; int iter = 0; bool flag = false; while (!flag && iter < maxiter) { flag = binary_search(matrix, alpha_size, lb, ub, letprob1, letprob2, &lambda, max_boundary_search_iter); iter++; } return lambda; } bool LambdaCalculator::check_lambda(double** matrix, double lambda, int alpha_size, vector& letprob1, vector& letprob2, double** tmpMat) { for (int i=0; i 1) return false; letprob2[i] = roundToFewDigits(p); } for (int i=0; i 1) return false; letprob1[j] = roundToFewDigits(q); } return true; } void LambdaCalculator::calculate(const const_int_ptr *matrix, int alphSize) { assert(alphSize >= 0); lambda_ = -1; letterProbs1_.resize(alphSize); letterProbs2_.resize(alphSize); int maxiter = 1000; int max_boundary_search_iter = 100; double lb_ratio = 1e-6; std::vector matVals(alphSize * alphSize); std::vector matPtrs(alphSize); for (int i = 0; i < alphSize; ++i) matPtrs[i] = &matVals[i * alphSize]; double** mat = &matPtrs[0]; for (int i=0; i