#include "util/HighsMatrixUtils.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include "util/HighsHash.h"
HighsStatus assessMatrix(const HighsLogOptions& log_options,
const std::string& matrix_name, const HighsInt vec_dim,
const HighsInt num_vec, vector<HighsInt>& matrix_start,
vector<HighsInt>& matrix_index,
vector<double>& matrix_value,
const double small_matrix_value,
const double large_matrix_value) {
vector<HighsInt> matrix_p_end;
const bool partitioned = false;
return assessMatrix(log_options, matrix_name, vec_dim, num_vec, partitioned,
matrix_start, matrix_p_end, matrix_index, matrix_value,
small_matrix_value, large_matrix_value);
}
HighsStatus assessMatrix(const HighsLogOptions& log_options,
const std::string& matrix_name, const HighsInt vec_dim,
const HighsInt num_vec, vector<HighsInt>& matrix_start,
vector<HighsInt>& matrix_p_end,
vector<HighsInt>& matrix_index,
vector<double>& matrix_value,
const double small_matrix_value,
const double large_matrix_value) {
const bool partitioned = false;
return assessMatrix(log_options, matrix_name, vec_dim, num_vec, partitioned,
matrix_start, matrix_p_end, matrix_index, matrix_value,
small_matrix_value, large_matrix_value);
}
HighsStatus assessMatrix(
const HighsLogOptions& log_options, const std::string& matrix_name,
const HighsInt vec_dim, const HighsInt num_vec, const bool partitioned,
vector<HighsInt>& matrix_start, vector<HighsInt>& matrix_p_end,
vector<HighsInt>& matrix_index, vector<double>& matrix_value,
const double small_matrix_value, const double large_matrix_value) {
if (assessMatrixDimensions(log_options, num_vec, partitioned, matrix_start,
matrix_p_end, matrix_index,
matrix_value) == HighsStatus::kError) {
return HighsStatus::kError;
}
bool error_found = false;
bool warning_found = false;
const HighsInt num_nz = matrix_start[num_vec];
if (matrix_start[0]) {
highsLogUser(log_options, HighsLogType::kError,
"%s matrix start vector begins with %" HIGHSINT_FORMAT
" rather than 0\n",
matrix_name.c_str(), matrix_start[0]);
return HighsStatus::kError;
}
HighsInt previous_start = matrix_start[0];
HighsInt this_start = matrix_start[0];
HighsInt this_p_end = 0;
if (partitioned) this_p_end = matrix_p_end[0];
for (HighsInt ix = 0; ix < num_vec; ix++) {
this_start = matrix_start[ix];
bool this_start_too_small = this_start < previous_start;
if (this_start_too_small) {
highsLogUser(log_options, HighsLogType::kError,
"%s matrix packed vector %" HIGHSINT_FORMAT
" has illegal start of %" HIGHSINT_FORMAT
" < %" HIGHSINT_FORMAT
" = "
"previous start\n",
matrix_name.c_str(), ix, this_start, previous_start);
return HighsStatus::kError;
}
if (partitioned) {
this_p_end = matrix_p_end[ix];
bool this_p_end_too_small = this_p_end < this_start;
if (this_p_end_too_small) {
highsLogUser(log_options, HighsLogType::kError,
"%s matrix packed vector %" HIGHSINT_FORMAT
" has illegal partition end of %" HIGHSINT_FORMAT
" < %" HIGHSINT_FORMAT
" = "
" start\n",
matrix_name.c_str(), ix, this_p_end, this_start);
return HighsStatus::kError;
}
}
previous_start = this_start;
}
bool this_start_too_big = this_start > num_nz;
if (this_start_too_big) {
highsLogUser(log_options, HighsLogType::kError,
"%s matrix packed vector %" HIGHSINT_FORMAT
" has illegal start of %" HIGHSINT_FORMAT
" > %" HIGHSINT_FORMAT
" = "
"number of nonzeros\n",
matrix_name.c_str(), num_vec, this_start, num_nz);
return HighsStatus::kError;
}
if (partitioned) {
bool this_p_end_too_big = this_p_end > num_nz;
if (this_p_end_too_big) {
highsLogUser(log_options, HighsLogType::kError,
"%s matrix packed vector %" HIGHSINT_FORMAT
" has illegal partition end of %" HIGHSINT_FORMAT
" > %" HIGHSINT_FORMAT
" = "
"number of nonzeros\n",
matrix_name.c_str(), num_vec, this_p_end, num_nz);
return HighsStatus::kError;
}
}
HighsInt num_new_nz = 0;
HighsInt num_small_values = 0;
double max_small_value = 0;
double min_small_value = kHighsInf;
HighsInt num_large_values = 0;
double max_large_value = 0;
double min_large_value = kHighsInf;
HighsHashTable<HighsInt> index_set;
for (HighsInt ix = 0; ix < num_vec; ix++) {
HighsInt from_el = matrix_start[ix];
HighsInt to_el = matrix_start[ix + 1];
matrix_start[ix] = num_new_nz;
for (HighsInt el = from_el; el < to_el; el++) {
HighsInt component = matrix_index[el];
bool legal_component = component >= 0;
if (!legal_component) {
highsLogUser(log_options, HighsLogType::kError,
"%s matrix packed vector %" HIGHSINT_FORMAT
", entry %" HIGHSINT_FORMAT
", is illegal index %" HIGHSINT_FORMAT "\n",
matrix_name.c_str(), ix, el, component);
return HighsStatus::kError;
}
legal_component = component < vec_dim;
if (!legal_component) {
highsLogUser(log_options, HighsLogType::kError,
"%s matrix packed vector %" HIGHSINT_FORMAT
", entry %" HIGHSINT_FORMAT
", is illegal index "
"%12" HIGHSINT_FORMAT " >= %" HIGHSINT_FORMAT
" = vector dimension\n",
matrix_name.c_str(), ix, el, component, vec_dim);
return HighsStatus::kError;
}
legal_component = index_set.find(component) == nullptr;
if (!legal_component) {
highsLogUser(log_options, HighsLogType::kError,
"%s matrix packed vector %" HIGHSINT_FORMAT
", entry %" HIGHSINT_FORMAT
", is duplicate index %" HIGHSINT_FORMAT "\n",
matrix_name.c_str(), ix, el, component);
return HighsStatus::kError;
}
double abs_value = fabs(matrix_value[el]);
bool large_value = abs_value >= large_matrix_value;
if (large_value) {
if (max_large_value < abs_value) max_large_value = abs_value;
if (min_large_value > abs_value) min_large_value = abs_value;
num_large_values++;
}
bool ok_value = abs_value > small_matrix_value;
if (!ok_value) {
if (max_small_value < abs_value) max_small_value = abs_value;
if (min_small_value > abs_value) min_small_value = abs_value;
num_small_values++;
}
if (ok_value) {
index_set.insert(component);
matrix_index[num_new_nz] = matrix_index[el];
matrix_value[num_new_nz] = matrix_value[el];
num_new_nz++;
}
} index_set.clear();
} if (num_large_values) {
highsLogUser(log_options, HighsLogType::kError,
"%s matrix packed vector contains %" HIGHSINT_FORMAT
" |values| in [%g, %g] greater than %g\n",
matrix_name.c_str(), num_large_values, min_large_value,
max_large_value, large_matrix_value);
error_found = true;
}
if (num_small_values) {
if (partitioned) {
highsLogUser(
log_options, HighsLogType::kError,
"%s matrix packed partitioned vector contains %" HIGHSINT_FORMAT
" |values| in [%g, %g] less than or equal to %g: ignored\n",
matrix_name.c_str(), num_small_values, min_small_value,
max_small_value, small_matrix_value);
error_found = true;
assert(num_small_values == 0);
}
if (max_small_value > 0) {
highsLogUser(log_options, HighsLogType::kWarning,
"%s matrix packed vector contains %" HIGHSINT_FORMAT
" |values| in [%g, %g] "
"less than or equal to %g: ignored\n",
matrix_name.c_str(), num_small_values, min_small_value,
max_small_value, small_matrix_value);
warning_found = true;
}
}
matrix_start[num_vec] = num_new_nz;
HighsStatus return_status = HighsStatus::kOk;
if (error_found)
return_status = HighsStatus::kError;
else if (warning_found)
return_status = HighsStatus::kWarning;
return return_status;
}
HighsStatus assessMatrixDimensions(const HighsLogOptions& log_options,
const HighsInt num_vec,
const bool partitioned,
const vector<HighsInt>& matrix_start,
const vector<HighsInt>& matrix_p_end,
const vector<HighsInt>& matrix_index,
const vector<double>& matrix_value) {
bool ok = true;
const bool legal_num_vec = num_vec >= 0;
if (!legal_num_vec)
highsLogUser(
log_options, HighsLogType::kError,
"Matrix dimension validation fails on number of vectors = %d < 0\n",
(int)num_vec);
ok = legal_num_vec && ok;
const bool legal_matrix_start_size =
(HighsInt)matrix_start.size() >= num_vec + 1;
if (!legal_matrix_start_size) {
highsLogUser(log_options, HighsLogType::kError,
"Matrix dimension validation fails on start size = %d < %d = "
"num vectors + 1\n",
(int)matrix_start.size(), (int)(num_vec + 1));
}
ok = legal_matrix_start_size && ok;
if (partitioned) {
const bool legal_matrix_p_end_size =
(HighsInt)matrix_p_end.size() >= num_vec + 1;
if (!legal_matrix_p_end_size)
highsLogUser(log_options, HighsLogType::kError,
"Matrix dimension validation fails on p_end size = %d < %d "
"= num vectors + 1\n",
(int)matrix_p_end.size(), (int)(num_vec + 1));
ok = (HighsInt)matrix_p_end.size() >= num_vec + 1 && ok;
}
const HighsInt num_nz = legal_matrix_start_size ? matrix_start[num_vec] : 0;
if (num_nz >= 0) {
const bool legal_matrix_index_size =
(HighsInt)matrix_index.size() >= num_nz;
if (!legal_matrix_index_size)
highsLogUser(log_options, HighsLogType::kError,
"Matrix dimension validation fails on index size = %d < %d "
"= number of nonzeros\n",
(int)matrix_index.size(), (int)num_nz);
ok = legal_matrix_index_size && ok;
const bool legal_matrix_value_size =
(HighsInt)matrix_value.size() >= num_nz;
if (!legal_matrix_value_size)
highsLogUser(log_options, HighsLogType::kError,
"Matrix dimension validation fails on value size = %d < %d "
"= number of nonzeros\n",
(int)matrix_value.size(), (int)num_nz);
ok = legal_matrix_value_size && ok;
} else {
highsLogUser(
log_options, HighsLogType::kError,
"Matrix dimension validation fails on number of nonzeros = %d < 0\n",
(int)num_nz);
ok = false;
}
if (ok) return HighsStatus::kOk;
return HighsStatus::kError;
}