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();