function [ sim , coor ] = smartconvert ( func , cla , p1 , p2 )
% Derives number of dimensions (variables) of given function
% (class - inline , symbolic or char) then tries to find a set of
% coordinates that function has simple relations between variables or finds
% the coordinates that function has less variables. See "p1" comments. This is
% done in two (cartesian or polar) or three (cartesian or cylandrical or
% spherical) dimensions. The output also contain an extra parameter that
% shows the result coordinates and you can choose the out put function
% class type (inline , symbolic or char). See "cla" comments. The function
% also can be used manually. See "p1" comments. Some of usual change of
% coordinate are provided that can be used manually. See "p2" comments.
%
% Clarification: If you choose 'S' for p1: When someone wants to integrate
% ( ( x ^ 2 ) + ( y ^ 2 ) + ( z ^ 2 ) ) dx dy dz. It is more simpler that
% integrate in spherical coordinates with integrand ( r ^ 2 ) ( r ^ 2 sin
% ( theta )dr d( theta )d( phi ) ). This program tries to find and convert
% functions like this. If you choose 'L' for p1: When someone wants to
% use del operator on ( ( x ^ 2 ) + ( y ^ 2 ) + ( z ^ 2 ) ). It is more
% simpler that work in spherical coordinates with ( r ^ 2 ) and use
% spherical del operator. This program tries to find and convert functions
% like this. The two case of code using aren't the same always. See
% examples of the code.
%
% function [ sim , coor ] = smartconvert ( func , cla , p1 , p2 )
%
% arguments: ( input )
% func - ( class - inline , symbolic or char ) - a function of two or
% three variables
%
% cla - ( class - char ) - desired output class type
%
% p1 - ( class - char ) - specifier of code procedure less variables: 'L'
% or simple relation: 'S' or manual: 'M'
%
% p2 - ( class - char ) - specifier of code manual coordinates conversion
% including all conversions between cartesian and polar in two dimensions
% and between cartesian and cylindrical and spherical in three dimensions
%
% arguments: ( returned )
% sim - ( class - inline , symbolic or char as user desired ) - New function,
% converted to simpler shape in two or three dimensions
%
% coor - ( class - char ) the output coordinates
%
% Example:
% (1)
% W = inline ( ' s * cos ( t ) * tan ( e ) ' , ' s ' ,' t ' , ' e ' ) ;
% [ simp , coord ] = smartconvert ( W , 'sym' , 'L')
% simp =
% A*tan(B)
% coord =
% Cartesian
%
% (2)
% W = inline ( ' s * cos ( t ) * tan ( e ) ' , ' s ' ,' t ' , ' e ' ) ;
% [ simp , coord ] = smartconvert ( W , 'sym' , 'S')
% simp =
% C*B/A
% coord =
% Cartesian
%
% See also simple.
%
% Copyright 2008
%
% Requirement: symbolic math toolbox
% check for simple errors
if nargin < 3 || isempty ( p1 ) % checks the number of inputs
p1 = 'S' ;
end % end of if loop
if p1 == 'M'
if nargin == 3
error 'must determine the result coodinates.'
end % end of if loop
end % end of if loop
if nargin < 2 || isempty ( cla ) % checks the number of inputs
cla = char ( class ( func ) ) ; % if the user doesn't want to change the out put class type he/she can just enter one input argument
end % end of if loop
cl1 = class ( func ) ; % determines the class of given function
cl = char ( cl1 ) ; % converts the class of given function to charcter class
if strcmp ( cl , 'inline' ) % if the class of input function just saves the class
end % end of if loop
if strcmp ( cl , 'sym' ) % if the class of input function was symbolic converts it to class inline
func = inline ( func ) ; % converts the class of given function from symbolic to inline
end % end of if loop
if strcmp ( cl , 'char' ) % if the class of input function was char converts it to class inline
func = inline ( func ) ; % converts the class of given function from char to inline
end % end of if loop
arg1 = argnames ( func ) ; % returns the matrix of input function arguments names
lengarg1 = length ( arg1 ) ; % returns the length of matrix of input function arguments names
func = sym ( func ) ; % converts the class of given function from inline to symbolic
alph = 'a' : 'z' ; % creates a string from a to z alphabetic letters
EU = 0 ; % preallocating
if lengarg1 < 27 % checks that the number of arguments of given function is less than 27
for nu = 1 : lengarg1 % a loop that converts all alphabetic letters from class char to class symbolic
var = sym ( alph ( nu ) ) ; % converts all alphabetic letters from class char to class symbolic
func = subs ( func , arg1 ( nu ) , var ) ; % substitutes all alphabetic variables in the given function for simplicity
end % end of for loop
end % end of if loop
if lengarg1 == 2
syms A B a b % creates symbolic variables
CO ( 1 ) = ( A ) ;
CO ( 2 ) = ( B ) ;
CO ( 3 ) = ( A ) ;
CO ( 4 ) = ( B ) ;
CO ( 5 ) = ( A ) .* cos ( B ) ; % creates x variable from polar coordinates
CO ( 6 ) = ( A ) .* sin ( B ) ; % creates y variable from polar coordinates
CO ( 7 ) = sqrt ( ( A .^ 2 ) + ( B .^ 2 ) ) ; % creates rho variable from cartesian coordinates
CO ( 8 ) = atan ( B ./ A ) ; % creates phi variable from cartesian coordinates
FU = sym ( '0' ) ;
for mu = 1 : 2 : 7
FU ( mu ) = subs ( func , a , CO ( ( ( ( ( mu + 1 ) / 2 ) - 1 ) * 2 ) + 1 ) ) ;
FU ( mu ) = subs ( FU ( mu ) , b , CO ( ( ( ( ( mu + 1 ) / 2 ) - 1 ) * 2 ) + 2 ) ) ;
FU ( mu + 1 ) = subs ( func , a , CO ( ( ( ( ( mu + 1 ) / 2 ) - 1 ) * 2 ) + 2 ) ) ;
FU ( mu + 1 ) = subs ( FU ( mu + 1 ) , b , CO ( ( ( ( ( mu + 1 ) / 2 ) - 1 ) * 2 ) + 1 ) ) ;
end
Fs = simple ( FU ) ; % simplifies the result function row vector
end % end of if loop
if lengarg1 == 3
syms A B C a b c % creates symbolic variables
CO ( 1 ) = ( A ) ; % creates x variable in cartesian coordinates from cylindrical coordinates
CO ( 2 ) = ( B ) ; % creates y variable in cartesian coordinates from cylindrical coordinates
CO ( 3 ) = ( C ) ; % creates z variable in cartesian coordinates from cylindrical coordinates
CO ( 4 ) = ( A ) ; % creates x variable in cartesian coordinates from cylindrical coordinates
CO ( 5 ) = ( B ) ; % creates y variable in cartesian coordinates from cylindrical coordinates
CO ( 6 ) = ( C ) ; % creates z variable in cartesian coordinates from cylindrical coordinates
CO ( 7 ) = sqrt ( ( A .^ 2 ) + ( B .^ 2 ) ) ; % creates r variable from cartesian coordinates
CO ( 8 ) = atan ( B ./ A ) ; % creares theta variable from cartesian cooadinates
CO ( 9 ) = C ; % creates phi variable from cartesian coordinates
CO ( 10 ) = sqrt ( ( A .^ 2 ) + ( B .^ 2 ) + ( C .^ 2 ) ) ; % creates r variable from cartesian coordinates
CO ( 11 ) = atan ( sqrt ( ( A .^ 2 ) + ( B .^ 2 ) ) ./ C ) ; % creares theta variable from cartesian cooadinates
CO ( 12 ) = atan ( B ./ A ) ; % creates phi variable from cartesian coordinates
CO ( 13 ) = ( A ) .* cos ( B ) ; % creates x variable in cartesian coordinates from cylindrical coordinates
CO ( 14 ) = ( A ) .* sin ( B ) ; % creates y variable in cartesian coordinates from cylindrical coordinates
CO ( 15 ) = C ; % creates z variable in cartesian coordinates from cylindrical coordinates
CO ( 16 ) = sqrt ( ( A .^ 2 ) + ( C .^ 2 ) ) ; % creates r variable from cartesian coordinates
CO ( 17 ) = atan ( A ./ C ) ; % creares theta variable from cartesian cooadinates
CO ( 18 ) = B ; % creates phi variable from cartesian coordinates
CO ( 19 ) = ( A ) .* sin ( C ) .* cos ( B ) ; % creates x variable in cartesian coordinates from cylindrical coordinates
CO ( 20 ) = ( A ) .* sin ( C ) .* sin ( B ) ; % creates y variable in cartesian coordinates from cylindrical coordinates
CO ( 21 ) = ( A ) .* cos ( C ) ; % creates z variable in cartesian coordinates from cylindrical coordinates
CO ( 22 ) = ( A ) .* sin ( C ) ; % creates x variable in cartesian coordinates from cylindrical coordinates
CO ( 23 ) = ( B ) ; % creates y variable in cartesian coordinates from cylindrical coordinates
CO ( 24 ) = ( A ) .* cos ( C ) ; % creates z variable in cartesian coordinates from cylindrical coordinates
FU = sym ( '0' ) ; % preallocating
for mu = 1 : 6 : 43
FU ( mu ) = subs ( func , a , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 1 ) ) ;
FU ( mu ) = subs ( FU ( mu ) , b , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 2 ) ) ;
FU ( mu ) = subs ( FU ( mu ) , c , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 3 ) ) ;
FU ( mu + 1 ) = subs ( func , a , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 1 ) ) ;
FU ( mu + 1 ) = subs ( FU ( mu + 1 ) , b , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 3 ) ) ;
FU ( mu + 1 ) = subs ( FU ( mu + 1 ) , c , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 2 ) ) ;
FU ( mu + 2 ) = subs ( func , a , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 2 ) ) ;
FU ( mu + 2 ) = subs ( FU ( mu + 2 ) , b , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 3 ) ) ;
FU ( mu + 2 ) = subs ( FU ( mu + 2 ) , c , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 1 ) ) ;
FU ( mu + 3 ) = subs ( func , a , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 2 ) ) ;
FU ( mu + 3 ) = subs ( FU ( mu + 3 ) , b , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 1 ) ) ;
FU ( mu + 3 ) = subs ( FU ( mu + 3 ) , c , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 3 ) ) ;
FU ( mu + 4 ) = subs ( func , a , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 3 ) ) ;
FU ( mu + 4 ) = subs ( FU ( mu + 4 ) , b , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 1 ) ) ;
FU ( mu + 4 ) = subs ( FU ( mu + 4 ) , c , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 2 ) ) ;
FU ( mu + 5 ) = subs ( func , a , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 3 ) ) ;
FU ( mu + 5 ) = subs ( FU ( mu + 5 ) , b , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 2 ) ) ;
FU ( mu + 5 ) = subs ( FU ( mu + 5 ) , c , CO ( ( ( ( ( ( ( mu + 2 ) / 3 ) + 1 ) / 2 ) - 1 ) * 3 ) + 1 ) ) ;
end
Fs = simple ( FU ) ; % simplifies the result function row vector
end % end of if loop
ST = [ ] ; % preallocating of length string row vector
Fi = inline ( Fs ) ; % converts the result function row vector from class symbolic to class inline
Fc = char ( Fi ) ; % converts the result function row vector from class inline to class char
NU = strfind ( Fc , ' ') ; % finds the spaces in the string tha shows that the length of each function
for nu = 1 : length ( NU ) - 1 % i is the numerator of for loop
ST ( nu + 1 ) = NU ( nu + 1 ) - NU ( nu ) ; % a row vector that shows the lenght of each function
end % end of for loop
ST ( 1 ) = NU ( 1 ) ; % first element of S vector
if p1 == 'S'
[ MIN , MI ] = min ( ST ) ; % finds the function that has more simple relation between variables
elseif p1 == 'L'
for i = 1 : length ( Fs )
EU ( i ) = length ( argnames ( inline ( Fs ( i ) ) ) ) ; % finds the function that has less variables
end % end of if loop
[ MIN , MI ] = min ( EU ) ;
end % end of if loop
if p1 == 'M'
if lengarg1 == 2 % used for two dimensional case
if strcmp ( p2 , 'pol2cart' )
MI = 5 ;
elseif strcmp ( p2 , 'cart2pol' )
MI = 7 ;
end % end of if loop
end % end of if loop
if lengarg1 == 3 % used for three dimensional case
if strcmp ( p2 , 'cart2cyl' ) % converts the input function from cartesian to cylindrical
MI = 25 ;
elseif strcmp ( p2 , 'cart2sph' ) % converts the input function from cartesian to spherical
MI = 37 ;
elseif strcmp ( p2 , 'cyl2sph' ) % converts the input function from cylindrical to spherical
MI = 42 ;
elseif strcmp ( p2 , 'cyl2cart' ) % converts the input function from cylindrical to cartesian
MI = 13 ;
elseif strcmp ( p2 , 'sph2cart' ) % converts the input function from spherical to cartesian
MI = 19 ;
elseif strcmp ( p2 , 'sph2cyl' ) % converts the input function from spherical to cylindrical
MI = 31 ;
end % end of if loop
end % end of if loop
end % end of if loop
simsym = Fs ( MI ) ; % finds the result function in class symbolic
final = inline ( simsym ) ; % converts the result function from class symbolic to class inline
if strcmp( cla , 'inline') % if the user wants the result in class inline the output is in class inline
sim = final ;
end % end of if loop
if strcmp( cla , 'char') % if the user wants the result in class char converts the output from class inline to class char
sim = char ( final ) ; % converts returned function to class - char
end % end of if loop
arg2 = argnames ( final ) ; % creates the column vector of output variables
lengarg2 = length ( arg2 ) ; % counts the number of output variables
if strcmp( cla , 'sym') % if the user wants the result in class symbolic converts the output from class inline to class symbolic
alpha = 'A' : 'Z' ; % creates a string from A to Z alphabetic letters
if lengarg2 < 27 % checks that the number of arguments of given function is less than 27
for nu = 1 : lengarg2 % a loop that converts all alphabetic letters from class char to class symbolic
var = sym ( alpha ( nu ) ) ; % converts all alphabetic letters from class char to class symbolic
sim = subs ( final , arg2 ( nu ) , var ) ; % substitutes all alphabetic variables in the given function for simplicity
end % end of for loop
end % end of if loop
end % end of if loop
if lengarg1 == 2 % used for two dimensional case
if MI < 5 % if there is no change in the output from input shows it to user
coor = 'Same with input function' ;
elseif MI < 9 % if the output is in polar cordinates shows it to user
coor = 'Cartesian' ;
elseif MI < 13 % if the output is in cartesian cordinates shows it to user
coor = 'Polar' ;
end % end of if loop
end % end of if loop
if lengarg1 == 3 % used for three dimensional case
if MI < 13 % if there is no change in the output from input shows it to user
coor = 'Same with input function' ;
elseif MI < 25 % if the output is in cartesian cordinates shows it to user
coor = 'Cartesian' ;
elseif MI < 37 % if the output is in cylindrical cordinates shows it to user
coor = 'Cylindrical' ;
elseif MI < 49 % if the output is in spherical cordinates shows it to user
coor = 'Spherical' ;
end % end of if loop
end % end of if loop
% With special thanks to John D'Errico
% By Ali Mohammad Razeghi