// TODO implement error handling void row_echolon_form(index_type start) { if (start == std::min(rows, cols)) return; index_type not_found = n_pos; // sort the rows so that the row with the first leading // pivot element is the top row std::sort(data.begin(), data.end(), [not_found](const std::array<double, m> &row_one, const std::array<double, m> &row_two){ return find_pivot(row_one, not_found) < find_pivot(row_two, not_found); }); // get pivot for first row index_type pivot = find_pivot(start); for (index_type i = start + 1; i < rows; i++) { index_type curr_pivot = find_pivot(i); // if there's no pivot element in this row then there will be no // pivot element in this column in some row later on, because the rows // have been sorted by the position of the row's pivot element. if (curr_pivot != pivot) break; // pivot * x = -curr_pivot; | / pivot // x = - curr_pivot / pivot; scale_and_add(start, i, -(data[i][curr_pivot] / data[start][pivot])); } row_echolon_form(start + 1); }
int QUERN_solve_with_CGNR(int m, int n, const int* A_row_start, const int* A_column_index, const double* A_value, const double* rhs, const int* R_row_start, const int* R_column_index, const double* R_value, int max_iterations, double absolute_convergence_tolerance, double* x, int* return_solved, int* return_iterations, double* return_residual_norm) { if(m<=0 || n<=0 || !A_row_start || !A_column_index || !A_value || !rhs || !R_row_start || !R_column_index || !R_value || !x || !return_solved || !return_iterations || !return_residual_norm) return QUERN_INPUT_ERROR; // default values *return_solved=0; *return_iterations=0; *return_residual_norm=two_norm(n, rhs); if(*return_residual_norm<=absolute_convergence_tolerance){ *return_solved=1; return QUERN_OK; } // allocate some room to work in double* working_vectors=(double*)std::malloc((3*n+m)*sizeof(double)); if(!working_vectors) return QUERN_OUT_OF_MEMORY; double* r=working_vectors; double* s=r+n; double* z=s+n; double* u=z+n; // set up CGNR int check; std::memset(x, 0, n*sizeof(double)); std::memcpy(r, rhs, n*sizeof(double)); std::memcpy(u, rhs, n*sizeof(double)); check=QUERN_solve_with_r_transpose_in_place(n, R_row_start, R_column_index, R_value, u); if(check){ std::free(working_vectors); return check; } check=QUERN_solve_with_r(n, R_row_start, R_column_index, R_value, u, z); if(check){ std::free(working_vectors); return check; } std::memcpy(s, z, n*sizeof(double)); double rho=two_norm_squared(n, u); // the main loop for(;;){ if(rho==0){ std::free(working_vectors); return QUERN_INPUT_ERROR; } check=QUERN_multiply(m, n, A_row_start, A_column_index, A_value, s, u); if(check){ std::free(working_vectors); return check; } check=QUERN_multiply_transpose(m, n, A_row_start, A_column_index, A_value, u, z); if(check){ std::free(working_vectors); return check; } double denom=two_norm_squared(m, u); if(denom==0){ std::free(working_vectors); return QUERN_INPUT_ERROR; } double alpha=rho/denom; add_scaled(n, x, alpha, s); add_scaled(n, r, -alpha, z); ++*return_iterations; *return_residual_norm=two_norm(n, r); if(*return_residual_norm<=absolute_convergence_tolerance){ *return_solved=1; break; } if(*return_iterations>max_iterations) break; std::memcpy(u, r, n*sizeof(double)); check=QUERN_solve_with_r_transpose_in_place(n, R_row_start, R_column_index, R_value, u); if(check){ std::free(working_vectors); return check; } check=QUERN_solve_with_r(n, R_row_start, R_column_index, R_value, u, z); if(check){ std::free(working_vectors); return check; } double rho_new=two_norm_squared(n, u); double beta=rho_new/rho; scale_and_add(n, beta, s, z); rho=rho_new; } std::free(working_vectors); return QUERN_OK; }