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
KernelEI.m
Go to the documentation of this file.
1 namespace approx{
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 KernelEI
19  :public approx.BaseApprox {
39  public: /* ( setObservable ) */
40 
56  Variant = 2;
71  .approx.ABase Algorithm;
88  .natural nJacobians = 5;
103  public:
104 
133  public: /* ( Dependent, setObservable ) */
134 
151  public:
152 
153  fOrder = 10;
154 
155 
156  u;
178  U;
188  S;
189 
190  f;
191 
193 
195 
196 
197  public:
198 
199  KernelEI(sys) {
200  this = this@approx.BaseApprox(sys);
201  this.CustomProjection= true;
202  this.TimeDependent= true;
203  }
204 
205 
207  this.f= model.System.f;
208  if ~isa(this.f," dscomponents.ACompEvalCoreFun ");
209  error(" Cannot use DEIM with no ACompEvalCoreFun core functions. ");
210  end
211 
212  atd = model.Data.ApproxTrainData;
213 
214  /* % Generate u_1 ... u_m base */
215  p = general.POD;
216  p.Mode= " abs ";
217  p.Value= this.MaxOrder;
218  p.UseSVDS= size(atd.fxi,1) > 10000;
219  this.u= p.computePOD(atd.fxi);
220 
221  if size(this.u,2) < this.MaxOrder
222  warning(" Less singular values (%d) than MaxOrder (%d). Setting MaxOrder=%d ",...
223  size(this.u,2),this.MaxOrder,size(this.u,2));
224  this.MaxOrder= min(this.MaxOrder,size(this.u,2));
225  end
226 
227  /* Get interpolation points */
228  this.pts= this.getInterpolationPoints(this.u);
229 
230  /* Compose argument indices arrays */
231  SP = this.f.JSparsityPattern;
232  if isempty(SP)
234  end
235 
236  invalid = sum(SP,2) == 0;
237  if any(invalid(this.pts))
238  invalididx = find(invalid);
239  this.pts= setdiff(this.pts, invalididx, " stable ");
240  old = this.MaxOrder;
241  this.MaxOrder= length(this.pts);
242  warning(" Detected Jacobian rows with all zero entries. New MaxOrder=%d (Prev: %d) ",this.MaxOrder,old);
243  end
244 
245  jr = [];
246  je = zeros(1,length(this.pts));
247  for i=1:length(this.pts)
248  sprow = SP(this.pts(i),:);
249  inew = find(sprow);
250  jr = [jr inew];/* #ok */
251 
252  je(i) = length(jr);
253  end
254  this.jrow= jr;
255  this.jend= je;
256 
257  /* Trigger computation of U matrix etc */
258  this.Order= this.fOrder;
259 
260  this.V1Expansion= [];
261  this.V2Expansions= [];
262  if this.Variant == 1
263  /* no space projection via W,V */
264  if isempty(this.W)
265  zi = atd.xi.toMemoryMatrix;
266  else
267  zi = this.W^t*atd.xi.toMemoryMatrix;
268  end
269 
270  if isempty(this.V)
271  Vzi = zi;
272  else
273  Vzi = this.V*zi;
274  end
275 
276  fzi = model.System.f.evaluateMulti(Vzi,atd.ti,atd.mui);
277  vatd = data.ApproxTrainData(zi,atd.ti,atd.mui);
278  mo = this.MaxOrder;
279  vatd.fxi= sparse(this.pts,1:mo,ones(mo,1),size(atd.fxi,1),mo)^t*fzi;
280  this.V1Expansion= this.Algorithm.computeApproximation(vatd);
281  elseif this.Variant == 2
282  /* Compose x-entry selection matrix */
283  pi = ProcessIndicator(sprintf(" KernelEI: Computing %d approximations\n ",this.MaxOrder),this.MaxOrder);
284  for idx = 1:this.MaxOrder
285  /* Select the elements of x that are effectively used in f */
286  off = 0;
287  if idx > 1
288  off = this.jend(idx-1);
289  end
290  xireq = atd.xi(this.jrow(off+1:this.jend(idx)),:);
291  latd = data.ApproxTrainData(xireq, atd.ti, atd.mui);
292  latd.fxi= atd.fxi(this.pts(idx),:);
293  this.V2Expansions[idx] = this.Algorithm.computeApproximation(latd);
294  pi.step;
295  end
296  pi.stop;
297  end
298  }
299 
300 
301  function fx = evaluateCoreFun(colvec<double> x,double t) {
302  if this.Variant == 1
303  fu = this.V1Expansion.evaluate(x, t, this.mu);
304  c = fu(1:this.fOrder);
305  elseif this.Variant == 2
306  c = zeros(this.fOrder,size(x,2));
307  for o = 1:this.fOrder
308  /* Select the elements of x that are effectively used in f
309  * S is already of the size of all required elements, so to this.jrow
310  * indexing is required */
311  off = 1;
312  if o > 1
313  off = off + this.jend(o-1);
314  end
315  c(o,:) = this.V2Expansions[o].evaluate(this.S(off:this.jend(o),:)*x,t,this.mu);
316  end
317  end
318  fx = this.U * c;
319  }
320 
321 
323 
324  /* % this method uses finite differences in the neighbourhood of
325  *% trajectory points and checks which entries of the Jacobian
326  *% turn out non-zero */
327 
328  /* reproducable (for now), uses matlabs default mt19937ar rand stream */
329  s = RandStream(" mt19937ar "," Seed ",42);
330 
331  nTraj = this.System.Model.Data.TrajectoryData.getNumTrajectories();
332  nJac = this.nJacobians;
333  ntimes = size(this.System.Model.Data.TrajectoryData,2);
334  nJac = min(nJac, nTraj*ntimes);
335  nMu = size(this.System.Model.Data.ParamSamples, 2);
336 
337  m = this.System.Model;
338  dim = m.Approx.f.xDim;
339  JSP = logical(sparse(dim,dim));
340 
341  if m.System.ParamCount == 0
342  /* get several trajectories, i.e Xi = dim x ntimes x nTraj */
343  [Xi, ~, ~, ~] = m.Data.TrajectoryData.getTrajectoryNr(s.randperm(nTraj,min(nJac,nTraj)));
344 
345  for j = s.randperm(size(Xi,2),nJac) /* choose random time */
346 
347  tt = []; /* TODO: Falls f = f(..,t) dann wissen wir nicht, was f�r ein t zu Xi(:,col) geh�rt.. ?
348  * Ist das t (immer?) �quidist und dann
349  * X(:,col) ~=> t = m.T / nCols * col ? */
350 
351 
352  k = s.randperm(size(Xi,3),1); /* choose random traj. number */
353 
354  JJ = this.System.f.getStateJacobianFD(Xi(:,j,k), tt);
355 
356  JSP = JSP | JJ;
357  end
358  else /* have parameters */
359 
360  if nMu == 0
361  error(" Have no parameter samples, yet the system has configured some. ");
362  end
363 
364  nMuToUse = min(nMu, nJac);
365  nJacPerMu = floor(nJac/nMuToUse);
366 
367  origMu = this.System.f.mu; /* TODO: do I have to restore mu? */
368 
369  mus = m.Data.ParamSamples(:, s.randperm(nMu,nMuToUse));
370 
371 
372  nJacDone = 0;
373  for muu = mus
374 
375  /* %TODO Lorin: what inputidx should i use?
376  * What happens when inputIndex is used when
377  * storing? Then hashes only exist for hash([mu; inidx])
378  * and not for hash([mu; [] ] ) .. */
379  inputindex = m.System.inputidx; /* TODO: is this only the current inIdx.. ? */
380 
381  [Xi, ~] = m.Data.TrajectoryData.getTrajectory(muu,inputindex);
382 
383  for j = randperm(size(Xi,2),nJacPerMu)
384  tt = []; /* TODO: Falls f = f(..,t) dann wissen wir nicht, was f�r ein t zu Xi(:,col) geh�rt.. ?
385  * Ist das t (immer?) �quidist. und dann
386  * X(:,col) ~=> t = m.T / nCols * col ? */
387 
388 
389  /* mu is used inside jacobianFD */
390  this.System.f.prepareSimulation(muu); /* sets mu */
391 
392 
393  JJ = this.System.f.getStateJacobianFD(Xi(:,j), tt);
394 
395 
396  JSP = JSP | JJ;
397  nJacDone = nJacDone + 1;
398  end
399  end
400  /* TODO: maybe floor(nJac/nMu)*nMu << nJac ? */
401  end
402 
403  ESP = sparse(JSP);
404  this.System.f.prepareSimulation(origMu);
405  }
406 
407 
408  function projected = project(V,W) {
409  projected = this.clone;
410  if ~isempty(this.V1Expansion)
411  /* No W projection needed as we are directly learning up to
412  * MaxOrder components */
413  orig = this.V1Expansion.Ma;
414  this.V1Expansion.Ma= rand(size(W,1),1);
415  projected.V1Expansion= this.V1Expansion.project(V,W);
416  projected.V1Expansion.Ma= orig;
417  end
418  projected = project@approx.BaseApprox(this, V, W, projected);
419  projected.updateOrderData;
420  }
421 
422 
423  function copy = clone() {
424  copy = approx.KernelEI(this.System);
425  copy = clone@approx.BaseApprox(this, copy);
426  copy.fOrder= this.fOrder;
427  copy.u= this.u;
428  copy.pts= this.pts;
429  copy.U= this.U;
430  copy.f= this.f;
431  copy.jrow= this.jrow;
432  copy.jend= this.jend;
433  copy.MaxOrder= this.MaxOrder;
434  if ~isempty(this.V1Expansion)
435  copy.V1Expansion= this.V1Expansion.clone;
436  end
437  copy.Variant= this.Variant;
438  copy.jend= this.jend;
439  copy.jrow= this.jrow;
440  n = length(this.V2Expansions);
441  for i=1:n
442  copy.V2Expansions[i] = this.V2Expansions[i].clone;
443  end
444  copy.S= this.S;
445  }
446 
447 
448  private:
449 
450  function pts = getInterpolationPoints(u) {
451  n =size(u,1);
452  m = size(u,2);
453  pts = zeros(1, m);
454  v = pts;
455  [v(1), pts(1)] = max(abs(u(:,1)));
456  P = zeros(n,1);
457  P(pts(1)) = 1;
458  for i=2:m
459  c = (P" *u(:,1:(i-1))) \ (P "*u(:,i));
460  [v(i), pts(i)] = max(abs(u(:,i) - u(:,1:(i-1))*c));
461  P = sparse(pts(1:i),1:i,ones(i,1),n,i);
462  end
463  if KerMor.App.Verbose > 2
464  fprintf(" DEIM interpolation points [%s] with values [%s] ",...
465  Utils.implode(pts," "," %d "),Utils.implode(v," "," %2.2e "));
466  end
467  }
477  function updateOrderData() {
478  n = size(this.u,1);
479  o = this.fOrder;
480  P = sparse(this.pts(1:o),1:o,ones(o,1),n,o);
481  this.U= this.u(:,1:this.fOrder) * ...
482  inv(P^t*this.u(:,1:this.fOrder));
483  if ~isempty(this.W)
484  this.U= this.W^t*this.U;
485  end
486 
487  len = this.jend(end);
488  sel = this.jrow(1:len);
489  if ~isempty(this.V)
490  this.S= this.V(sel,:);
491  else
492  this.S= sparse(1:len,sel,ones(len,1),len,n);
493  end
494  }
501  /* % Getter & Setter */
502  public:
503 
504 
505 #if 0 //mtoc++: 'get.Order'
506 function o = Order() {
507  o = this.fOrder;
508  }
509 
510 #endif
511 
512 
513 
514 #if 0 //mtoc++: 'set.Order'
515 function Order(value) {
516  if isempty(this.u) || isempty(this.pts)
517  error(" Cannot set DEIM order as approximateSystemFunction has not been called yet. ");
518  end
519  if value > size(this.u,2) || value < 1
520  error(" Invalid Order value. Allowed are integers in [1, %d] ",size(this.u,2));
521  end
522  this.fOrder= value;
523 
524  this.updateOrderData;
525  }
526 
527 #endif
528 
529 
530 
531 #if 0 //mtoc++: 'set.MaxOrder'
532 function MaxOrder(value) {
533  if ~isempty(this.fOrder) && this.fOrder > value/* #ok */
534 
535  this.fOrder= value;/* #ok */
536 
537  end
538  this.MaxOrder= value;
539  }
540 
541 #endif
542 
543 
544  public: /* ( Static ) */
545 
546  static function res = test_KernelEI() {
547  m = models.pcd.PCDModel(1);
548  m.dt= .1;
549  m.T= 1;
550  m.EnableTrajectoryCaching= false;
551 
552  /* Define prototype expansion */
553  ec = kernels.config.ParamTimeExpansionConfig;
554  ec.StateConfig= kernels.config.GaussConfig(" G ",1:3);
555  ec.TimeConfig= [];
556  ec.ParamConfig= kernels.config.GaussConfig(" G ",1:3);
557 
558  a = approx.algorithms.VKOGA;
559  a.MaxExpansionSize= 300;
560  a.UsefScaling= false;
561  a.UsefPGreedy= false;
562  a.ExpConfig= ec;
563 
564  kei = approx.KernelEI(m.System);
565  kei.Algorithm= a;
566  kei.Variant= 2;
567 
568  m.Approx= kei;
569  m.Approx.MaxOrder= 5;
570  m.System.Params(1).Desired = 2;
571  m.SpaceReducer= spacereduction.PODGreedy;
572  m.SpaceReducer.Eps= 1e-5;
573  m.offlineGenerations;
574 
575  mu = m.getRandomParam;
576  r = m.buildReducedModel;
577  r.simulate(mu);
578 
579  kei.Variant= 1;
580  m.off5_computeApproximation;
581 
582  r = m.buildReducedModel;
583  r.simulate(mu);
584 
585  res = true;
586  }
587 
588 
598 };
599 }
600 
function copy = clone()
Definition: KernelEI.m:423
Collection of generally useful functions.
Definition: Utils.m:17
matrix< double > Ma
The coefficient data for each dimension.
KernelEI: DEIM approximation using kernel expansions for function/operator evaluations.
Definition: KernelEI.m:18
natural nJacobians
nJacobians: number of Jacobian samples to use for empirical sparsity detection i.e. we choose nJacobians many Jacobian samples from trajectories number
Definition: KernelEI.m:88
The base class for any KerMor detailed model.
Definition: BaseFullModel.m:18
CustomProjection
Set this property if the projection process is customized by overriding the default project method...
Definition: ACoreFun.m:108
models.BaseFirstOrderSystem System
The actual dynamical system used in the model.
Definition: BaseModel.m:102
function prepareSimulation(colvec< double > mu)
A method that allows parameter-dependent computations to be performed before a simulation using this ...
Definition: ACoreFun.m:380
logical TimeDependent
Flag that indicates if the ACoreFun is (truly) time-dependent.
Definition: ACoreFun.m:84
Model
The Model this System is attached to.
integer MaxOrder
The maximum order up to which the DEIM approximation should be computed.
Definition: KernelEI.m:41
static function res = test_KernelEI()
Definition: KernelEI.m:546
U
The U matrix for the current Order.
Definition: KernelEI.m:178
An integer value.
rowvec< kernels.KernelExpansion > V2Expansions
The array of kernel expansions of using Variant 2.
Definition: KernelEI.m:119
function ESP = computeEmpiricalSparsityPattern()
Definition: KernelEI.m:322
function target = project(V, W)
pts
Interpolation points.
Definition: KernelEI.m:167
A boolean value.
function fx = evaluate(matrix x, varargin)
Evaluates the kernel expansion.
kernels.KernelExpansion V1Expansion
The Kernel expansion computed if using Variant 1.
Definition: KernelEI.m:105
function approximateSystemFunction(models.BaseFullModel model)
Definition: KernelEI.m:206
models.BaseFirstOrderSystem System
The system associated with the current ACoreFun.
Definition: ACoreFun.m:193
integer Order
The actual order for the current DEIM approximation.
Definition: KernelEI.m:135
V
The matrix of the biorthogonal pair .
Definition: AProjectable.m:61
colvec< double > mu
The current model parameter mu for evaluations. Will not be persisted as only valid for runtime durin...
Definition: ACoreFun.m:208
data.ModelData Data
The full model's data container. Defaults to an empty container.
Abstract base class for all core function approximations inside dynamical systems.
Definition: BaseApprox.m:18
dscomponents.ACoreFun f
The core f function from the dynamical system.
function fx = evaluateCoreFun(colvec< double > x,double t)
Actual method used to evaluate the dynamical sytems' core function.
Definition: KernelEI.m:301
function fx = evaluateMulti(colvec< double > x,double t,colvec< double > mu)
Evaluates this function on multiple locations and maybe multiple times and parameters.
Definition: ACoreFun.m:335
function projected = project(V, W)
Definition: KernelEI.m:408
static function char str = implode(char|rowvec data,char glue,char format)
Implodes the elements of data using glue.
Definition: Utils.m:208
function [ matrix< double > J , dx ] = getStateJacobianFD(x, t,rowvec< integer > partidx)
Implementation of jacobian matrix evaluation via finite differences.
Definition: ACoreFun.m:456
function copy = clone(copy)
The interface method with returns a copy of the current class instance.
Global configuration class for all KerMor run-time settings.
Definition: KerMor.m:17
approx.ABase Algorithm
An approx.ABase approximation algorithm that is used to learn the component functions (either simulta...
Definition: KernelEI.m:71
static function KerMor theinstance = App()
The singleton KerMor instance.
Definition: KerMor.m:910
u
The full approximation base.
Definition: KernelEI.m:156
Variant
The variant to use.
Definition: KernelEI.m:56
W
The matrix of the biorthogonal pair .
Definition: AProjectable.m:72
data.ApproxTrainData ApproxTrainData
Training data for the core function approximation.
Definition: ModelData.m:110
ProcessIndicator: A simple class that indicates process either via waitbar or text output...
KernelExpansion: Base class for state-space kernel expansions.