Home > functions > internal > dsClassifyEquation.m

dsClassifyEquation

PURPOSE ^

CLASSIFYEQUATION - use regular expressions to classify model expressions in STRING

SYNOPSIS ^

function classes = dsClassifyEquation(string,delimiter, varargin)

DESCRIPTION ^

CLASSIFYEQUATION - use regular expressions to classify model expressions in STRING

 Usage:
 CLASS=dsClassifyEquation(STRING,DELIMITER)

 Inputs:
   - STRING
   - DELIMITER (optional character, default=';'): delimit expressions in STRING

 Output:
  -  CLASS (string or cell array of strings for each delimited expression):
     class:            format:
     parameter         name=value
     fixed_variable    name=expression/data
     function          name(inputs)=expression
     ODE               dx/dt or x' = expression
     IC                x(0)=values
     conditional       if(condition)(action) or if(condition)(action)else(action)
     monitor           monitor *   (previously: monitor name=expression)
     linker            {'+=','-=','*=','/='} ('=>'for backwards compatibility) {'>-','>+','>*',or '>\'}
     comment           % or #

 Notes:
 - Output "class" will be a cell array of strings if STRING contains
   multiple expressions; otherwise it will be a string.
 - This function is designed to be an internal helper function
   called by user-level functions in DynaSim.

 Examples:
   class=dsClassifyEquation('dx/dt=3*a*x')
   classes=dsClassifyEquation('dx/dt=3*a*x; x(0)=0')
   classes=dsClassifyEquation('dx/dt=3*a*x, x(0)=0',',')
   classes=dsClassifyEquation('a=2; b=2*a; f(x)=b; dx/dt=f(x); x(0)=0; if(x>1)(x=0); current=>f(x); monitor f(x); % comments')
   classes=dsClassifyEquation('model.eqns');

 See also: dsParseModelEquations

 Author: Jason Sherfey, PhD <jssherfey@gmail.com>
 Copyright (C) 2016 Jason Sherfey, Boston University, USA

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function classes = dsClassifyEquation(string,delimiter, varargin)
0002 %CLASSIFYEQUATION - use regular expressions to classify model expressions in STRING
0003 %
0004 % Usage:
0005 % CLASS=dsClassifyEquation(STRING,DELIMITER)
0006 %
0007 % Inputs:
0008 %   - STRING
0009 %   - DELIMITER (optional character, default=';'): delimit expressions in STRING
0010 %
0011 % Output:
0012 %  -  CLASS (string or cell array of strings for each delimited expression):
0013 %     class:            format:
0014 %     parameter         name=value
0015 %     fixed_variable    name=expression/data
0016 %     function          name(inputs)=expression
0017 %     ODE               dx/dt or x' = expression
0018 %     IC                x(0)=values
0019 %     conditional       if(condition)(action) or if(condition)(action)else(action)
0020 %     monitor           monitor *   (previously: monitor name=expression)
0021 %     linker            {'+=','-=','*=','/='} ('=>'for backwards compatibility) {'>-','>+','>*',or '>\'}
0022 %     comment           % or #
0023 %
0024 % Notes:
0025 % - Output "class" will be a cell array of strings if STRING contains
0026 %   multiple expressions; otherwise it will be a string.
0027 % - This function is designed to be an internal helper function
0028 %   called by user-level functions in DynaSim.
0029 %
0030 % Examples:
0031 %   class=dsClassifyEquation('dx/dt=3*a*x')
0032 %   classes=dsClassifyEquation('dx/dt=3*a*x; x(0)=0')
0033 %   classes=dsClassifyEquation('dx/dt=3*a*x, x(0)=0',',')
0034 %   classes=dsClassifyEquation('a=2; b=2*a; f(x)=b; dx/dt=f(x); x(0)=0; if(x>1)(x=0); current=>f(x); monitor f(x); % comments')
0035 %   classes=dsClassifyEquation('model.eqns');
0036 %
0037 % See also: dsParseModelEquations
0038 %
0039 % Author: Jason Sherfey, PhD <jssherfey@gmail.com>
0040 % Copyright (C) 2016 Jason Sherfey, Boston University, USA
0041 
0042 %% localfn output
0043 if ~nargin
0044   output = localfunctions; % output var name specific to this fn
0045   return
0046 end
0047 
0048 %% auto_gen_test_data_flag argin
0049 options = dsCheckOptions(varargin,{'auto_gen_test_data_flag',0,{0,1}},false);
0050 if options.auto_gen_test_data_flag
0051   varargs = varargin;
0052   varargs{find(strcmp(varargs, 'auto_gen_test_data_flag'))+1} = 0;
0053   varargs(end+1:end+2) = {'unit_test_flag',1};
0054   argin = [{string},{delimiter}, varargs]; % specific to this function
0055 end
0056 
0057 
0058 %% check inputs
0059 if nargin==1, delimiter=';'; end % set default delimiter
0060 
0061 if ~ischar(string) % error handling
0062   error('input must be string containing equations');
0063 end
0064 
0065 if exist(string,'file')
0066   % load equations from file and concatenate into a single string
0067   string=readtext(string);
0068   string=[string{:}]; % concatenate text from all lines
0069 end
0070 
0071 %% split string on delimiter; remove insignificant white space & delimiters
0072 %strings=strtrim(splitstr(string,delimiter));
0073 strings=strtrim(regexp(string,delimiter,'split'));
0074 strings=strrep(strings,delimiter,'');
0075 
0076 % classify each delimited expression in string
0077 classes=cell(1,length(strings));
0078 for i=1:length(strings)
0079   classes{i} = classify(strings{i}, varargin{:});
0080 end
0081 
0082 if length(classes)==1 % check for single expression
0083   classes=classes{1}; % return class label as string
0084 end
0085 
0086 %% auto_gen_test_data_flag argout
0087 if options.auto_gen_test_data_flag
0088   argout = {classes}; % specific to this function
0089 
0090   dsUnitSaveAutoGenTestData(argin, argout);
0091 end
0092 
0093 end % main fn
0094 
0095 
0096 %% local functions
0097 
0098 function class = classify(string, varargin)
0099 % input: string containing only one expression
0100 % output: class label (string)
0101 
0102 %% auto_gen_test_data_flag argin
0103 options = dsCheckOptions(varargin,{'auto_gen_test_data_flag',0,{0,1}},false);
0104 if options.auto_gen_test_data_flag
0105   varargs = varargin;
0106   varargs{find(strcmp(varargs, 'auto_gen_test_data_flag'))+1} = 0;
0107   varargs(end+1:end+2) = {'unit_test_flag',1};
0108   argin = [{string}, varargs]; % specific to this function
0109 end
0110 
0111 class='';
0112 
0113 if isempty(string)
0114   % null check
0115   class='null';
0116 elseif string(1)=='%' || string(1)=='#'
0117 % comment check
0118   class='comment';
0119 end
0120 
0121 % linker check: % [link ]? target operation expression
0122                 % DynaSim-linker (matlab-incompatible) character combinations
0123 pattern='(link\s*)?((\+=)|(\-=)|(\*=)|(/=)|(=>))';
0124 if isempty(class) && ~isempty(regexp(string,pattern,'once'))
0125   class='linker';
0126 end
0127 
0128 % ODE check: x'=expression or dx/dt=expression
0129 pattern='^((\w+'')|(d\w+/dt))\s*=';
0130 if isempty(class) && ~isempty(regexp(string,pattern,'once'))
0131   class='ODE';
0132 end
0133 
0134 % IC check: x(0)=expression
0135 pattern='^\w+\(0\)\s*=';
0136 if isempty(class) && ~isempty(regexp(string,pattern,'once'))
0137   class='IC';
0138 end
0139 
0140 % parameter check: var=expression (string or numeric)
0141 %pattern='^(([\w\.]+)|(\[\w+\]))\s*=\s*((''.*'')|(\[?[\d\.-(Inf)(inf)]+\]?))$';
0142 % TODO: support scientific notation
0143 pattern='^(([\w\.]+)|(\[\w+\]))\s*=\s*((''.*'')|(\[?[+\d\.\-(Inf)(inf)]+\]?)|(\d+e[\-\+]?\d+))$';
0144 if isempty(class) && ~isempty(regexp(string,pattern,'once'))
0145   class='parameter';
0146 end
0147 
0148 % conditional check: if(conditions)(actions)(else)
0149 pattern='^if\s*\(.+\)\s*\(.+\)';
0150 if isempty(class) && ~isempty(regexp(string,pattern,'once','ignorecase'))
0151   class='conditional';
0152 end
0153 
0154 % function check: f(vars)=exression
0155 pattern='^\w+\([@a-zA-Z][\w,@]*\)\s*=';
0156 if isempty(class) && ~isempty(regexp(string,pattern,'once'))
0157   class='function';
0158 end
0159 
0160 % monitor check:  monitor f=(expression or function)
0161 pattern='monitor .*';
0162 if isempty(class) && ~isempty(regexp(string,pattern,'once'))
0163   class='monitor';
0164 end
0165 
0166 % fixed_variable (with indexing) check: var(#), var([#]), var([# #]), var([#,#]), var(#:#), var(#:end), var([#:#]), var([#:end])
0167 pattern='^\w+\([\(\[?[\d\s,]+\]?\) | \(\[?\d+:[\(\d+\)|\(end\)]\]?\)]+\)'; % fixed with indexing: var(#), var([#]), var([# #]), var([#,#]), var(#:#), var(#:end), var([#:#]), var([#:end])
0168 if isempty(class) && ~isempty(regexp(string,pattern,'once'))
0169   class='fixed_variable';
0170 end
0171 
0172 % fixed_variable (without indexing) check: var=(expression with grouping or arithmetic)
0173 pattern='^((\w+)|(\[\w+\]))\s*=';
0174 if isempty(class) && ~isempty(regexp(string,pattern,'once'))
0175   pattern1='(.*[a-z_A-Z,<>(<=)(>=)]+.*)$'; % rhs contains: []{}(),<>*/|   % '=\s*.*[a-z_A-Z,<>(<=)(>=)]+.*'
0176   pattern2='=\s*\d+e[\-\+]?\d+$'; % scientific notation (should be classified as parameter, not fixed_variable)
0177   if ~isempty(regexp(string,pattern1,'once')) && ...
0178       isempty(regexp(string,pattern2,'once'))
0179     class='fixed_variable';
0180   end
0181 end
0182 
0183 if isempty(class)
0184   class='unclassified';
0185 end
0186 
0187 %% auto_gen_test_data_flag argout
0188 if options.auto_gen_test_data_flag
0189   argout = {class}; % specific to this function
0190 
0191   dsUnitSaveAutoGenTestDataLocalFn(argin, argout); % localfn
0192 end
0193 
0194 end %fn

Generated on Tue 12-Dec-2017 11:32:10 by m2html © 2005