From b6ab6f111e92dc1942326c79454afbca6899a0ce Mon Sep 17 00:00:00 2001 From: Ferdinand Fischer <ferdinand.fischer@fau.de> Date: Fri, 6 Sep 2019 12:52:45 +0200 Subject: [PATCH] Moved helper functions for polynomial matrices to the new package folder +polyMatrix --- +misc/polynomial2coefficients.m | 1 + +misc/powerSeries2Sum.m | 1 + +polyMatrix/cTranspose.m | 13 +++++++ +polyMatrix/polynomial2coefficients.m | 52 ++++++++++++++++++++++++++ +polyMatrix/powerSeries2Sum.m | 40 ++++++++++++++++++++ +quantity/BasicVariable.m | 54 ++++++++++++++++++--------- +quantity/Discrete.m | 8 ++-- +quantity/Function.m | 4 +- +quantity/Operator.m | 6 +-- +signals/GevreyFunction.m | 40 ++++++++++++-------- +signals/PolyBump.m | 41 ++++++++++++++++---- +signals/polyBump.m | 2 +- +unittests/signalsTest.m | 7 +++- 13 files changed, 216 insertions(+), 53 deletions(-) create mode 100644 +polyMatrix/cTranspose.m create mode 100644 +polyMatrix/polynomial2coefficients.m create mode 100644 +polyMatrix/powerSeries2Sum.m diff --git a/+misc/polynomial2coefficients.m b/+misc/polynomial2coefficients.m index 5aa20e5..5ecc914 100644 --- a/+misc/polynomial2coefficients.m +++ b/+misc/polynomial2coefficients.m @@ -1,4 +1,5 @@ function [ APoly ] = polynomial2coefficients(A, s_var, N) +warning('DEPRICATED: Use polyMatrix.polynomial2coefficients instead') % OPERATOR2POLYNOMIAL Returns the coefficient matrices of an operator % % Inputs: diff --git a/+misc/powerSeries2Sum.m b/+misc/powerSeries2Sum.m index 8db229a..6ece677 100644 --- a/+misc/powerSeries2Sum.m +++ b/+misc/powerSeries2Sum.m @@ -1,4 +1,5 @@ function [ S ] = powerSeries2Sum( M, s_var ) +warning('DEPRICATED: Use polyMatrix.powerSeries2Sum instead') % POWERSERIES2SUM Sum of power series in s_var % % Description: diff --git a/+polyMatrix/cTranspose.m b/+polyMatrix/cTranspose.m new file mode 100644 index 0000000..947da96 --- /dev/null +++ b/+polyMatrix/cTranspose.m @@ -0,0 +1,13 @@ +function [M_T] = cTranspose(M) +%CTRANSPOSE complex conjugate transpose of M +% [M_T] = cTranspose(M) returns the complex conjugate transpose of a +% polynomial matrix M = sum M_k s^k +% M^T_k = sum (-1)^k M_k^T s^k +% M has to be given as 3-dimensional array with the dimension 3 as +% polynomial dimension. +M_T = zeros(size(M,2), size(M, 1), size(M, 3)); + +for k = 1:size(M, 3) + M_T(:,:,k) = (-1)^(k-1) * M(:,:,k)'; +end + diff --git a/+polyMatrix/polynomial2coefficients.m b/+polyMatrix/polynomial2coefficients.m new file mode 100644 index 0000000..5aa20e5 --- /dev/null +++ b/+polyMatrix/polynomial2coefficients.m @@ -0,0 +1,52 @@ +function [ APoly ] = polynomial2coefficients(A, s_var, N) +% OPERATOR2POLYNOMIAL Returns the coefficient matrices of an operator +% +% Inputs: +% A Operator matrix with polynomials A \in C[s]^(n x n) +% s_var symbolic variable +% N maximal degree to be regarded for the coefficients. If the +% polynomial contains higher degree entries than *N*, +% the values are cut off. +% Outputs: +% APoly Coefficients +% +% Example: +% ------------------------------------------------------------------------- +% import misc.* +% syms s; +% A = [10, s; 2*s^2, 3*s^3] +% polynomial2coefficients(A, s) +% +% >> ans(:,:,1) = [10, 0] +% [ 0, 0] +% >> ans(:,:,2) = [ 0, 1] +% [ 0, 0] +% >> ans(:,:,3) = [ 0, 0] +% [ 2, 0] +% >> ans(:,:,4) = [ 0, 0] +% [ 0, 3] +% ------------------------------------------------------------------------- +import misc.* +if ~exist('N', 'var') + % determine maximal degree of spatial variable s + sDegreeMax = -1; + for i=1:numel(A) + sDegreeMax = max([sDegreeMax, length(coeffsAll(A(i),s_var))]); + end + N=sDegreeMax; +end + +% convert system-operator into polynomal expression +APoly = sym(zeros([size(A), N])); +for i=1:size(A,1) + for j=1:size(A,2) + tmp = coeffsAll(A(i,j), s_var); + for k=1:N + if k>length(tmp) + APoly(i, j, k) = sym(0); + else + APoly(i, j, k) = sym(tmp(k)); + end + end + end +end \ No newline at end of file diff --git a/+polyMatrix/powerSeries2Sum.m b/+polyMatrix/powerSeries2Sum.m new file mode 100644 index 0000000..8db229a --- /dev/null +++ b/+polyMatrix/powerSeries2Sum.m @@ -0,0 +1,40 @@ +function [ S ] = powerSeries2Sum( M, s_var ) +% POWERSERIES2SUM Sum of power series in s_var +% +% Description: +% [ S ] = powerSeries2Sum( M, s_var ) +% Summation of all entries in *M* as power series with the symbolic +% varivable *s_var*. *M* can be a cell or a three dimensional array. For +% the 3-D array the dimension 1 and 2 are for the matrices that sould be +% summed up and dimension 3 defines the exponent of the series. Its index +% k corresponds to the coefficient for s_var^(k-1). +% +% Inputs: +% M Matrix of interest +% s_var Symbolic variable in which S should be developed +% Outputs: +% S Summation of power Series +% +% Example: +% ------------------------------------------------------------------------- +% import misc.* +% syms s +% M = cat(3, [0 1], [2 0], [0 3]); +% powerSeries2Sum(M, s) +% >> ans = [2*s, 3*s^2 + 1] +% ------------------------------------------------------------------------- + +if iscell(M) + + S=M{1}; + for k=2:size(M,1) + S=S+M{k}*s_var^(k-1); + end + +else + + S = M(:,:,1); + for k=2:size(M,3) + S = S + M(:,:,k)*s_var^(k-1); + end +end \ No newline at end of file diff --git a/+quantity/BasicVariable.m b/+quantity/BasicVariable.m index d8e3c16..78a573f 100644 --- a/+quantity/BasicVariable.m +++ b/+quantity/BasicVariable.m @@ -33,7 +33,7 @@ function obj = BasicVariable(valueContinuous, varargin) parentVarargin = {}; - if nargin > 0 + if nargin > 0 && ~isempty(varargin) % make default grid: preParser = misc.Parser(); @@ -55,14 +55,20 @@ function obj = BasicVariable(valueContinuous, varargin) preResults.N_diff = preParser.Results.N_diff; end - grid = {linspace(0, preParser.Results.T, N_t)'}; - varargin = [varargin{:}, 'grid', {grid}]; - parentVarargin = {valueContinuous, varargin{:}, 'gridName', {'t'}}; + prsr = misc.Parser(); + prsr.addParameter('grid', {linspace(0, preParser.Results.T, N_t)'} ); + prsr.addParameter('gridName', {'t'}); + prsr.parse(varargin{:}); + + uargin = misc.struct2namevaluepair(prsr.Unmatched); + pargin = misc.struct2namevaluepair(prsr.Results); + + parentVarargin = [{valueContinuous}, uargin(:)', pargin(:)']; end obj@quantity.Function(parentVarargin{:}); - if nargin > 0 + if nargin > 0 && ~isempty(varargin) % first parser p1 = misc.Parser(); p1.addParameter('K', 1); @@ -75,25 +81,31 @@ function obj = BasicVariable(valueContinuous, varargin) for parameter = fieldnames(preResults)' obj.(parameter{1}) = preParser.Results.(parameter{1}); end + + obj.derivatives = obj; end end - - function n = nargin(obj) - n = 1; - end - + function D = diff(obj, K) if nargin == 1 i = 1; end - + for i = 1:numel(K) - % create a new object for the derivative of obj: - D(:,i) = obj.copy(); - [D.name] = deal(['d/dt (' num2str(K(i)) ') ']); - [D.valueDiscrete] = deal([]); - for l = 1:numel(obj) - D(l,i).diffShift = D(l, 1).diffShift + K(i); + k = K(i); + + if size(obj.derivatives, 1) < k+1 || isempty(obj.derivatives(k+1,:)) + % create a new object for the derivative of obj: + D = obj.copy(); + [D.name] = deal(['d/dt (' num2str(k) ') ']); + [D.valueDiscrete] = deal([]); + for l = 1:numel(obj) + D(l).diffShift = D(l).diffShift + k; + end + obj.derivatives(k+1,:) = D; + D.valueDiscrete(); + else + D(:,i) = obj.derivatives(k+1,:); end end end @@ -126,6 +138,14 @@ function obj = BasicVariable(valueContinuous, varargin) b = obj.copy(); b.valueDiscrete = K / obj.K * obj.valueDiscrete(); b.K = K; + b.derivatives(1) = b; + for i = 2:numel(b.derivatives) + bi = b.derivatives(i).copy; + bi.valueDiscrete = K / obj.K * bi.valueDiscrete(); + bi.K = K; + b.derivatives(i) = bi; + end + end end diff --git a/+quantity/Discrete.m b/+quantity/Discrete.m index 4ca6aef..784dc04 100644 --- a/+quantity/Discrete.m +++ b/+quantity/Discrete.m @@ -5,10 +5,10 @@ classdef (InferiorClasses = {?quantity.Symbolic, ?quantity.SymbolicII}) Discret % Name of the domains that generate the grid. gridName {mustBe.unique}; - + % In this cell, already computed derivatives can be stored to avoid % multiple computations of the same derivative. - derivatives cell = {}; + derivatives; end properties (Hidden, Access = protected, Dependent) @@ -325,12 +325,12 @@ classdef (InferiorClasses = {?quantity.Symbolic, ?quantity.SymbolicII}) Discret % find the finest grid of all input quantities by comparing % gridSize for each iteratively. - if isempty(a) + if isempty(a) || isempty(a(1).grid) if nargin > 1 [referenceGrid, referenceGridName] = varargin{1}.getFinestGrid(varargin{2:end}); else referenceGrid = {}; - referenceGridName = ''; + referenceGridName = ''; end return; else diff --git a/+quantity/Function.m b/+quantity/Function.m index 0815054..5c7cc55 100644 --- a/+quantity/Function.m +++ b/+quantity/Function.m @@ -136,9 +136,7 @@ classdef Function < quantity.Discrete mObj = obj.copy(); for k = 1:numel(obj) - assert(isequal(obj(k).gridName, {'z'}), ['This only works for gridName == z, ', ... - 'otherwise valueContinuous is wrong']); - mObj(k).valueContinuous = @(z) - obj(k).valueContinuous(z); + mObj(k).valueContinuous = @(varargin) - obj(k).valueContinuous(varargin{:}); mObj(k).valueDiscrete = - obj(k).valueDiscrete; end diff --git a/+quantity/Operator.m b/+quantity/Operator.m index 4bdd04a..813e2e9 100644 --- a/+quantity/Operator.m +++ b/+quantity/Operator.m @@ -136,7 +136,7 @@ classdef Operator < handle & matlab.mixin.Copyable function C = adj(A) assert(A(1).coefficient.isConstant()) - C = misc.polynomial2coefficients(misc.adj(A.powerSeries), A(1).s); + C = polyMatrix.polynomial2coefficients(misc.adj(A.powerSeries), A(1).s); c = cell(1, size(C, 3)); for k = 1:size(C, 3) c{k} = quantity.Discrete(double(C(:,:,k)), ... @@ -149,7 +149,7 @@ classdef Operator < handle & matlab.mixin.Copyable assert(A(1).coefficient.isConstant()) C = det(A.powerSeries); - C = misc.polynomial2coefficients(C, A(1).s); + C = polyMatrix.polynomial2coefficients(C, A(1).s); c = cell(1, size(C, 3)); for k = 1:size(C, 3) c{k} = quantity.Discrete(double(C(:,:,k)), ... @@ -196,7 +196,7 @@ classdef Operator < handle & matlab.mixin.Copyable end function S = powerSeries(obj) - S = misc.powerSeries2Sum(squeeze(obj.M.on()), obj(1).s); + S =polyMatrix.powerSeries2Sum(squeeze(obj.M.on()), obj(1).s); end function A = ctranspose(obj) diff --git a/+signals/GevreyFunction.m b/+signals/GevreyFunction.m index 822a238..bc1b546 100644 --- a/+signals/GevreyFunction.m +++ b/+signals/GevreyFunction.m @@ -4,37 +4,45 @@ classdef GevreyFunction < quantity.BasicVariable properties % Gevrey-order - order double = -1; + order double = -1; end -properties (Dependent) - sigma; -end + properties (Dependent) + sigma; + end methods function obj = GevreyFunction(varargin) - obj@quantity.BasicVariable(@signals.gevrey.bump.g, varargin{:}); - prsr = misc.Parser(); - prsr.addParameter('order', 1.5 ); - prsr.parse(varargin{:}); - obj.order = prsr.Results.order; + + if nargin == 0 + g = []; + else + g = @signals.gevrey.bump.g; + end + obj@quantity.BasicVariable(g, varargin{:}); + if nargin > 0 + prsr = misc.Parser(); + prsr.addParameter('order', 1.5 ); + prsr.parse(varargin{:}); + obj.order = prsr.Results.order; + end end - function s = get.sigma(obj) - s = 1 ./ ( obj.order - 1); - end - function set.sigma(obj, s) - obj.order = 1 + 1/s; - end + function s = get.sigma(obj) + s = 1 ./ ( obj.order - 1); + end + function set.sigma(obj, s) + obj.order = 1 + 1/s; + end end methods (Access = protected) function v = evaluateFunction(obj, grid) v = obj.K * obj.valueContinuous(grid, obj.diffShift, obj.T, obj.sigma); - end + end end end diff --git a/+signals/PolyBump.m b/+signals/PolyBump.m index a306a3e..a385b85 100644 --- a/+signals/PolyBump.m +++ b/+signals/PolyBump.m @@ -4,6 +4,7 @@ classdef PolyBump < quantity.BasicVariable a double; b double; c double; + sgn double; end properties ( Access = protected, Hidden) @@ -12,31 +13,55 @@ classdef PolyBump < quantity.BasicVariable end methods - - function obj = PolyBump(varargin) + function obj = PolyBump(varargin) + % make default grid: + preParser = misc.Parser(); + preParser.addParameter('T', 1); + preParser.addParameter('N_t', 101); + preParser.addParameter('dt', []); + preParser.addParameter('z', linspace(0, 1)'); + preParser.parse(varargin{:}); + + if ~isempty(preParser.Results.dt) + Nt = quantity.BasicVariable.setDt(preParser.Results.T, preParser.Results.dt); + else + Nt = preParser.Results.N_t; + end + prsr = misc.Parser(); prsr.addParameter('a', 1); prsr.addParameter('b', 1); prsr.addParameter('c', 0); + prsr.addParameter('grid', {preParser.Results.z, linspace(0, preParser.Results.T, Nt)'}); + prsr.addParameter('gridName', {'z', 't'}); + prsr.addParameter('name', 'phi'); + prsr.addParameter('sgn', 1); + prsr.addParameter('T', preParser.Results.T); + prsr.addParameter('N_t', Nt); prsr.parse(varargin{:}); uargin = misc.struct2namevaluepair(prsr.Unmatched); + argin = [uargin(:)', ... + {'grid', prsr.Results.grid, ... + 'gridName', prsr.Results.gridName, ... + 'name', prsr.Results.name, ... + 'T', preParser.Results.T, ... + 'N_T', Nt}]; - obj@quantity.BasicVariable(@signals.polyBump, uargin{:}); + obj@quantity.BasicVariable(@signals.polyBump, argin{:}); obj.a = prsr.Results.a; obj.b = prsr.Results.b; obj.c = prsr.Results.c; + obj.sgn = prsr.Results.sgn; end - - - end methods (Access = protected) - function v = evaluateFunction(obj, grid) - v = obj.K * obj.valueContinuous(grid, obj.diffShift, obj.T, obj.a, obj.b, obj.c); + function v = evaluateFunction(obj, z, t) + v = obj.K * obj.valueContinuous( t + obj.sgn * obj.c * z, obj.diffShift, obj.T, obj.a, obj.b, obj.c); end + end end diff --git a/+signals/polyBump.m b/+signals/polyBump.m index 5f8b03a..8a9a29f 100644 --- a/+signals/polyBump.m +++ b/+signals/polyBump.m @@ -14,5 +14,5 @@ else end % restict the output to the considered domain -out = o .* ( t >= c & t <= (T-c) ); +out = o .* ( t >= c & t <= (T - c) ); end diff --git a/+unittests/signalsTest.m b/+unittests/signalsTest.m index 451365d..0a4a178 100644 --- a/+unittests/signalsTest.m +++ b/+unittests/signalsTest.m @@ -35,10 +35,15 @@ function testGevreyBump(testCase) % Test script to check if the class for the bumb function returns the right % signals. -g = quantity.BasicVariable(@signals.gevrey.bump.g, 'diffShift', 1); +g = signals.GevreyFunction('diffShift', 1); b = signals.gevrey.bump.dgdt_1(g.T, g.sigma, g.grid{1}) * 1 / signals.gevrey.bump.dgdt_0(g.T, g.sigma, g.T); %% Test scaling of Gevrey function verifyEqual(testCase, b, g.on(), 'AbsTol', 1e-13); +% test the derivatives of the bump +g = signals.GevreyFunction('diffShift', 0); +g.diff(0:5); + + end \ No newline at end of file -- GitLab