KerMor  0.9
Model order reduction for nonlinear dynamical systems and nonlinear approximation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
POD.m
Go to the documentation of this file.
1 namespace general{
2 
3 
4 /* (Autoinserted by mtoc++)
5  * This source code has been filtered by the mtoc++ executable,
6  * which generates code that can be processed by the doxygen documentation tool.
7  *
8  * On the other hand, it can neither be interpreted by MATLAB, nor can it be compiled with a C++ compiler.
9  * Except for the comments, the function bodies of your M-file functions are untouched.
10  * Consequently, the FILTER_SOURCE_FILES doxygen switch (default in our Doxyfile.template) will produce
11  * attached source files that are highly readable by humans.
12  *
13  * Additionally, links in the doxygen generated documentation to the source code of functions and class members refer to
14  * the correct locations in the source code browser.
15  * However, the line numbers most likely do not correspond to the line numbers in the original MATLAB source files.
16  */
17 
18 class POD
19  :public KerMorObject {
46  public: /* ( setObservable ) */
47 
48  Mode = "rel";
82  Value = .3;
100  UseSVDS = false;
122  public: /* ( setObservable ) */
123 
124 
125  POD() {
126  this = this@KerMorObject;
127 
128  this.registerProps(" Mode "," Value "," UseSVDS ");
129  }
130 
131 
132  function [matrix<double>podvec , rowvec<double>s ] = computePOD(matrix<double> data,matrix<double> Vexclude,colvec<integer> targetdims) {
133 
134  /* % Dimension checks
135  * This is for the "explicit" modes where the target dimension
136  * is either a fixed value or a fraction of the full dimension. */
137  if nargin < 4
138  targetdims = " : ";
139  if nargin < 3
140  Vexclude = [];
141  end
142  end
143  target_dim=[];
144  if strcmpi(this.Mode," rel ")
145  target_dim = ceil(min(size(data))*this.Value);
146  elseif strcmpi(this.Mode," abs ")
147  target_dim = this.Value;
148  end
149  if ~isempty(target_dim) && target_dim > min(size(data))
150  warning(" KerMor:general:POD "," Targeted reduced space dimension (%d) has to be <= the smallest matrix dimension (%d). Using size %d. ",...
151  target_dim,min(size(data)),min(size(data)));
152  target_dim = min(size(data));
153  end
154 
155  /* % Block SVD case */
156  if isa(data," data.ABlockedData ")
157  if ~any(strcmpi(this.Mode,[" abs "," rel "]))
158  target_dim = min(size(data));
159  if max(size(data)) > 10000
160  warning(" POD on data.ABlockedData with dimension %d and mode '%s' is possibly very very slow. Try to use "" abs "" or "" rel "" modes. ",max(size(data)),this.Mode);
161  end
162  end
163  if KerMor.App.Verbose > 2
164  [n,m] = size(data);
165  fprintf(" Starting POD on ABlockedData(%s, %dx%d, %d blocks) with mode "" %s "" and value %g\n ",...
166  class(data),n,m,data.getNumBlocks,this.Mode,this.Value);
167  end
168  [podvec, s] = data.getSVD(target_dim, Vexclude, targetdims);
169  s = diag(s);
170 
171  sig = 1:size(podvec,2);
172  if strcmpi(this.Mode," sign ")
173  sig = s >= s(1)*this.Value;
174  elseif strcmpi(this.Mode," eps ")
175  sig = s >= this.Value;
176  end
177  podvec = podvec(:,sig);
178 
179  /* % Matrix argument case */
180  else
181  /* Reduce the data to the targeted dimensions first */
182  data = data(targetdims,:);
183 
184  /* Subtract the space spanned by Vexclude if given */
185  if ~isempty(Vexclude)
186  data = data - Vexclude*(Vexclude^t*data);
187  target_dim = min(target_dim, min(size(data))-size(Vexclude,2));
188  end
189 
190  /* Create full matrix out of sparse fxi sets to enable use of
191  * svd instead of svds */
192  nonzero = [];
193  if issparse(data)
194  nonzero = find(sum(abs(data),2) ~= 0);
195  /* Check if same sparsity pattern holds for each fxi column */
196  if ~isempty(nonzero)
197  if KerMor.App.Verbose > 2
198  fprintf(" Reducing data dimension from %d to %d as sparse matrix is given. ",...
199  size(data,1),length(find(nonzero)));
200  end
201  fulldim = size(data,1);
202  data = full(data(nonzero,:));
203  end
204  end
205 
206  if KerMor.App.Verbose > 2
207  fprintf(" Starting POD on %dx%d matrix with mode "" %s "" and value %g (UseSVDS=%d) ... ",...
208  size(data),this.Mode,this.Value,this.UseSVDS);
209  end
210  /* % Reduction for modes 'sign' and 'eps'
211  * For these "dynamic" modes the full singular values have
212  * to be computed in order to determine how many to use. */
213  if any(strcmpi(this.Mode,[" sign "," eps "]))
214  [u,s] = svd(data," econ ");
215  s = diag(s);
216  if strcmpi(this.Mode," sign ")
217  sig = s >= s(1)*this.Value;
218  elseif strcmpi(this.Mode," eps ")
219  sig = s >= this.Value;
220  end
221  if KerMor.App.Verbose > 2
222  fprintf(" selecting %d singular values ... ",length(find(sig)));
223  end
224  /* Select wanted subspace */
225  u = u(:,sig);
226 
227  err = sum(s(~sig));
228  rerr = 100*err/sum(s);
229  else
230  /* % Reduction for modes 'abs' and 'rel'
231  * For cases 'abs' or 'rel': fixed target dimension.
232  * So just let svds extract the wanted components! */
233 
234  /* As tests showed that the svds method is less reliable
235  * computing correct subspaces, an option is added that
236  * explicitly allows to choose if svds is used rather than
237  * svd. */
238  if this.UseSVDS || issparse(data)
239  [u, s] = svds(data, target_dim);
240  s = diag(s);
241  else
242  [u,s] = svd(data," econ ");
243  s = diag(s);
244  err = sum(s(target_dim+1:end));
245  rerr = 100*err/sum(s);
246  u(:,target_dim+1:end) = [];
247  end
248  end
249  if KerMor.App.Verbose > 2
250  fprintf(" error %g (%g%% relative)\n ",err,rerr);
251  end
252 
253  /* Safety for zero singular values. */
254  z = find(s(1:size(u,2)) == 0);
255  if ~isempty(z)
256  warning(" KerMor:POD "," %d of %d selected singular values are zero. Assuming output size %d ",...
257  length(z),length(s),length(s)-length(z));
258  end
259  u(:,z) = [];
260 
261  /* Re-create the sparse matrix structure after POD computation if input argument
262  * was a sparse matrix */
263  if ~isempty(nonzero)
264  u = MatUtils.toSparse(u, nonzero, fulldim);
265  end
266 
267  podvec = u;
268  end
269  /* Security checks (only for true matrices so far) */
270  if any(any(round(podvec^t*podvec) ~= eye(size(podvec,2))))
271  warning(" KerMor:POD ",[" Resulting POD vectors not " ...
272  " sufficiently orthogonal. Orthonormalizing. "]);
273  /* Sometimes the u vectors generated by svds are not
274  * properly orthonormal */
275  o = general.Orthonormalizer;
276  podvec = o.orthonormalize(podvec);
277  end
278  }
308 #if 0 //mtoc++: 'set.UseSVDS'
309 function UseSVDS(value) {
310  if ~islogical(value)
311  error(" Value should be logical ");
312  end
313  this.UseSVDS= value;
314  }
315 
316 #endif
317 
318 
319 
320 #if 0 //mtoc++: 'set.Mode'
321 function Mode(value) {
322  if ~any(strcmpi(value, [" sign "," eps "," abs "," rel "]))
323  error([" Unknown POD reduction mode: " value " \nAllowed: sign, eps, abs, rel "]);
324  end
325  this.Mode= lower(value);
326  }
327 
328 #endif
329 
330 
331 
332 #if 0 //mtoc++: 'set.Value'
333 function Value(value) {
334  if ~isreal(value) || ~isscalar(value)
335  error(" Value property must be a positive real scalar. ");
336  end
337  this.Value= value;
338  }
339 
340 #endif
341 
342 
343  public: /* ( Static ) */ /* ( setObservable ) */
344 
345 
346  static function res = test_POD() {
347  pod = general.POD;
348  res = true;
349 
350  /* d < N */
351  vec = rand(50,1000);
352  res = res && general.POD.internalPODTest(pod, vec);
353  res = res && general.POD.internalPODTest(pod, vec, 1:30);
354  res = res && general.POD.internalPODTest(pod, vec, 30:50);
355 
356  /* d > N */
357  vec = rand(1000,50);
358  res = res && general.POD.internalPODTest(pod, vec);
359  res = res && general.POD.internalPODTest(pod, vec, 1:300);
360  res = res && general.POD.internalPODTest(pod, vec, 800:900);
361  }
362 
363 
364 
365  private: /* ( Static ) */ /* ( setObservable ) */
366 
367  static function res = internalPODTest(pod,vec,selection) {
368  if nargin < 3
369  selection = " : ";
370  end
371  res = true;
372  pod.Mode= " eps ";
373  pod.Value= 7;
374  V = pod.computePOD(vec,[],selection);
375  res = res && isequal(round(V^t*V),eye(size(V,2)));
376 
377  pod.Mode= " sign ";
378  pod.Value= .3;
379  V = pod.computePOD(vec,[],selection);
380  res = res && isequal(round(V^t*V),eye(size(V,2)));
381 
382  pod.Mode= " abs ";
383  pod.Value= 10;
384  V = pod.computePOD(vec,[],selection);
385  res = res && isequal(round(V^t*V),eye(size(V,2)));
386 
387  /* Vexclude mode */
388  o = general.Orthonormalizer;
389 
390  exclu = o.orthonormalize(rand(length(vec(selection,1)),round(pod.Value/2)));
391  Vex = pod.computePOD(vec,exclu,selection);
392  res = res && isequal(round(Vex^t*Vex),eye(size(Vex,2)));
393  res = res && norm(exclu^t*Vex) < 1e-12;
394 
395  pod.Mode= " abs ";
396  pod.Value= 10;
397  Vf = pod.computePOD(data.FileMatrix(vec),[],selection);
398  res = res && isequal(round(Vf" *Vf),eye(size(Vf,2))) && norm(abs(V)-abs(Vf), "fro^t) < 1e-10;
399 
400  pod.Mode= " rel ";
401  pod.Value= .3;
402  V = pod.computePOD(vec,[],selection);
403  res = res && isequal(round(V^t*V),eye(size(V,2)));
404 
405  pod.Mode= " rel ";
406  pod.Value= .3;
407  Vf = pod.computePOD(data.FileMatrix(vec),[],selection);
408  res = res && isequal(round(Vf" *Vf),eye(size(Vf,2))) && norm(abs(V)-abs(Vf), "fro^t) < 1e-10;
409  }
410 
411 
425 };
426 }
427 
428 
429 
static function res = test_POD()
Definition: POD.m:346
Base class for any KerMor class.
Definition: KerMorObject.m:17
static function Asparse = toSparse(matrix< double > A,rowvec< integer > rowidx, n)
Converts a full matrix A to a sparse matrix, where the entries of A are split up to the row indices s...
Definition: MatUtils.m:467
function registerProps(varargin)
Call this method at any class that defines DPCM observed properties.
Definition: DPCMObject.m:125
function [ matrix< double > podvec , rowvec< double > s ] = computePOD(matrix< double > data,matrix< double > Vexclude,colvec< integer > targetdims)
Computes the POD vectors according to the specified settings.
Definition: POD.m:132
A boolean value.
KerMorObject()
Constructs a new KerMor object.
Definition: KerMorObject.m:55
Value
The value associated with the selected Mode.
Definition: POD.m:82
A matlab column vector.
POD()
Definition: POD.m:125
Mode
The modus used to generate the reduced space.
Definition: POD.m:48
UseSVDS
Flag whether to use the svds routine rather than svd. Applies only for the Modes abs and rel...
Definition: POD.m:100
MatUtils: Matrix utility functions.
Definition: MatUtils.m:17
POD: Implements proper orthogonal decomposition.
Definition: POD.m:18
Global configuration class for all KerMor run-time settings.
Definition: KerMor.m:17
static function KerMor theinstance = App()
The singleton KerMor instance.
Definition: KerMor.m:910