ProjectBudgetMaintenanceStrategy.h
Go to the documentation of this file.
1 //===========================================================================
2 /*!
3  *
4  *
5  * \brief Project budget maintenance strategy
6  *
7  * \par
8  * This is an budget strategy that simply project one of the
9  * budget vectors onto the others. To save time, the smallest
10  * vector (measured in 2-norm of the alpha-coefficients) will
11  * be selected for projection.
12  *
13  *
14  *
15  *
16  * \author Aydin Demircioglu
17  * \date 2014
18  *
19  *
20  * \par Copyright 1995-2017 Shark Development Team
21  *
22  * <BR><HR>
23  * This file is part of Shark.
24  * <http://shark-ml.org/>
25  *
26  * Shark is free software: you can redistribute it and/or modify
27  * it under the terms of the GNU Lesser General Public License as published
28  * by the Free Software Foundation, either version 3 of the License, or
29  * (at your option) any later version.
30  *
31  * Shark is distributed in the hope that it will be useful,
32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34  * GNU Lesser General Public License for more details.
35  *
36  * You should have received a copy of the GNU Lesser General Public License
37  * along with Shark. If not, see <http://www.gnu.org/licenses/>.
38  *
39  */
40 //===========================================================================
41 
42 
43 #ifndef SHARK_MODELS_PROJECTBUDGETMAINTENANCESTRATEGY_H
44 #define SHARK_MODELS_PROJECTBUDGETMAINTENANCESTRATEGY_H
45 
47 #include <shark/ObjectiveFunctions/KernelBasisDistance.h>
48 #include <shark/Data/Dataset.h>
49 #include <shark/Data/DataView.h>
50 
51 
52 namespace shark {
53 
54  ///
55  /// \brief Budget maintenance strategy that projects a vector
56  ///
57  /// This is an budget strategy that simply projects one of the
58  /// budget vectors onto the others. The resulting coefficients are
59  /// then added to the other vectors and the projected vector is
60  /// removed from the budget.
61  ///
62  template<class InputType>
66  typedef typename DataType::element_type ElementType;
67 
68  public:
69 
70  /// constructor.
72  }
73 
74 
75  /// add to model.
76  /// this is just a fake here, as it is unclear in general how to merge two objects,
77  /// one needs to specialize this template.
78  ///
79  /// @param[in,out] model the model the strategy will work with
80  /// @param[in] alpha alphas for the new budget vector
81  /// @param[in] supportVector the vector to add to the model by applying the maintenance strategy
82  ///
83  virtual void addToModel (ModelType& model, InputType const& alpha, ElementType const& supportVector) {
84  // to project we simply utilize the kernel basis distance
85  }
86 
87 
88  /// class name
89  std::string name() const
90  { return "ProjectBudgetMaintenanceStrategy"; }
91 
92  protected:
93 
94  };
95 
96  ///
97  /// \brief Budget maintenance strategy that projects a vector
98  ///
99  /// \par This is an specialization of the project budget maintenance strategy
100  /// that handles simple real-valued vectors. This is a nearly 1:1 adoption of
101  /// the strategy presented in Wang, Cramer and Vucetic.
102  ///
103  template<>
105  typedef RealVector InputType;
108  typedef typename DataType::element_type ElementType;
109 
110  public:
111 
112  /// constructor.
114  }
115 
116 
117 
118  /// add a vector to the model.
119  /// this will add the given vector to the model and merge the budget so that afterwards
120  /// the budget size is kept the same. If the budget has a free entry anyway, no merging
121  /// will be performed, but instead the given vector is simply added to the budget.
122  ///
123  /// @param[in,out] model the model the strategy will work with
124  /// @param[in] alpha alphas for the new budget vector
125  /// @param[in] supportVector the vector to add to the model by applying the maintenance strategy
126  ///
127  virtual void addToModel (ModelType& model, InputType const& alpha, ElementType const& supportVector) {
128 
129  // projecting should try out every budget vector
130  // but as this would yield $O(B^3)$ runtime, the vector
131  // with the smallest alpha is taken instead.
132 
133  // first put the new vector into place
134  size_t maxIndex = model.basis().numberOfElements();
135  model.basis().element(maxIndex - 1) = supportVector.input;
136  row (model.alpha(), maxIndex - 1) = alpha;
137 
138 
139  size_t firstIndex = 0;
140  double firstAlpha = 0;
141  findSmallestVector (model, firstIndex, firstAlpha);
142 
143  // if the smallest vector has zero alpha,
144  // the budget is not yet filled so we can skip projecting.
145  if (firstAlpha == 0.0f)
146  {
147  // as we need the last vector to be zero, we put the new
148  // vector to that place and undo our putting-the-vector-to-back-position
149  model.basis().element(firstIndex) = supportVector.input;
150  row (model.alpha(), firstIndex) = alpha;
151 
152  // enough to zero out the alpha
153  row (model.alpha(), maxIndex - 1).clear();
154 
155  // ready.
156  return;
157  }
158 
159  // now solve the projection equation
160 
161  // we need to project the one vector we have chosen down
162  // to all others. so we need a model with just thet one vector
163  // and then we try to approximate alphas from the rest of thet
164  // vectors, such that the difference is small as possible.
165 
166  // create a KernelExpansion just with the one selected vector.
167  std::vector<RealVector> singlePointVector (1,model.basis().element(firstIndex));
168  std::vector<unsigned int> singlePointLabel (1, 0);
169  ClassificationDataset singlePointData = createLabeledDataFromRange(singlePointVector, singlePointLabel);
170  KernelExpansion<RealVector> singlePointExpansion(model.kernel(), singlePointData.inputs(), false, model.alpha().size2());
171  row (singlePointExpansion.alpha(), 0) = row (model.alpha(), firstIndex);
172  KernelBasisDistance distance(&singlePointExpansion, maxIndex - 1);
173 
174  // now create a whole new 'point' with all the other vectors.
175  // then our approximation will give us one coefficient to approximate
176  // the basis, which consits only of the one selected vector.
177  // thus, we approximate the one vector with the rest of them.
178  size_t inputDimension = model.basis().element(0).size();
179  RealVector point(inputDimension * (maxIndex - 1));
180 
181  // copy all other budget vectors into one big vector
182  size_t linearIndex = 0;
183  for(std::size_t t = 0; t < maxIndex; t++){
184  // do not copy the first index.
185  if (t == firstIndex)
186  continue;
187  noalias(subrange(point, linearIndex*inputDimension, (linearIndex+1)*inputDimension)) = (model.basis().element(t));
188  linearIndex++;
189  }
190 
191  //calculate solution found by the function and check that it is close
192  RealMatrix projectedAlphas = distance.findOptimalBeta(point);
193 
194  // stupid sanity check
195  SHARK_ASSERT (projectedAlphas.size2() == model.alpha().size2());
196 
197  // add the projected values to the budget
198  linearIndex = 0;
199  for (std::size_t j = 0; j < maxIndex; j++)
200  {
201  if (j == firstIndex)
202  continue;
203 
204  // for each class we add the alpha contribution to the true alphas.
205  for (std::size_t c = 0; c < model.alpha().size2(); c++)
206  model.alpha(j, c) += projectedAlphas(linearIndex, c);
207 
208  linearIndex++;
209  }
210 
211  // overwrite the projected vector with the last vector
212  model.basis().element(firstIndex) = supportVector.input;
213  row (model.alpha(), firstIndex) = alpha;
214 
215  // zero out buffer, enough to zero out the alpha
216  row (model.alpha(), maxIndex - 1).clear();
217  }
218 
219 
220  /// class name
221  std::string name() const
222  { return "ProjectBudgetMaintenanceStrategy"; }
223 
224  protected:
225 
226  };
227 
228 
229 }
230 #endif