randomMatrices.h
Go to the documentation of this file.
1 /* Copyright 2020 CNRS-AIST JRL */
2 
3 #pragma once
4 
5 #include <Eigen/Core>
6 
7 #include <3rd-party/effolkronium/random.hpp>
8 
9 namespace jrl::qp::test
10 {
12 template<typename Scalar>
14 {
15  scalar_normal_random_op(double mean = 0, double stddev = 1) : d_(mean, stddev) {}
16 
17  inline const Scalar operator()() const
18  {
19  return effolkronium::random_static::get(d_);
20  }
21 
22  mutable std::normal_distribution<Scalar> d_;
23 };
24 
30 inline auto randnVec(Eigen::Index size, double mean = 0, double stddev = 1)
31 {
32  return Eigen::VectorXd::NullaryExpr(size, scalar_normal_random_op<double>(mean, stddev));
33 }
34 
41 inline auto randnMat(Eigen::Index rows, Eigen::Index cols, double mean = 0, double stddev = 1)
42 {
43  return Eigen::MatrixXd::NullaryExpr(rows, cols, scalar_normal_random_op<double>(mean, stddev));
44 }
45 
49 inline Eigen::VectorXd randUnitVec(Eigen::Index size)
50 {
51  Eigen::VectorXd r = randnVec(size);
52  r.normalize();
53  return r;
54 }
55 
62 inline Eigen::MatrixXd randOrtho(Eigen::Index size, bool special = false)
63 {
64  assert(size >= 0);
65  Eigen::VectorXd buffv(size);
66  Eigen::VectorXd buffw(size);
67  Eigen::MatrixXd Q = Eigen::MatrixXd::Identity(size, size);
68 
69  if(size == 0) return Q;
70 
71  bool positiveDet;
72  if(effolkronium::random_static::get<bool>())
73  {
74  Q(size - 1, size - 1) = 1;
75  positiveDet = true;
76  }
77  else
78  {
79  Q(size - 1, size - 1) = -1;
80  positiveDet = false;
81  }
82 
83  for(Eigen::Index i = 2; i <= size; ++i)
84  {
85  auto v = buffv.head(i);
86  auto w = buffw.head(i);
87 
88  // Random unit vector
89  v = randUnitVec(i);
90 
91  // compute (v+sgn(v_1)*e_1)/||v+sgn(v_1)*e_1||
92  bool positive = v[0] >= 0;
93  if(positive)
94  {
95  v[0] += 1;
96  if(i % 2 == 0) positiveDet = !positiveDet;
97  }
98  else
99  {
100  v[0] -= 1;
101  positiveDet = !positiveDet;
102  }
103  v.normalize();
104 
105  Eigen::MatrixXd H;
106  if(positive)
107  H = -(Eigen::MatrixXd::Identity(i, i) - 2 * v * v.transpose());
108  else
109  H = Eigen::MatrixXd::Identity(i, i) - 2 * v * v.transpose();
110  // Apply the Householder transformation H = -sgn(v_1)*(I-2*vv^T) : Q = H*Q
111  w = Q.bottomRightCorner(i, i).transpose() * v;
112  if(positive)
113  {
114  Q(size - i, size - i) = -1;
115  Q.bottomRightCorner(i - 1, i - 1) *= -1;
116  Q.bottomRightCorner(i, i).noalias() += 2 * v * w.transpose();
117  }
118  else
119  {
120  Q.bottomRightCorner(i, i).noalias() -= 2 * v * w.transpose();
121  }
122  }
123 
124  if(special && !positiveDet) Q.col(0) *= -1;
125 
126  return Q;
127 }
128 
149 inline Eigen::MatrixXd randn(Eigen::Index rows, Eigen::Index cols, Eigen::Index rank = -1)
150 {
151  assert(rank <= rows && rank <= cols && "Invalid rank");
152  Eigen::Index p = std::min(rows, cols);
153  if(rank < 0) rank = p;
154 
155  if(rank == 0) return Eigen::MatrixXd::Zero(rows, cols);
156 
157  if(rank == p) return randnMat(rows, cols);
158 
159  Eigen::VectorXd s = Eigen::VectorXd::Zero(p);
160  s.head(rank).setRandom();
161  // set the correct variance
162  s.head(rank) *= std::sqrt((3. * static_cast<double>(rows) * static_cast<double>(cols)) / static_cast<double>(rank));
163 
164  Eigen::MatrixXd M(rows, cols);
165 
166  if(rows <= cols)
167  {
168  M.leftCols(rows).noalias() = randOrtho(rows) * s.asDiagonal();
169  M.rightCols(cols - rows).setZero();
170  return M * randOrtho(cols);
171  }
172  else
173  {
174  M.topRows(cols).noalias() = s.asDiagonal() * randOrtho(cols);
175  M.bottomRows(rows - cols).setZero();
176  return randOrtho(rows) * M;
177  }
178 }
179 
189 inline std::pair<Eigen::MatrixXd, Eigen::MatrixXd> randDependent(Eigen::Index cols,
190  Eigen::Index rowsA,
191  Eigen::Index rankA,
192  Eigen::Index rowsB,
193  Eigen::Index rankB,
194  Eigen::Index rankAB)
195 {
196  assert(rankA <= rowsA && rankA <= cols);
197  assert(rankB <= rowsB && rankB <= cols);
198  assert(rankAB >= rankA && rankAB >= rankB && rankAB <= rankA + rankB && rankAB <= cols);
199 
200  Eigen::MatrixXd M = randn(rankA + rankB, cols, rankAB);
201  Eigen::MatrixXd A(rowsA, cols);
202  Eigen::MatrixXd B(rowsB, cols);
203 
204  if(rankA == rowsA)
205  A = M.topRows(rankA);
206  else
207  A.noalias() = randOrtho(rowsA).leftCols(rankA) * M.topRows(rankA);
208 
209  if(rankB == rowsB)
210  B = M.bottomRows(rankB);
211  else
212  B.noalias() = randOrtho(rowsB).leftCols(rankB) * M.bottomRows(rankB);
213 
214  return {A, B};
215 }
216 } // namespace jrl::qp::test
jrl::qp::test::scalar_normal_random_op
Definition: randomMatrices.h:13
jrl::qp::test::randn
Eigen::MatrixXd randn(Eigen::Index rows, Eigen::Index cols, Eigen::Index rank=-1)
Definition: randomMatrices.h:149
jrl::qp::test
Definition: BoxAndSingleConstraintSolver.h:36
jrl::qp::test::scalar_normal_random_op::operator()
const Scalar operator()() const
Definition: randomMatrices.h:17
jrl::qp::test::randnMat
auto randnMat(Eigen::Index rows, Eigen::Index cols, double mean=0, double stddev=1)
Definition: randomMatrices.h:41
jrl::qp::test::randOrtho
Eigen::MatrixXd randOrtho(Eigen::Index size, bool special=false)
Definition: randomMatrices.h:62
jrl::qp::test::scalar_normal_random_op::scalar_normal_random_op
scalar_normal_random_op(double mean=0, double stddev=1)
Definition: randomMatrices.h:15
jrl::qp::test::randnVec
auto randnVec(Eigen::Index size, double mean=0, double stddev=1)
Definition: randomMatrices.h:30
jrl::qp::test::randUnitVec
Eigen::VectorXd randUnitVec(Eigen::Index size)
Definition: randomMatrices.h:49
jrl::qp::test::scalar_normal_random_op::d_
std::normal_distribution< Scalar > d_
Definition: randomMatrices.h:22
jrl::qp::test::randDependent
std::pair< Eigen::MatrixXd, Eigen::MatrixXd > randDependent(Eigen::Index cols, Eigen::Index rowsA, Eigen::Index rankA, Eigen::Index rowsB, Eigen::Index rankB, Eigen::Index rankAB)
Definition: randomMatrices.h:189