1 /**
2  * @file sdp.hpp
3  * @author Stephen Tu
4  *
5  *
6  * ensmallen is free software; you may redistribute it and/or modify it under
7  * the terms of the 3-clause BSD license.  You should have received a copy of
8  * the 3-clause BSD license along with ensmallen.  If not, see
9  * http://www.opensource.org/licenses/BSD-3-Clause for more information.
10  */
11 #ifndef ENSMALLEN_SDP_SDP_HPP
12 #define ENSMALLEN_SDP_SDP_HPP
13 
14 namespace ens {
15 
16 /**
17  * Specify an SDP in primal form
18  *
19  *     min    dot(C, X)
20  *     s.t.   dot(Ai, X) = bi, i=1,...,m, X >= 0
21  *
22  * This representation allows the constraint matrices Ai to be specified as
23  * either dense matrices (arma::mat) or sparse matrices (arma::sp_mat).  After
24  * initializing the SDP object, you will need to set the constraints yourself,
25  * via the SparseA(), SparseB(), DenseA(), DenseB(), and C() functions.  Note
26  * that for each matrix you add to either SparseA() or DenseA(), you must add
27  * the corresponding b value to the corresponding vector SparseB() or DenseB().
28  *
29  * The objective matrix (C) may be stored as either dense or sparse depending on
30  * the ObjectiveMatrixType parameter.
31  *
32  * @tparam ObjectiveMatrixType Should be either arma::mat or arma::sp_mat.
33  */
34 template<typename ObjectiveMatrixType,
35          typename DenseConstraintMatrixType =
36              arma::Mat<typename ObjectiveMatrixType::elem_type>,
37          typename SparseConstraintMatrixType =
38              arma::SpMat<typename ObjectiveMatrixType::elem_type>,
39          typename BVectorType =
40              arma::Col<typename ObjectiveMatrixType::elem_type>>
41 class SDP
42 {
43  public:
44   //! Type of objective matrix.
45   typedef ObjectiveMatrixType ObjectiveType;
46   //! Type of element held by the SDP.
47   typedef typename ObjectiveMatrixType::elem_type ElemType;
48   //! Type of dense constraints.
49   typedef DenseConstraintMatrixType DenseConstraintType;
50   //! Type of sparse constraints.
51   typedef SparseConstraintMatrixType SparseConstraintType;
52   //! Type of B values.
53   typedef BVectorType BType;
54 
55   /**
56    * Initialize this SDP to an empty state.  To add constraints, you will have
57    * to modify the constraints via the SparseA(), DenseA(), SparseB(), DenseB(),
58    * and C() functions.  For the sake of speed, there is no error checking, so
59    * if you specify an invalid SDP, whatever solver you use will gladly try to
60    * solve it!  (And it will probably crash horribly.)
61    */
62   SDP();
63 
64   /**
65    * Initialize this SDP to one which structurally has size n.  To set the
66    * constraints you will still need to access through SparseA(), DenseA(),
67    * SparseB(), DenseB(), and C().  Consider using move semantics to keep things
68    * fast.  As with the previous constructor, there is no error checking for the
69    * sake of speed, so if you build an invalid SDP, whatever solver you use will
70    * gladly try to solve it!  (And it will probably crash horribly.)
71    *
72    * @param n Number of rows (and columns) in the objective matrix C.
73    * @param numSparseConstraints Number of sparse constraints.
74    * @param numDenseConstraints Number of dense constraints.
75    */
76   SDP(const size_t n,
77       const size_t numSparseConstraints,
78       const size_t numDenseConstraints);
79 
80   //! Return number of rows and columns in the objective matrix C.
N() const81   size_t N() const { return c.n_rows; }
82 
N2bar() const83   size_t N2bar() const { return N() * (N() + 1) / 2; }
84 
85   //! Return the number of sparse constraints (constraints with sparse Ai) in
86   //! the SDP.
NumSparseConstraints() const87   size_t NumSparseConstraints() const { return sparseB.n_elem; }
88   //! Return the number of dense constraints (constraints with dense Ai) in the
89   //! SDP.
NumDenseConstraints() const90   size_t NumDenseConstraints() const { return denseB.n_elem; }
91 
92   //! Return the total number of constraints in the SDP.
NumConstraints() const93   size_t NumConstraints() const { return sparseB.n_elem + denseB.n_elem; }
94 
95   //! Modify the sparse objective function matrix (sparseC).
C()96   ObjectiveMatrixType& C() { return c; }
97   //! Return the sparse objective function matrix (sparseC).
C() const98   const ObjectiveMatrixType& C() const { return c; }
99 
100   //! Return the vector of sparse A matrices (which correspond to the sparse
101   //! constraints).
SparseA() const102   const std::vector<SparseConstraintMatrixType>& SparseA() const
103   { return sparseA; }
104 
105   //! Modify the vector of sparse A matrices (which correspond to the sparse
106   //! constraints).
SparseA()107   std::vector<SparseConstraintMatrixType>& SparseA() { return sparseA; }
108 
109   //! Return the vector of dense A matrices (which correspond to the dense
110   //! constraints).
DenseA() const111   const std::vector<DenseConstraintMatrixType>& DenseA() const
112   { return denseA; }
113 
114   //! Modify the vector of dense A matrices (which correspond to the dense
115   //! constraints).
DenseA()116   std::vector<DenseConstraintMatrixType>& DenseA() { return denseA; }
117 
118   //! Return the vector of sparse B values.
SparseB() const119   const BVectorType& SparseB() const { return sparseB; }
120   //! Modify the vector of sparse B values.
SparseB()121   BVectorType& SparseB() { return sparseB; }
122 
123   //! Return the vector of dense B values.
DenseB() const124   const BVectorType& DenseB() const { return denseB; }
125   //! Modify the vector of dense B values.
DenseB()126   BVectorType& DenseB() { return denseB; }
127 
128   /**
129    * Check whether or not the constraint matrices are linearly independent.
130    *
131    * Warning: possibly very expensive check.
132    */
133   bool HasLinearlyIndependentConstraints() const;
134 
135   //! Get an initial point for the primal coordinates.
136   template<typename MatType = arma::mat>
137   MatType GetInitialPoint() const;
138 
139   //! Get initial points for the primal and dual coordinates.
140   template<typename MatType = arma::mat>
141   void GetInitialPoints(MatType& coordinates,
142                         MatType& ySparse,
143                         MatType& yDense,
144                         MatType& dualCoordinates) const;
145 
146  private:
147   //! Objective function matrix c.
148   ObjectiveMatrixType c;
149 
150   //! A_i for each sparse constraint.
151   std::vector<SparseConstraintMatrixType> sparseA;
152   //! b_i for each sparse constraint.
153   BVectorType sparseB;
154 
155   //! A_i for each dense constraint.
156   std::vector<DenseConstraintMatrixType> denseA;
157   //! b_i for each dense constraint.
158   BVectorType denseB;
159 };
160 
161 } // namespace ens
162 
163 // Include implementation.
164 #include "sdp_impl.hpp"
165 
166 #endif
167