[mlpack-git] master: Add log chebyshev approx testcase (3b82ee0)
gitdub at big.cc.gt.atl.ga.us
gitdub at big.cc.gt.atl.ga.us
Thu Mar 5 22:12:56 EST 2015
Repository : https://github.com/mlpack/mlpack
On branch : master
Link : https://github.com/mlpack/mlpack/compare/904762495c039e345beba14c1142fd719b3bd50e...f94823c800ad6f7266995c700b1b630d5ffdcf40
>---------------------------------------------------------------
commit 3b82ee0e5306e777dcb1665381716c789fa19667
Author: Stephen Tu <tu.stephenl at gmail.com>
Date: Fri Jan 16 01:00:14 2015 -0800
Add log chebyshev approx testcase
>---------------------------------------------------------------
3b82ee0e5306e777dcb1665381716c789fa19667
src/mlpack/tests/sdp_primal_dual_test.cpp | 140 ++++++++++++++++++++++++++++++
1 file changed, 140 insertions(+)
diff --git a/src/mlpack/tests/sdp_primal_dual_test.cpp b/src/mlpack/tests/sdp_primal_dual_test.cpp
index 55053de..c4d7d3e 100644
--- a/src/mlpack/tests/sdp_primal_dual_test.cpp
+++ b/src/mlpack/tests/sdp_primal_dual_test.cpp
@@ -248,4 +248,144 @@ BOOST_AUTO_TEST_CASE(SmallLovaszThetaSdp)
BOOST_REQUIRE(p.first);
}
+static inline arma::sp_mat
+RepeatBlockDiag(const arma::sp_mat& block, size_t repeat)
+{
+ assert(block.n_rows == block.n_cols);
+ arma::sp_mat ret(block.n_rows * repeat, block.n_rows * repeat);
+ ret.zeros();
+ for (size_t i = 0; i < repeat; i++)
+ ret(arma::span(i * block.n_rows, (i + 1) * block.n_rows - 1),
+ arma::span(i * block.n_rows, (i + 1) * block.n_rows - 1)) = block;
+ return ret;
+}
+
+static inline arma::sp_mat
+BlockDiag(const std::vector<arma::sp_mat>& blocks)
+{
+ // assumes all blocks are the same size
+ const size_t n = blocks.front().n_rows;
+ assert(blocks.front().n_cols == n);
+ arma::sp_mat ret(n * blocks.size(), n * blocks.size());
+ ret.zeros();
+ for (size_t i = 0; i < blocks.size(); i++)
+ ret(arma::span(i * n, (i + 1) * n - 1),
+ arma::span(i * n, (i + 1) * n - 1)) = blocks[i];
+ return ret;
+}
+
+static inline SDP
+ConstructLogChebychevApproxSdp(const arma::mat& A, const arma::vec& b)
+{
+ if (A.n_rows != b.n_elem)
+ Log::Fatal << "A.n_rows != len(b)" << std::endl;
+ const size_t p = A.n_rows;
+ const size_t k = A.n_cols;
+
+ // [0, 0, 0]
+ // [0, 0, 1]
+ // [0, 1, 0]
+ arma::sp_mat cblock(3, 3);
+ cblock(1, 2) = cblock(2, 1) = 1.;
+ const arma::sp_mat C = RepeatBlockDiag(cblock, p);
+
+ SDP sdp(C.n_rows, k + 1, 0);
+ sdp.SparseC() = C;
+ sdp.SparseB().zeros();
+ sdp.SparseB()[0] = -1;
+
+ // [1, 0, 0]
+ // [0, 0, 0]
+ // [0, 0, 1]
+ arma::sp_mat a0block(3, 3);
+ a0block(0, 0) = a0block(2, 2) = 1.;
+ sdp.SparseA()[0] = RepeatBlockDiag(a0block, p);
+ sdp.SparseA()[0] *= -1.;
+
+ for (size_t i = 0; i < k; i++)
+ {
+ std::vector<arma::sp_mat> blocks;
+ for (size_t j = 0; j < p; j++)
+ {
+ arma::sp_mat block(3, 3);
+ const double f = A(j, i) / b(j);
+ // [ -a_j(i)/b_j 0 0 ]
+ // [ 0 a_j(i)/b_j 0 ]
+ // [ 0 0 0 ]
+ block(0, 0) = -f;
+ block(1, 1) = f;
+ blocks.emplace_back(block);
+ }
+ sdp.SparseA()[i + 1] = BlockDiag(blocks);
+ sdp.SparseA()[i + 1] *= -1;
+ }
+
+ return sdp;
+}
+
+static inline arma::mat
+RandomOrthogonalMatrix(size_t rows, size_t cols)
+{
+ arma::mat Q, R;
+ if (!arma::qr(Q, R, arma::randu<arma::mat>(rows, cols)))
+ Log::Fatal << "could not compute QR decomposition" << std::endl;
+ return Q;
+}
+
+static inline arma::mat
+RandomFullRowRankMatrix(size_t rows, size_t cols)
+{
+ const arma::mat U = RandomOrthogonalMatrix(rows, rows);
+ const arma::mat V = RandomOrthogonalMatrix(cols, cols);
+ arma::mat S;
+ S.zeros(rows, cols);
+ for (size_t i = 0; i < std::min(rows, cols); i++)
+ {
+ S(i, i) = math::Random() + 1e-3;
+ }
+ return U * S * V;
+}
+
+/**
+ * See the examples section, Eq. 9, of
+ *
+ * Semidefinite Programming.
+ * Lieven Vandenberghe and Stephen Boyd.
+ * SIAM Review. 1996.
+ *
+ * The logarithmic Chebychev approximation to Ax = b, A is p x k and b is
+ * length p is given by the SDP:
+ *
+ * min t
+ * s.t.
+ * [ t - dot(a_i, x) 0 0 ]
+ * [ 0 dot(a_i, x) / b_i 1 ] >= 0, i=1,...,p
+ * [ 0 1 t ]
+ *
+ */
+BOOST_AUTO_TEST_CASE(LogChebychevApproxSdp)
+{
+ const size_t p0 = 5;
+ const size_t k0 = 10;
+ const arma::mat A0 = RandomFullRowRankMatrix(p0, k0);
+ const arma::vec b0 = arma::randu<arma::vec>(p0);
+ const SDP sdp0 = ConstructLogChebychevApproxSdp(A0, b0);
+ PrimalDualSolver solver0(sdp0);
+ arma::mat X0, Z0;
+ arma::vec ysparse0, ydense0;
+ const auto stat0 = solver0.Optimize(X0, ysparse0, ydense0, Z0);
+ BOOST_REQUIRE(stat0.first);
+
+ const size_t p1 = 10;
+ const size_t k1 = 5;
+ const arma::mat A1 = RandomFullRowRankMatrix(p1, k1);
+ const arma::vec b1 = arma::randu<arma::vec>(p1);
+ const SDP sdp1 = ConstructLogChebychevApproxSdp(A1, b1);
+ PrimalDualSolver solver1(sdp1);
+ arma::mat X1, Z1;
+ arma::vec ysparse1, ydense1;
+ const auto stat1 = solver1.Optimize(X1, ysparse1, ydense1, Z1);
+ BOOST_REQUIRE(stat1.first);
+}
+
BOOST_AUTO_TEST_SUITE_END();
More information about the mlpack-git
mailing list