V_PARAMSETCH update and check parameter values p=(d,q,m,c,t) Usage: (1) function x=func(y,q) d=struct('a',1,'b',2,'c',3); % default parameters p=v_paramsetch(d,q); % update selected parameters (2) function x=func(y,q) d=struct('a',1,'b',2,'c',3); % default parameters c={'p.a>0 && p.a<5','Message 1';'p.b>0','b must be positive'}; p=v_paramsetch(d,q,'E',c); % check parameter ranges (3) t={'a','description of parameter a';'c','and of parameter c'} p=v_paramsetch(d,q,'l',c,t); % list values with optional descrpitions % '-','=','*','+' indicates default, unchanged, updated and new fields Inputs: d default parameter structure q new parameter values either a struct or alternatively matrix with each row being the value of the variables in the same order as the fields of d. If q is a matrix then all updated values will be row vectors with the same number of elements. m mode string: any combination of the following 'a' include additional fields in q that are not in d 'A' additional fields in q constitute an error 'e' print errors (but don't exit unless 'E' given as well) 'E' exit if there are any errors 'l' list fields and their values (default if no output) c cell array with parameter checking conditions (use p for structure name) and error message; one row per check. All results of command c{*,1) must be true. e.g. {'p.a>3' 'parameter a must be > 3'; 'p.b<2' 'parameter b must be < 2'} t cell array with descriptive text for each field in a new row. Either in the form t(:,*)={'field' 'description'} or a single column of descriptions in the same order as the fields of d Outputs: p output parameter structure Bugs/Suggestions: (1) When printing include "=" to show an updated parameter has not changed (might waste a lot of computation) (2) If input d has few entries, it would be faster to loop through d rather than q
0001 function p=v_paramsetch(d,q,m,c,t) 0002 %V_PARAMSETCH update and check parameter values p=(d,q,m,c,t) 0003 % Usage: (1) function x=func(y,q) 0004 % d=struct('a',1,'b',2,'c',3); % default parameters 0005 % p=v_paramsetch(d,q); % update selected parameters 0006 % 0007 % (2) function x=func(y,q) 0008 % d=struct('a',1,'b',2,'c',3); % default parameters 0009 % c={'p.a>0 && p.a<5','Message 1';'p.b>0','b must be positive'}; 0010 % p=v_paramsetch(d,q,'E',c); % check parameter ranges 0011 % 0012 % (3) t={'a','description of parameter a';'c','and of parameter c'} 0013 % p=v_paramsetch(d,q,'l',c,t); % list values with optional descrpitions 0014 % % '-','=','*','+' indicates default, unchanged, updated and new fields 0015 % 0016 % Inputs: 0017 % d default parameter structure 0018 % q new parameter values either a struct or alternatively matrix with 0019 % each row being the value of the variables in the same order as the 0020 % fields of d. If q is a matrix then all updated values will be row 0021 % vectors with the same number of elements. 0022 % m mode string: any combination of the following 0023 % 'a' include additional fields in q that are not in d 0024 % 'A' additional fields in q constitute an error 0025 % 'e' print errors (but don't exit unless 'E' given as well) 0026 % 'E' exit if there are any errors 0027 % 'l' list fields and their values (default if no output) 0028 % c cell array with parameter checking conditions (use p for structure name) and error 0029 % message; one row per check. All results of command c{*,1) must be true. 0030 % e.g. {'p.a>3' 'parameter a must be > 3'; 'p.b<2' 'parameter b must be < 2'} 0031 % t cell array with descriptive text for each field in a new row. Either in 0032 % the form t(:,*)={'field' 'description'} or a single column of 0033 % descriptions in the same order as the fields of d 0034 % 0035 % Outputs: 0036 % p output parameter structure 0037 % 0038 % Bugs/Suggestions: 0039 % (1) When printing include "=" to show an updated parameter has not changed (might waste a lot of computation) 0040 % (2) If input d has few entries, it would be faster to loop through d rather than q 0041 0042 % Copyright (C) Mike Brookes 2017 0043 % Version: $Id: v_paramsetch.m 10865 2018-09-21 17:22:45Z dmb $ 0044 % 0045 % VOICEBOX is a MATLAB toolbox for speech processing. 0046 % Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html 0047 % 0048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0049 % This program is free software; you can redistribute it and/or modify 0050 % it under the terms of the GNU General Public License as published by 0051 % the Free Software Foundation; either version 2 of the License, or 0052 % (at your option) any later version. 0053 % 0054 % This program is distributed in the hope that it will be useful, 0055 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0056 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0057 % GNU General Public License for more details. 0058 % 0059 % You can obtain a copy of the GNU General Public License from 0060 % http://www.gnu.org/copyleft/gpl.html or by writing to 0061 % Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA. 0062 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0063 p=d; % initialize output structure to the default values 0064 numerr=0; % initialize error count 0065 dn=fieldnames(d); % list of parameter default fields 0066 ndn=length(dn); % number of default parameter fields 0067 nq=0; % default value for size(q,1) 0068 % handle common case efficiently with 1 or 2 input arguments and an output argument 0069 if nargin<=2 && nargout>0 0070 if nargin==2 && numel(q)>0 % if update argument exists 0071 if isstruct(q) % if update argument is a structure 0072 qn=fieldnames(q); % field names to update 0073 nq=length(qn); % number of fields to update 0074 if nq<ndn % relatively few entries in q 0075 for i=1:nq % loop through list of fields to update 0076 fi=qn{i}; % get field name to update 0077 if isfield(p,fi); % is this an existing field ? 0078 p.(fi)=q.(fi); % set new field value 0079 end 0080 end 0081 else % more entries in q than in d 0082 for i=1:ndn % loop through list of existing fields 0083 fi=dn{i}; % get field name to potentially update 0084 if isfield(q,fi); % is there a replacement value for this field ? 0085 p.(fi)=q.(fi); % set new field value 0086 end 0087 end 0088 end 0089 else % else update argument is a matrix 0090 nq=size(q,1); % number of fields to update 0091 for i=1:min(nq,ndn) 0092 p.(dn{i})=q(i,:); 0093 end 0094 end 0095 end 0096 else % we have >2 arguments or else no output arguments 0097 % sort out input arguments 0098 if nargin<5 0099 t={'' ''}; % define an empty description array 0100 if nargin<4 0101 c=cell(0,2); % define an empty check condition array 0102 if nargin<3 0103 m=''; % define an empty check mode string 0104 end 0105 end 0106 end 0107 % now update the selected fields 0108 adderr=any(m=='A'); % new fields constitute an error 0109 addnew=any(m=='a'); % new fields should be added into p 0110 printerr=any(m=='e'); % print error messages 0111 numerr=0; % initialize count of errors 0112 if numel(q)>0 % if update argument is non-empty 0113 if isstruct(q) % if update argument is a structure 0114 qn=fieldnames(q); % field names to update 0115 nq=length(qn); % number of fields to update 0116 if addnew % we are including all fields in q(n) 0117 for i=1:nq % loop through list of fields to update 0118 fi=qn{i}; % get field name to update 0119 p.(fi)=q.(fi); % set new field value 0120 end 0121 else 0122 for i=1:length(qn) % loop through list of fields to update 0123 fi=qn{i}; % get field name to update 0124 if isfield(p,fi) % if this is an existing field ... 0125 p.(fi)=q.(fi); % set new field value 0126 elseif adderr % if this is an non-existant field ... 0127 numerr=numerr+1; % increment error count 0128 if printerr 0129 fprintf(2,'Unknown parameter: %s\n',fi); 0130 end 0131 end 0132 end 0133 end 0134 else % else update argument is a matrix 0135 nq=size(q,1); % number of fields to update 0136 for i=1:min(nq,ndn) 0137 p.(dn{i})=q(i,:); 0138 end 0139 if nq>ndn 0140 numerr=numerr+nq-ndn; 0141 if printerr 0142 if nq==ndn+1 0143 fprintf(2,'1 extra parameter specified\n'); 0144 else 0145 fprintf(2,'%d extra parameters specified\n',nq-ndn); 0146 end 0147 end 0148 end 0149 end 0150 end 0151 % Apply parameter checks 0152 if numel(c)>0 % check if any checks are specified 0153 for i=1:size(c,1) % one check per row of c 0154 if ~all(eval(c{i,1}),'all') % perform the check 0155 numerr=numerr+1; 0156 if size(c,1)==1 0157 fprintf(2,'Parameter check failed: %s\n',c{i}); 0158 else 0159 fprintf(2,c{i,2}); 0160 fprintf(2,'\n'); 0161 end 0162 end 0163 end 0164 end 0165 % print out a list of the parameters if requested 0166 if ~nargout || any(m=='l') 0167 fprintf('Key: - default value, = updated to default value, * updated to new value, + additional field\n'); 0168 pn=fieldnames(p); 0169 nf=length(pn); % length of updated structure 0170 st=size(t); 0171 for i=1:nf % loop through field in output p 0172 fi=pn{i}; % field name 0173 vi=p.(fi); % field value 0174 if i>ndn % if this field was added to structure d 0175 cat='+'; % new field 0176 else 0177 if nq>0 && isstruct(q) % if update argument is a structure 0178 if isfield(q,fi) % was this field updated ? 0179 if isequal(p.(fi),d.(fi)) 0180 cat='='; % updated to existing value 0181 else 0182 cat='*'; % updated to new value 0183 end 0184 else % not an updated field 0185 cat='-'; % not updated 0186 end 0187 else % if update argument is a matrix 0188 if i>nq % beyond list of updated fields 0189 cat='-'; % not updated 0190 else 0191 if isequal(p.(fi),d.(fi)) 0192 cat='='; % updated to existing value 0193 else 0194 cat='*'; % updated to new value 0195 end 0196 end 0197 end 0198 end 0199 if st(2)>1 % description are field-based 0200 jti=find(strcmp(fi,t(:,1)),1); % find description for this field 0201 if ~isempty(jti) 0202 jti=t{jti,2}; % description string 0203 end 0204 elseif i<=st(1) 0205 jti=t{i,1}; % description string 0206 else 0207 jti=[]; % empty description 0208 end 0209 if isnumeric(vi) && length(vi)==numel(vi) && isreal(vi) % can print vector on one line 0210 fit=fi; 0211 if size(vi,1)>1 0212 fit=[fi '''']; % transposed vector 0213 end 0214 fprintf('%3d%c %s:',i,cat,fit); 0215 fprintf(' %g',vi); 0216 if isempty(jti) 0217 fprintf('\n'); 0218 else 0219 fprintf(' = %s\n',jti); 0220 end 0221 elseif numel(vi)<6 0222 fprintf('%3d%c %s:',i,cat,fi); 0223 if isempty(jti) 0224 fprintf('\n'); 0225 else 0226 fprintf(' %s:\n',jti); 0227 end 0228 disp(vi); 0229 else 0230 fprintf('%3d%c %s: [large]',i,cat,fi); 0231 if isempty(jti) 0232 fprintf('\n'); 0233 else 0234 fprintf(' = %s\n',jti); 0235 end 0236 end 0237 end 0238 end 0239 if numerr>0 && any(m=='E') 0240 error('%d error%c in parameter specification',numerr,(' '+(numerr>1)*('s'-' '))); 0241 end 0242 end