You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

236 lines
7.7 KiB

%CCODEFUNCTIONSTRING Converts a symbolic expression into a C-code function
%
% [FUNSTR, HDRSTR] = ccodefunctionstring(SYMEXPR, ARGLIST) returns a string
% representing a C-code implementation of a symbolic expression SYMEXPR.
% The C-code implementation has a signature of the form:
%
% void funname(double[][n_o] out, const double in1,
% const double* in2, const double[][n_i] in3);
%
% depending on the number of inputs to the function as well as the
% dimensionality of the inputs (n_i) and the output (n_o).
% The whole C-code implementation is returned in FUNSTR, while HDRSTR
% contains just the signature ending with a semi-colon (for the use in
% header files).
%
% Options::
% 'funname',name Specify the name of the generated C-function. If
% this optional argument is omitted, the variable name
% of the first input argument is used, if possible.
% 'output',outVar Defines the identifier of the output variable in the C-function.
% 'vars',varCells The inputs to the C-code function must be defined as a cell array. The
% elements of this cell array contain the symbolic variables required to
% compute the output. The elements may be scalars, vectors or matrices
% symbolic variables. The C-function prototype will be composed accoringly
% as exemplified above.
% 'flag',sig Specifies if function signature only is generated, default (false).
%
% Example::
% % Create symbolic variables
% syms q1 q2 q3
%
% Q = [q1 q2 q3];
% % Create symbolic expression
% myrot = rotz(q3)*roty(q2)*rotx(q1)
%
% % Generate C-function string
% [funstr, hdrstr] = ccodefunctionstring(myrot,'output','foo', ...
% 'vars',{Q},'funname','rotate_xyz')
%
% Notes::
% - The function wraps around the built-in Matlab function 'ccode'. It does
% not check for proper C syntax. You must take care of proper
% dimensionality of inputs and outputs with respect to your symbolic
% expression on your own. Otherwise the generated C-function may not
% compile as desired.
%
% Author::
% Joern Malzahn, (joern.malzahn@tu-dortmund.de)
%
% See also ccode, matlabFunction.
% Copyright (C) 2012-2014, by Joern Malzahn
%
% This file is part of The Robotics Toolbox for Matlab (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB. If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com
function [funstr hdrstr] = ccodefunctionstring(f,varargin)
% option defaults
opt.funname = inputname(1);
opt.output{1} = zeros(size(f));
opt.outputName{1} = inputname(1);
opt.flag = 0;
if isempty(opt.outputName{1})
opt.outputName{1} = 'myout';
end
opt.vars = {};
% tb_optparse is not applicable here,
% since handling cell inputs and extracting input variable names is
% required.
% Thus, scan varargin manually:
if mod(nargin,2)==0
error('CodeGenerator:codefunctionstring:wrongArgumentList',...
'Wrong number of elements in the argument list.');
end
for iArg = 1:2:nargin-1
switch lower(varargin{iArg})
case 'funname'
opt.funname = varargin{iArg+1};
case 'output'
if ~isempty(varargin{iArg+1})
opt.outputName{1} = varargin{iArg+1};
end
case 'vars'
opt.vars = varargin{iArg+1};
case 'flag'
opt.flag = varargin{iArg+1};
otherwise
error('ccodefunctionstring:unknownArgument',...
['Argument ',inputname(iArg),' unknown.']);
end
end
nOut = numel(opt.output);
nIn = numel(opt.vars);
%% Function signature
funstr = sprintf('void %s(', opt.funname);
initstr = '';
% outputs
for iOut = 1:nOut
tmpOutName = opt.outputName{iOut};
tmpOut = opt.output{iOut};
if ~isscalar(tmpOut);
funstr = [funstr, sprintf('double %s[][%u]', tmpOutName, size(tmpOut,1) ) ];
for iRow = 1:size(tmpOut,1)
for iCol = 1:size(tmpOut,2)
initstr = sprintf(' %s %s[%u][%u]=0;\n',initstr,tmpOutName,iCol-1,iRow-1);
end
end
else
funstr = [funstr, sprintf('double %s', tmpOutName ) ];
end
% separate argument list by commas
if ( iOut ~= nOut ) || ( nIn > 0 )
funstr = [funstr,', '];
end
end
% inputs
for iIn = 1:nIn
tmpInName = ['input',num2str(iIn)];%opt.varsName{iIn};
tmpIn = opt.vars{iIn};
% treat different dimensionality of input variables
if isscalar(tmpIn)
funstr = [funstr, sprintf('const double %s', tmpInName ) ];
elseif isvector(tmpIn)
funstr = [funstr, sprintf('const double* %s', tmpInName ) ];
elseif ismatrix(tmpIn)
funstr = [funstr, sprintf('const double %s[][%u]', tmpInName, size(tmpIn,2) ) ];
else
error('ccodefunctionstring:UnsupportedOutputType', 'Unsupported datatype for %s', tmpOutName)
end
% separate argument list by commas
if ( iIn ~= nIn )
funstr = [funstr,', '];
end
end
funstr = [funstr,sprintf('%s', ')')];
% finalize signature for the use in header files
if nargout > 1
hdrstr = [funstr,sprintf('%s', ';')];
end
if opt.flag
return; %% STOP IF FLAG == TRUE
end
% finalize signature for use in function definition
funstr = [funstr,sprintf('%s', '{')];
funstr = sprintf('%s\n%s',funstr,sprintf('%s', ' ') ); % empty line
%% Function body
% input paramter expansion
for iIn = 1:nIn
tmpInName = ['input',num2str(iIn)];%opt.varsName{iIn};
tmpIn = opt.vars{iIn};
% for scalars
% -> do nothing
% for vectors
if ~isscalar(tmpIn) && isvector(tmpIn)
nEl = numel(tmpIn);
for iEl = 1:nEl
funstr = sprintf('%s\n%s',...
funstr,...
sprintf(' double %s = %s[%u];', char(tmpIn(iEl)), tmpInName,iEl-1 ));
end
% for matrices
elseif ~isscalar(tmpIn) && ~isvector(tmpIn) && ismatrix(tmpIn)
nRow = size(tmpIn,1);
nCol = size(tmpIn,2);
for iRow = 1:nRow
for iCol = 1:nCol
funstr = sprintf('%s\n%s',...
funstr,...
sprintf(' double %s%u%u = %s[%u][%u];', char(tmpIn(iRow,iCol)), iRow, iCol, tmpInName{iIn},iRow-1,iCol-1 ));
end
end
end
end
funstr = sprintf('%s\n%s',...
funstr,...
sprintf('%s', ' ') );
funstr = sprintf('%s\n%s',...
funstr,...
sprintf('%s\n\n', initstr) );
% Actual code
% use f.' here, because of column/row indexing in C
eval([opt.outputName{1}, ' = f.''; codestr = ccode(',opt.outputName{1},');'])
if isscalar(f)
% in the case of scalar expressions the resulting ccode always
% begins with ' t0'. Replace that with the desired name.
codestr(1:4) = [];
codestr = [opt.outputName{1}, codestr];
end
funstr = sprintf('%s\n%s',...
funstr,...
codestr );
funstr = sprintf('%s\n%s',...
funstr,sprintf('%s', '}') );
funstr = sprintf('%s\n%s',...
funstr,sprintf('%s', ' ') ); % empty line