Program Listing for File utils.cpp
↰ Return to documentation for file (src/support/utils.cpp
)
/* #############################################
* This file is part of
* ZERO
*
* Copyright (c) 2020
* Released under the Creative Commons
* CC BY-NC-SA 4.0 License
*
* Find out more at
* https://github.com/ds4dm/ZERO
* #############################################*/
#include "support/utils.h"
#include <armadillo>
arma::sp_mat
Utils::resizePatch(const arma::sp_mat &mat, const unsigned int nR, const unsigned int nC) {
arma::sp_mat mMat(nR, nC);
mMat.zeros();
if (nR >= mat.n_rows && nC >= mat.n_cols) {
if (mat.n_rows >= 1 && mat.n_cols >= 1)
mMat.submat(0, 0, mat.n_rows - 1, mat.n_cols - 1) = mat;
} else {
if (nR <= mat.n_rows && nC <= mat.n_cols)
mMat = mat.submat(0, 0, nR, nC);
else
throw ZEROException(ZEROErrorCode::OutOfRange,
"Either both dimension should be smaller or larger.");
}
return mMat;
}
arma::mat Utils::resizePatch(const arma::mat &mat, const unsigned int nR, const unsigned int nC) {
arma::mat mMat(nR, nC);
mMat.zeros();
if (nR >= mat.n_rows && nC >= mat.n_cols) {
if (mat.n_rows >= 1 && mat.n_cols >= 1)
mMat.submat(0, 0, mat.n_rows - 1, mat.n_cols - 1) = mat;
} else {
if (nR <= mat.n_rows && nC <= mat.n_cols)
mMat = mat.submat(0, 0, nR, nC);
else
throw ZEROException(ZEROErrorCode::OutOfRange,
"Either both dimension should be smaller or larger.");
}
return mMat;
}
arma::vec Utils::resizePatch(const arma::vec &mat, const unsigned int nR) {
arma::vec mMat(nR);
mMat.zeros();
if (mat.n_rows > 0) {
if (nR > mat.n_rows)
mMat.subvec(0, mat.n_rows - 1) = mat;
else
mMat = mat.subvec(0, nR - 1);
}
return mMat;
}
void Utils::appendSave(const arma::sp_mat &matrix,
const std::string &out,
const std::string &header,
bool erase) {
unsigned int nR{0}, nC{0}, nnz{0};
std::ofstream outfile(out, erase ? std::ios::out : std::ios::app);
nR = matrix.n_rows;
nC = matrix.n_cols;
nnz = matrix.n_nonzero;
outfile << header << "\n";
outfile << nR << "\t" << nC << "\t" << nnz << "\n";
for (auto it = matrix.begin(); it != matrix.end(); ++it)
outfile << it.row() << "\t" << it.col() << "\t" << (*it)
<< "\n"; // Write the required information of arma::sp_mat
outfile << "\n";
outfile.close(); // and close it
}
long int Utils::appendRead(arma::sp_mat &matrix,
const std::string &in,
long int pos,
const std::string &header) {
unsigned int nR = 0, nC = 0, nnz = 0;
std::ifstream infile(in, std::ios::in);
infile.seekg(pos);
std::string headerCheckwith;
infile >> headerCheckwith;
if (!header.empty() && header != headerCheckwith)
throw ZEROException(ZEROErrorCode::InvalidData,
"Wrong header. Expected " + header + " found " + headerCheckwith);
infile >> nR >> nC >> nnz;
if (nR == 0 || nC == 0)
matrix.set_size(nR, nC);
else {
arma::umat locations(2, nnz);
arma::vec values(nnz);
unsigned int r = 0, c = 0;
double val = 0;
for (unsigned int i = 0; i < nnz; ++i) {
infile >> r >> c >> val;
locations(0, i) = r;
locations(1, i) = c;
values(i) = val;
}
matrix = arma::sp_mat(locations, values, nR, nC);
}
pos = infile.tellg();
infile.close();
return pos;
}
void appendSave(const std::vector<double> &v,
const std::string &out,
const std::string &header,
bool erase) {
std::ofstream outfile(out, erase ? std::ios::out : std::ios::app);
outfile << header << "\n" << v.size() << "\n";
for (const double x : v)
outfile << x << "\n";
outfile.close();
}
long int
appendRead(std::vector<double> &v, const std::string &in, long int pos, const std::string &header) {
unsigned long int size = 0;
std::ifstream infile(in, std::ios::in);
infile.seekg(pos);
std::string headerCheckwith;
infile >> headerCheckwith;
if (!header.empty() && header != headerCheckwith)
throw ZEROException(ZEROErrorCode::InvalidData,
"Wrong header. Expected " + header + " found " + headerCheckwith);
infile >> size;
v.resize(size);
for (unsigned int i = 0; i < size; ++i)
infile >> v[i];
pos = infile.tellg();
infile.close();
return pos;
}
void Utils::appendSave(const arma::vec &matrix,
const std::string &out,
const std::string &header,
bool erase) {
unsigned int nR{0};
std::ofstream outfile(out, erase ? std::ios::out : std::ios::app);
nR = matrix.n_rows;
outfile << header << "\n";
outfile << nR << "\n";
for (double it : matrix)
outfile << it << "\n"; // Write the required information of arma::sp_mat
outfile << "\n";
outfile.close(); // and close it
}
long int Utils::appendRead(arma::vec &matrix,
const std::string &in,
long int pos,
const std::string &header) {
unsigned int nR;
std::string buffers;
std::string checkwith;
std::ifstream inFile(in, std::ios::in);
inFile.seekg(pos);
inFile >> checkwith;
if (!header.empty() && checkwith != header)
throw ZEROException(ZEROErrorCode::InvalidData,
"Wrong header. Expected " + header + " found " + checkwith);
inFile >> nR;
matrix.zeros(nR);
for (unsigned int i = 0; i < nR; ++i) {
double val;
inFile >> val;
matrix.at(i) = val;
}
pos = inFile.tellg();
inFile.close();
return pos;
}
void Utils::appendSave(const long int v,
const std::string &out,
const std::string &header,
bool erase)
{
std::ofstream outfile(out, erase ? std::ios::out : std::ios::app);
outfile << header << "\n";
outfile << v << "\n";
outfile.close();
}
long int
Utils::appendRead(long int &v, const std::string &in, long int pos, const std::string &header) {
std::ifstream infile(in, std::ios::in);
infile.seekg(pos);
std::string headerCheckwith;
infile >> headerCheckwith;
if (!header.empty() && header != headerCheckwith)
throw ZEROException(ZEROErrorCode::InvalidData,
"Wrong header. Expected " + header + " found " + headerCheckwith);
long int val;
infile >> val;
v = val;
pos = infile.tellg();
infile.close();
return pos;
}
void Utils::appendSave(const unsigned int v,
const std::string &out,
const std::string &header,
bool erase) {
std::ofstream outfile(out, erase ? std::ios::out : std::ios::app);
outfile << header << "\n";
outfile << v << "\n";
outfile.close();
}
long int
Utils::appendRead(unsigned int &v, const std::string &in, long int pos, const std::string &header) {
std::ifstream infile(in, std::ios::in);
infile.seekg(pos);
std::string headerCheckwith;
infile >> headerCheckwith;
if (!header.empty() && header != headerCheckwith)
throw ZEROException(ZEROErrorCode::InvalidData,
"Wrong header. Expected " + header + " found " + headerCheckwith);
unsigned int val;
infile >> val;
v = val;
pos = infile.tellg();
infile.close();
return pos;
}
void Utils::appendSave(const std::string &v, const std::string &out, bool erase) {
std::ofstream outfile(out, erase ? std::ios::out : std::ios::app);
outfile << v << "\n";
outfile.close();
}
long int Utils::appendRead(std::string &v, const std::string &in, long int pos) {
std::ifstream infile(in, std::ios::in);
infile.seekg(pos);
std::string val;
infile >> val;
v = val;
pos = infile.tellg();
infile.close();
return pos;
}
bool Utils::containsConstraint(const arma::sp_mat &A,
const arma::vec &b,
const arma::vec &lhs,
const double &rhs,
const double tol) {
if (lhs.size() != A.n_cols)
return false;
for (int i = 0; i < A.n_rows; ++i) {
bool res = true;
// The RHS is good
if (Utils::isEqual(b.at(i), rhs, tol)) {
// Okay. Let's check the cut
bool res = true;
for (int j = 0; j < A.n_cols; ++j) {
if (!Utils::isEqual(lhs.at(j), A.at(i, j), tol)) {
// Not equal
res = false;
break;
}
}
if (res)
return true;
}
}
return false;
}
bool Utils::containsElement(const arma::vec &b, const double &element, const double tol) {
for (unsigned int i = 0; i < b.size(); ++i) {
if (Utils::isEqual(b.at(i), element, tol))
return true;
}
return false;
}
bool Utils::containsRow(const arma::sp_mat &A, const arma::vec &row, const double tol) {
if (row.size() != A.n_cols)
return false;
for (int i = 0; i < A.n_rows; ++i) {
bool res = true;
for (int j = 0; j < A.n_cols; ++j) {
if (!Utils::isEqual(row.at(j), A.at(i, j), tol)) {
res = false;
break;
}
}
if (res)
return true;
}
return false;
}
bool Utils::containsConstraint(const arma::sp_mat &A,
const arma::vec &b,
const arma::sp_mat &lhs,
const double &rhs,
const double tol) {
if (lhs.n_rows > 1)
return false;
arma::vec Ai = arma::vec{lhs};
return Utils::containsConstraint(A, b, Ai, rhs, tol);
}
bool Utils::isZero(const arma::mat &M, double tol) noexcept {
return (Utils::isEqual(abs(M).max(), 0, tol));
}
bool Utils::isZero(const arma::sp_mat &M, double tol) noexcept {
if (M.n_nonzero != 0)
return false;
return (Utils::isEqual(abs(M).max(), 0, tol));
}
void Utils::sortByKey(perps &set) {
sort(set.begin(),
set.end(),
[](std::pair<unsigned int, unsigned int> a, std::pair<unsigned int, unsigned int> b) {
return a.first < b.first;
});
}
VariableBounds Utils::intersectBounds(const VariableBounds &bA, const VariableBounds &bB) {
auto longest = bA.size() >= bB.size() ? bA : bB;
auto shortest = bA.size() >= bB.size() ? bB : bA;
// Set the size of the longest
VariableBounds bC(longest.size());
for (unsigned int i = 0; i < shortest.size(); ++i) {
// Lower bound. The higher, the better
if (bA.at(i).first >= 0 || bB.at(i).first >= 0)
bC.at(i).first = bA.at(i).first > bB.at(i).first ? bA.at(i).first : bB.at(i).first;
else
bC.at(i).first = 0;
// Upper bound. The lower, the better
if (bA.at(i).second < 0 && bB.at(i).second)
bC.at(i).second = -1;
else {
if (bA.at(i).second >= 0)
bC.at(i).second = bA.at(i).second;
else
bC.at(i).second = bB.at(i).second;
}
}
// Fill remaining element
for (unsigned int i = shortest.size(); i < longest.size(); ++i) {
bC.at(i).first = longest.at(i).first;
bC.at(i).second = longest.at(i).second;
}
return bC;
}
std::string Utils::printBounds(const VariableBounds &bounds) {
std::stringstream r;
for (unsigned int i = 0; i < bounds.size(); ++i) {
r << "var_" << std::to_string(i) << "\t\t\t[" << std::to_string(bounds.at(i).first) << ","
<< std::to_string(bounds.at(i).second) << "]\n";
}
return r.str();
}
double Utils::round_nplaces(const double &value, const int &numDecimals) {
return roundf(value * pow(10, numDecimals)) / pow(10, numDecimals);
}
arma::vec Utils::normalizeVec(const arma::vec &v) {
double norm = arma::max(arma::abs(v));
if (Utils::isEqual(norm, 0, 1e-6))
norm = 1;
return v / arma::max(arma::abs(v));
}
void Utils::normalizeIneq(arma::vec &lhs, double &rhs, bool force) {
// lhs.print("Input with RHS="+std::to_string(rhs));
arma::vec abs = arma::abs(lhs);
double norm = abs.max();
for (auto &elem : abs) {
if (std::abs(elem) < norm && elem != 0)
norm = std::abs(elem);
}
double ratio = abs.max() / norm;
if ((ratio > 1e2) || force) {
LOG_S(5) << "Utils::normalizeIneq: normalizing inequality.";
// Force this for very bad inequalities with too much of range...
if (ratio > 1e2)
norm = abs.max();
assert(norm != 0);
rhs = rhs / norm;
lhs = lhs / norm;
}
// lhs.print("Normalized with RHS="+std::to_string(rhs));
}
CoinPackedMatrix Utils::armaToCoinSparse(const arma::sp_mat &A) {
CoinPackedMatrix R = CoinPackedMatrix(true, A.n_cols, 0);
auto nnz = A.n_nonzero;
std::vector<CoinPackedVector> cols(A.n_cols);
for (arma::sp_mat::const_iterator it = A.begin(); it != A.end(); ++it)
cols.at(it.col()).insert(it.row(), *it);
for (unsigned int i = 0; i < A.n_cols; ++i)
R.appendCol(cols.at(i));
assert(A.n_rows == R.getNumRows() && A.n_cols == R.getNumCols());
return R;
}
arma::sp_mat Utils::clearMatrix(const arma::sp_mat &A, double tol, double percent) {
arma::sp_mat ACopy = A;
for (arma::sp_mat::const_iterator it = A.begin(); it != A.end(); ++it) {
if (Utils::isEqual(*it, 0, tol, percent))
ACopy.at(it.row(), it.col()) = 0;
}
return ACopy;
}
arma::vec Utils::clearVector(const arma::vec &b, double tol, double percent) {
arma::vec bCopy = b;
for (unsigned int i = 0; i < bCopy.size(); ++i) {
if (Utils::isEqual(b.at(i), 0, tol, percent))
bCopy.at(i) = 0;
}
return bCopy;
}
std::vector<CoinPackedVector> Utils::armaToCoinPackedVector(const arma::sp_mat &A) {
std::vector<CoinPackedVector> vectors(A.n_rows);
for (arma::sp_mat::const_iterator it = A.begin(); it != A.end(); ++it)
vectors.at(it.row()).insert(it.col(), *it);
return vectors;
}
void Utils::addSparseConstraints(const arma::sp_mat &A,
const arma::vec &b,
GRBVar *x,
const std::string &basename,
GRBModel *model,
int sense = GRB_LESS_EQUAL,
GRBVar *z = nullptr) {
std::vector<GRBLinExpr> Constraints(A.n_rows, 0);
for (arma::sp_mat::const_iterator it = A.begin(); it != A.end(); ++it) {
double coeff = *it;
Constraints.at(it.row()).addTerms(&coeff, &x[it.col()], 1);
}
if (z != nullptr) {
for (unsigned int i = 0; i < A.n_rows; ++i) {
model->addConstr(Constraints.at(i) - z[i], sense, b(i), basename + "_" + std::to_string(i));
}
} else {
for (unsigned int i = 0; i < A.n_rows; ++i) {
model->addConstr(Constraints.at(i), sense, b(i), basename + "_" + std::to_string(i));
}
}
}
int Utils::vecToBin(const arma::vec &x) {
int output = 0;
int power = 1;
int len = x.size();
for (int i = 0; i < len; i++) {
output += x.at(len - 1 - i) * power;
power *= 2;
}
return output;
}
int Utils::nonzeroDecimals(const double num, const int decimalBound) {
double integral = 0;
// Take the fractional
modf(num, &integral);
double fractional = num - integral;
int count = 0;
for (unsigned int i = 0; i < decimalBound; ++i) {
fractional *= 10;
if (static_cast<long>(fractional) % 10 != 0)
++count;
}
return count;
}
bool Utils::isEqualAbs(const double a, const double b, const double tol) {
float diff = fabs(a - b);
if (diff <= tol)
return true;
else
return false;
}
bool Utils::isEqualRel(const double a, const double b, const double percent) {
float diff = fabs(a - b);
double A = fabs(a);
double B = fabs(b);
float largest = (B > A) ? B : A;
if (diff <= largest * (1 - percent))
return true;
else
return false;
}
bool Utils::isEqual(const double a, const double b, const double tol, const double percent) {
if (Utils::isEqualAbs(a, b, tol)) {
return true;
} else if (Utils::isEqualRel(a, b, percent)) {
return true;
}
return false;
}
int Utils::getSign(double val) { return val >= 0 ? 1 : -1; }