1#ifndef ZONOOPT_SPARSEMATRIXUTILITIES_HPP_ 
    2#define ZONOOPT_SPARSEMATRIXUTILITIES_HPP_ 
   15#include <Eigen/Sparse> 
   18namespace ZonoOpt::detail
 
   22    Eigen::SparseMatrix<T> hcat(
const Eigen::SparseMatrix<T> &A, 
const Eigen::SparseMatrix<T> &B)
 
   24        if (A.rows() != B.rows())
 
   26            throw std::invalid_argument(
"hcat: number of rows must match.");
 
   29        Eigen::SparseMatrix<T> C(A.rows(), A.cols() + B.cols());
 
   30        std::vector<Eigen::Triplet<T>> tripvec;
 
   31        tripvec.reserve(A.nonZeros() + B.nonZeros());
 
   33        for (
int k=0; k<A.outerSize(); ++k)
 
   35            for (
typename Eigen::SparseMatrix<T>::InnerIterator it(A, k); it; ++it)
 
   37                tripvec.emplace_back(
static_cast<int>(it.row()), 
static_cast<int>(it.col()), it.value());
 
   41        for (
int k=0; k<B.outerSize(); ++k)
 
   43            for (
typename Eigen::SparseMatrix<T>::InnerIterator it(B, k); it; ++it)
 
   45                tripvec.emplace_back(
static_cast<int>(it.row()), 
static_cast<int>(it.col()+A.cols()), it.value());
 
   49        C.setFromTriplets(tripvec.begin(), tripvec.end());
 
   55    Eigen::SparseMatrix<T> vcat(
const Eigen::SparseMatrix<T> &A, 
const Eigen::SparseMatrix<T> &B)
 
   57        if (A.cols() != B.cols())
 
   59            throw std::invalid_argument(
"vcat: number of columns must match.");
 
   62        Eigen::SparseMatrix<T> C(A.rows() + B.rows(), A.cols());
 
   63        std::vector<Eigen::Triplet<T>> tripvec;
 
   64        tripvec.reserve(A.nonZeros() + B.nonZeros());
 
   66        for (
int k=0; k<A.outerSize(); ++k)
 
   68            for (
typename Eigen::SparseMatrix<T>::InnerIterator it(A, k); it; ++it)
 
   70                tripvec.emplace_back(
static_cast<int>(it.row()), 
static_cast<int>(it.col()), it.value());
 
   74        for (
int k=0; k<B.outerSize(); ++k)
 
   76            for (
typename Eigen::SparseMatrix<T>::InnerIterator it(B, k); it; ++it)
 
   78                tripvec.emplace_back(
static_cast<int>(it.row()+A.rows()), 
static_cast<int>(it.col()), it.value());
 
   82        C.setFromTriplets(tripvec.begin(), tripvec.end());
 
   88    void get_triplets_offset(
const Eigen::SparseMatrix<T> &mat, std::vector<Eigen::Triplet<T>> &triplets,
 
   89                const int i_offset, 
const int j_offset)
 
   92        if (i_offset < 0 || j_offset < 0)
 
   94            throw std::invalid_argument(
"get_triplets_offset: offsets must be non-negative.");
 
   98        for (
int k=0; k<mat.outerSize(); ++k)
 
  100            for (
typename Eigen::SparseMatrix<T>::InnerIterator it(mat, k); it; ++it)
 
  102                triplets.emplace_back(
static_cast<int>(it.row() + i_offset), 
static_cast<int>(it.col() + j_offset), it.value());
 
  108    template <
typename T>
 
  109    void remove_redundant_constraints(Eigen::SparseMatrix<T>& A, Eigen::Vector<T,-1>& b)
 
  112        if (A.rows() == 0 || A.cols() == 0)
 
  120        Eigen::SparseMatrix<T> At = A.transpose();
 
  123        Eigen::SparseQR<Eigen::SparseMatrix<T>, Eigen::COLAMDOrdering<int>> qr;
 
  124        qr.analyzePattern(At);
 
  128        Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic> P = qr.colsPermutation();
 
  129        Eigen::VectorXi P_indices = P.indices();
 
  132        std::vector<Eigen::Triplet<T>> tripvec;
 
  133        for (
int i=0; i<qr.rank(); i++)
 
  135            tripvec.emplace_back(P_indices(i), i, 
static_cast<T
>(1.0));
 
  138        Eigen::SparseMatrix<T> P_full (At.cols(), qr.rank());
 
  139        P_full.setFromTriplets(tripvec.begin(), tripvec.end());
 
  142        A = (At * P_full).transpose();
 
  143        b = (b.transpose() * P_full).transpose();
 
  147    template <
typename T>
 
  148    std::vector<Eigen::Triplet<T>> get_triplets_row(
const Eigen::SparseMatrix<T, Eigen::RowMajor> &mat, 
int row)
 
  150        std::vector<Eigen::Triplet<T>> triplets;
 
  151        if (row < 0 || row >= mat.rows())
 
  153            throw std::out_of_range(
"get_triplets_row: row index out of range.");
 
  156        for (
typename Eigen::SparseMatrix<T, Eigen::RowMajor>::InnerIterator it(mat, row); it; ++it)
 
  158            triplets.emplace_back(row, 
static_cast<int>(it.col()), it.value());
 
  164    template <
typename T>
 
  167        Eigen::SparseMatrix<T> R;
 
  168        Eigen::Vector<T, -1> b_tilde;
 
  169        Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic> P;
 
  172    template <
typename T>
 
  173    void QREqCons(
const Eigen::SparseMatrix<T>& A, 
const Eigen::Vector<T, -1>& b, QREqConsData<T>& data)
 
  175        Eigen::SparseQR<Eigen::SparseMatrix<T>, Eigen::COLAMDOrdering<int>> qr;
 
  177        data.R = qr.matrixR();
 
  178        data.b_tilde = qr.matrixQ().transpose()*b;
 
  179        data.P = qr.colsPermutation();