PartlyPrecomputedMatrix.h
Go to the documentation of this file.
1//===========================================================================
2/*!
3 *
4 *
5 * \brief Partly Precomputed version of a matrix for quadratic programming
6 *
7 *
8 * \par
9 *
10 *
11 *
12 * \author T. Glasmachers, A. Demircioglu
13 * \date 2007-2014
14 *
15 *
16 * \par Copyright 1995-2017 Shark Development Team
17 *
18 * <BR><HR>
19 * This file is part of Shark.
20 * <https://shark-ml.github.io/Shark/>
21 *
22 * Shark is free software: you can redistribute it and/or modify
23 * it under the terms of the GNU Lesser General Public License as published
24 * by the Free Software Foundation, either version 3 of the License, or
25 * (at your option) any later version.
26 *
27 * Shark is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU Lesser General Public License for more details.
31 *
32 * You should have received a copy of the GNU Lesser General Public License
33 * along with Shark. If not, see <http://www.gnu.org/licenses/>.
34 *
35 */
36//===========================================================================
37
38
39#ifndef SHARK_LINALG_PARTLYPRECOMPUTEDMATRIX_H
40#define SHARK_LINALG_PARTLYPRECOMPUTEDMATRIX_H
41
42#include <shark/Data/Dataset.h>
43#include <shark/LinAlg/Base.h>
44
45#include <vector>
46#include <cmath>
47
48
49namespace shark
50{
51
52///
53/// \brief Partly Precomputed version of a matrix for quadratic programming
54///
55/// \par
56/// The PartlyPrecomputedMatrix class computes all pairs of kernel
57/// evaluations that fits the given cachesize in its constructor and
58/// stores them im memory.
59///
60/// \par
61/// Use of this class may be beneficial for certain model
62/// selection strategies, where the whole matrix does not fit into
63/// memory, and the LRU cache will produce too much hit rates,
64/// so that at least partially caching the kernel matrix will help.
65/// In particular this will help the KernelSGD/Pegasos algorithm.
66///
67template <class Matrix>
69{
70public:
71 typedef typename Matrix::QpFloatType QpFloatType;
72
73 /// Constructor
74 /// \param[in] base matrix to be cached. it is assumed that this matrix is not precomputed,
75 /// but the (costy) computation takes place every time an entry is queried.
76 /// \param[in] cachesize size of the cache to use in bytes. the size of the cached matrix will
77 // depend on this value.
78 PartlyPrecomputedMatrix(Matrix* base, std::size_t cachesize = 0x4000000)
79 : m_cacheSize(cachesize)
80 , m_baseMatrix(base)
81 {
82 SHARK_RUNTIME_CHECK(m_baseMatrix || m_baseMatrix ->size() == 0, "Cannot cache a NULL matrix!");
83
84 // remember the original size of the matrix
86
87 // determine how many bytes we need for a single row
88 size_t rowSizeBytes = m_originalNumberOfRows * sizeof(QpFloatType);
89
90 // how many rows fit into our cache?
91 size_t m_nRows = (size_t) m_cacheSize / rowSizeBytes;
92 SHARK_RUNTIME_CHECK(m_nRows, "Cache size is smaller than the size of a row!");
93
94 // if we have more space than needed, well, we do not need it.
95 if(m_nRows > m_originalNumberOfRows)
96 m_nRows = m_originalNumberOfRows ;
97
98 // resize matrix
99 m_cachedMatrix.resize(m_nRows, m_baseMatrix ->size());
100
101 // copy the rows
102 for(std::size_t r = 0; r < m_cachedMatrix.size1(); r++)
103 {
104 for(std::size_t j = 0; j < m_baseMatrix->size(); j++)
105 {
106 m_cachedMatrix(r, j) = (*m_baseMatrix)(r, j);
107 }
108 }
109 }
110
111
112
113 /// return, if a given row is cached
114 /// \param[in] k row to check
115 /// \return is given row in cached matrix or not?
116 bool isCached(std::size_t k) const
117 {
118 if(k < m_cachedMatrix.size1())
119 return true;
120 return false;
121 }
122
123
124
125 /// return a complete row of the matrix.
126 /// if the row is cached, it will be returned from there, if not, it will
127 /// be recomputed on-the-fly and not stored.
128 /// param[in] k row to compute
129 /// param[in] storage vector to store the row. must be the same size as a row!
130 void row(std::size_t k, blas::vector<QpFloatType> &storage) const
131 {
133 RANGE_CHECK(0 <= k);
134 SIZE_CHECK(storage.size() == m_cachedMatrix.size2());
135 if(isCached(k) == true)
136 {
137 for(std::size_t j = 0; j < m_cachedMatrix.size2(); j++)
138 {
139 storage[j] = m_cachedMatrix(k, j);
140 }
141 }
142 else
143 {
144 for(std::size_t j = 0; j < m_cachedMatrix.size2(); j++)
145 {
146 storage[j] = (*m_baseMatrix)(k, j);
147 }
148 }
149 }
150
151
152
153 /// return a single matrix entry
154 /// param[in] i row of entry
155 /// param[in] j column entry
156 /// @return value of matrix at given position
157 QpFloatType operator()(std::size_t i, std::size_t j) const
158 {
159 return entry(i, j);
160 }
161
162
163
164 /// return a single matrix entry
165 /// param[in] i row of entry
166 /// param[in] j column entry
167 /// @return value of matrix at given position
168 QpFloatType entry(std::size_t i, std::size_t j) const
169 {
170 // check if we have to compute that or not
171 if(isCached(i))
172 return m_cachedMatrix(i, j);
173
174 // ok, need to compute that element
175 return (*m_baseMatrix)(i, j);
176 }
177
178
179
180 /// return the number of cached rows
181 /// @return number of rows that are cached
182 std::size_t size() const
183 {
184 return m_cachedMatrix.size();
185 }
186
187
188
189 /// return size of cached matrix in QpFloatType units
190 /// @return the capacity of the cached matrix in QpFloatType units
191 std::size_t getMaxCacheSize()
192 {
193 return m_cachedMatrix.size() * m_cachedMatrix.size2();
194 }
195
196
197
198 /// return the dimension of a row in the cache (as we do not shorten our
199 /// rows, this must be the same as the dimension of a row in the original kernel matrix).
200 /// @return dimension of any cached row
201 std::size_t getCacheRowSize() const
202 {
203 return m_cachedMatrix.size2();
204 }
205
206
207
208protected:
209 /// container for precomputed values
210 blas::matrix<QpFloatType> m_cachedMatrix;
211
212 // maximal size of cache
214
215 // original kernel matrix, will be accessed if entries outsied the cache are requested
217
218 // remember how big the original matrix was to prevent access errors
220};
221
222}
223#endif