Creating a translator in MatLab - matlab

I am trying to create a simple program in Matlab where the user can input a string (such as "A", "B", "AB" or "A B") and the program will output a word corresponding to my letter.
Input | Output
A Hello
B Hola
AB HelloHola
A B Hello Hola
This is my code:
A='Hello'; B='Hola';
userText = input('What is your message: ', 's');
userText = upper(userText);
for ind = 1:length(userText)
current = userText(ind);
X = ['The output is ', current];
disp(X);
end
Currently I don't get my desired results. I instead get this:
Input | Output
A The output is A
B The output is B
I'm not totally sure why X = ['The output is ', current]; evaluates to The output is A instead of The output is Hello.
Edit:
How would this program be able to handle numbers... such as 1 = "Goodbye"

What's going on:
%// intput text
userText = input('What is your message: ', 's');
%// ...and some lines later
X = ['The output is ', userText];
You never map what you type to what is contained by the variables A and B.
The fact that they are called A and B has nothing to do with what you type. You could call them C and blargh and still get the same result.
Now, you could use eval, but that's really not advisable here. In this case, using eval would force the one typing in the strings to know the exact names of your variables...that's a portability, maintainability, security, etc. disaster waiting to happen.
There are better solutions possible, for instance, create a simple map:
map = {
'A' 'Hello'
'B' 'Hola'
'1' 'Goodbye'
};
userText = input('What is your message: ', 's');
str = map{strcmpi(map(:,1), userText), 2};
disp(['The output is ', str]);

I would recommend using a map object to contain what you want. This will circumvent the eval function (which I suggest avoiding like the plague). This is pretty simple to read and understand, and is pretty efficient especially in the case of a long input string.
translation = containers.Map()
translation('A') = 'Hola';
translation('B') = 'Hello';
translation('1') = 'Goodbye';
inputString = 'ABA1BA1B11ABBA';
resultString = '';
for i = 1:length(inputString)
if translation.isKey(inputString(i))
% get mapped string if it exists
resultString = [resultString,translation(inputString(i))];
else
% if mapping does not exist, simply put the input string in (covers space case)
resultString = [resultString,inputString(i)];
end
end

Take a look at the command eval. Currently, you are displaying the name of the variable that contains the string you want. eval will help you in actually accessing and printing it.

What you need to do it :
X = ['The output is ', eval(current)];
Here the documentation : eval

Related

How to print a chain of arrows with fprintf

I am looking for a way to set up the fprintf function so that it returns the string 1->2->...->n for any input n. However, I cannot find a way to do so without having an extra arrow attached at the beginning (->1->2->...->n) or the end of the string (1->2->...->n->). Is there a way around this?
You could use strjoin for this...
n = 4;
str = strjoin( arrayfun(#num2str, 1:n, 'uni', 0), '->' );
% str = '1->2->3->4'
Or if you're set on using fprintf (or sprintf), you could manually add the first element (for ease, assume n >= 1)
str = ['1', sprintf('->%.0f', 2:n )];
If you just want to print these to the Command Window, simply use disp on either option instead of (or after) assigning to str. If you're writing to a file with fprintf then simply use fprintf( fid, [str '\n'] ) to print the line to file.
For this type of task, the solution is to print either the first or the last element separately:
n = 8;
fprintf('%d', 1);
fprintf('->%d', 2:n);
fprintf('\n');
Here's another approach to build the desired string:
n = 10;
str = regexprep(num2str(1:n), '\s+', '->');
This gives
str =
'1->2->3->4->5->6->7->8->9->10'

Matlab: Compare strings in a for loop

I want to compare two strings from two structs. My Code is like below:
%matlab model scan
[variables] = Simulink.findVars('myModell');
variablesNames =[];
%save the names of all the variables in variablesNames
for t= 1:length(variables)
variablesNames(t).Name = variables(t).Name;
end
%scan workspace
for f = fieldnames(my_workspace)
found = false;
for c = 1:length(variablesNames)
if strcmp(f{c}, variablesNames(c))
found = true;
result = 'Found in Workspace: ';
end
if ~found
result = 'Not found inside Workspace';
end
end
disp(['Workspace Variable: ', sprintf('%-*s',40,f{c}), result]);
end
variablesNames is a struct 1x15 with 1 field
my_workspace is 1x1 struct with 20 fields
I got only one variable as return.
What is wrong in this code?
I don't really understand why are you creating a new struct here: variablesNames(t).Name, therefore I just removed that part.
The modified code just iterates through the variables struct-array and checks whether variable my_workspace has a field with the name of the value stored in the Name field of the currently processed element, using isfield.
[variables] = Simulink.findVars('myModell');
for i = 1:length(variables)
if isfield(my_workspace, variables(t).Name)
result = 'Found in Workspace: ';
else
result = 'Not found inside Workspace';
end
disp(['Workspace Variable: ', sprintf('%-*s', 40, variables(t).Name), result]);
end

Create a matrix from all the variable in the workspace starting with a specified name

For example, imagine that I've in my workspace 100 variables whoes names range from var_1 to var_100. Now I want to create a matrix using all the variable starting with the name 'var_'.
I know I could try to list all the variables, but that would be ineficient and long:
A = [var_1 var_2 ... var_100]
Is there a better way to do complish this?
While this is probably (most definitely) not a good idea, here is what you can do:
varstr = 'A = ['
for ii = 1:100
varstr = [varstr, ' var_', num2str(ii)];
end
varstr = [varstr, '];']
eval(varstr)
The eval function lets you execute a string of matlab code. Therefore, you just need to generate a string that constructs the array, then pass it to eval. Fortunately, this is pretty easy:
eval([ 'A = [' sprintf('var_%d, ', 1:100) ']']);
It might be a little clearer if you actually do the assignment outside of the eval, like so
A = eval([ '[' sprintf('var_%d, ', 1:100) ']']);
Note that the string here has an extra trailing comma. That doesn't seem to be a problem, at least on 2014b.
If you don't know the total number of variables, you can get them with the who command. This returns a cell array of strings, which you'd then reformat and pass to eval, like so
my_variables = who('var_*');
% You may want to sort (re-order, take a subset of) my_variables here
str_to_run = '['
for ii=1:length(my_variables)
str_to_run = [str_to_run, my_variables{ii}, ',']
end

Convert matlab symbol to array of products

Can I convert a symbol that is a product of products into an array of products?
I tried to do something like this:
syms A B C D;
D = A*B*C;
factor(D);
but it doesn't factor it out (mostly because that isn't what factor is designed to do).
ans =
A*B*C
I need it to work if A B or C is replaced with any arbitrarily complicated parenthesized function, and it would be nice to do it without knowing what variables are in the function.
For example (all variables are symbolic):
D = x*(x-1)*(cos(z) + n);
factoring_function(D);
should be:
[x, x-1, (cos(z) + n)]
It seems like a string parsing problem, but I'm not confident that I can convert back to symbolic variables afterwards (also, string parsing in matlab sounds really tedious).
Thank you!
Use regexp on the string to split based on *:
>> str = 'x*(x-1)*(cos(z) + n)';
>> factors_str = regexp(str, '\*', 'split')
factors_str =
'x' '(x-1)' '(cos(z) + n)'
The result factor_str is a cell array of strings. To convert to a cell array of sym objects, use
N = numel(factors_str);
factors = cell(1,N); %// each cell will hold a sym factor
for n = 1:N
factors{n} = sym(factors_str{n});
end
I ended up writing the code to do this in python using sympy. I think I'm going to port the matlab code over to python because it is a more preferred language for me. I'm not claiming this is fast, but it serves my purposes.
# Factors a sum of products function that is first order with respect to all symbolic variables
# into a reduced form using products of sums whenever possible.
# #params orig_exp A symbolic expression to be simplified
# #params depth Used to control indenting for printing
# #params verbose Whether to print or not
def factored(orig_exp, depth = 0, verbose = False):
# Prevents sympy from doing any additional factoring
exp = expand(orig_exp)
if verbose: tabs = '\t'*depth
terms = []
# Break up the added terms
while(exp != 0):
my_atoms = symvar(exp)
if verbose:
print tabs,"The expression is",exp
print tabs,my_atoms, len(my_atoms)
# There is nothing to sort out, only one term left
if len(my_atoms) <= 1:
terms.append((exp, 1))
break
(c,v) = collect_terms(exp, my_atoms[0])
# Makes sure it doesn't factor anything extra out
exp = expand(c[1])
if verbose:
print tabs, "Collecting", my_atoms[0], "terms."
print tabs,'Seperated terms with ',v[0], ', (',c[0],')'
# Factor the leftovers and recombine
c[0] = factored(c[0], depth + 1)
terms.append((v[0], c[0]))
# Combines trivial terms whenever possible
i=0
def termParser(thing): return str(thing[1])
terms = sorted(terms, key = termParser)
while i<len(terms)-1:
if equals(terms[i][1], terms[i+1][1]):
terms[i] = (terms[i][0]+terms[i+1][0], terms[i][1])
del terms[i+1]
else:
i += 1
recombine = sum([terms[i][0]*terms[i][1] for i in range(len(terms))])
return simplify(recombine, ratio = 1)

How do I retrieve the names of function parameters in matlab?

Aside from parsing the function file, is there a way to get the names of the input and output arguments to a function in matlab?
For example, given the following function file:
divide.m
function [value, remain] = divide(left, right)
value = floor(left / right);
remain = left / right - value;
end
From outside the function, I want to get an array of output arguments, here: ['value', 'remain'], and similarly for the input arguments: ['left', 'right'].
Is there an easy way to do this in matlab? Matlab usually seems to support reflection pretty well.
EDIT Background:
The aim of this is to present the function parameters in a window for the user to enter. I'm writing a kind of signal processing program, and functions to perform operations on these signals are stored in a subfolder. I already have a list and the names of each function from which the user can select, but some functions require additional arguments (e.g. a smooth function might take window size as a parameter).
At the moment, I can add a new function to the subfolder which the program will find, and the user can select it to perform an operation. What I'm missing is for the user to specify the input and output parameters, and here I've hit the hurdle here in that I can't find the names of the functions.
MATLAB offers a way to get information about class metadata (using the meta package), however this is only available for OOP classes not regular functions.
One trick is to write a class definition on the fly, which contain the source of the function you would like to process, and let MATLAB deal with the parsing of the source code (which can be tricky as you'd imagine: function definition line spans multiple lines, comments before the actual definition, etc...)
So the temporary file created in your case would look like:
classdef SomeTempClassName
methods
function [value, remain] = divide(left, right)
%# ...
end
end
end
which can be then passed to meta.class.fromName to parse for metadata...
Here is a quick-and-dirty implementation of this hack:
function [inputNames,outputNames] = getArgNames(functionFile)
%# get some random file name
fname = tempname;
[~,fname] = fileparts(fname);
%# read input function content as string
str = fileread(which(functionFile));
%# build a class containing that function source, and write it to file
fid = fopen([fname '.m'], 'w');
fprintf(fid, 'classdef %s; methods;\n %s\n end; end', fname, str);
fclose(fid);
%# terminating function definition with an end statement is not
%# always required, but now becomes required with classdef
missingEndErrMsg = 'An END might be missing, possibly matching CLASSDEF.';
c = checkcode([fname '.m']); %# run mlint code analyzer on file
if ismember(missingEndErrMsg,{c.message})
% append "end" keyword to class file
str = fileread([fname '.m']);
fid = fopen([fname '.m'], 'w');
fprintf(fid, '%s \n end', str);
fclose(fid);
end
%# refresh path to force MATLAB to detect new class
rehash
%# introspection (deal with cases of nested/sub-function)
m = meta.class.fromName(fname);
idx = find(ismember({m.MethodList.Name},functionFile));
inputNames = m.MethodList(idx).InputNames;
outputNames = m.MethodList(idx).OutputNames;
%# delete temp file when done
delete([fname '.m'])
end
and simply run as:
>> [in,out] = getArgNames('divide')
in =
'left'
'right'
out =
'value'
'remain'
If your problem is limited to the simple case where you want to parse the function declaration line of a primary function in a file (i.e. you won't be dealing with local functions, nested functions, or anonymous functions), then you can extract the input and output argument names as they appear in the file using some standard string operations and regular expressions. The function declaration line has a standard format, but you have to account for a few variations due to:
Varying amounts of white space or blank lines,
The presence of single-line or block comments, and
Having the declaration broken up on more than one line.
(It turns out that accounting for a block comment was the trickiest part...)
I've put together a function get_arg_names that will handle all the above. If you give it a path to the function file, it will return two cell arrays containing your input and output parameter strings (or empty cell arrays if there are none). Note that functions with variable input or output lists will simply list 'varargin' or 'varargout', respectively, for the variable names. Here's the function:
function [inputNames, outputNames] = get_arg_names(filePath)
% Open the file:
fid = fopen(filePath);
% Skip leading comments and empty lines:
defLine = '';
while all(isspace(defLine))
defLine = strip_comments(fgets(fid));
end
% Collect all lines if the definition is on multiple lines:
index = strfind(defLine, '...');
while ~isempty(index)
defLine = [defLine(1:index-1) strip_comments(fgets(fid))];
index = strfind(defLine, '...');
end
% Close the file:
fclose(fid);
% Create the regular expression to match:
matchStr = '\s*function\s+';
if any(defLine == '=')
matchStr = strcat(matchStr, '\[?(?<outArgs>[\w, ]*)\]?\s*=\s*');
end
matchStr = strcat(matchStr, '\w+\s*\(?(?<inArgs>[\w, ]*)\)?');
% Parse the definition line (case insensitive):
argStruct = regexpi(defLine, matchStr, 'names');
% Format the input argument names:
if isfield(argStruct, 'inArgs') && ~isempty(argStruct.inArgs)
inputNames = strtrim(textscan(argStruct.inArgs, '%s', ...
'Delimiter', ','));
else
inputNames = {};
end
% Format the output argument names:
if isfield(argStruct, 'outArgs') && ~isempty(argStruct.outArgs)
outputNames = strtrim(textscan(argStruct.outArgs, '%s', ...
'Delimiter', ','));
else
outputNames = {};
end
% Nested functions:
function str = strip_comments(str)
if strcmp(strtrim(str), '%{')
strip_comment_block;
str = strip_comments(fgets(fid));
else
str = strtok([' ' str], '%');
end
end
function strip_comment_block
str = strtrim(fgets(fid));
while ~strcmp(str, '%}')
if strcmp(str, '%{')
strip_comment_block;
end
str = strtrim(fgets(fid));
end
end
end
This is going to be very hard (read: impossible) to do for general functions (think of things like varargin, etc). Also, in general, relying on variable names as a form of documentation might be... not what you want. I'm going to suggest a different approach.
Since you control the program, what about specifying each module not just with the m-file, but also with a table entry with extra information. You could document the extra parameters, the function itself, notate when options are booleans and present them as checkboxes, etc.
Now, where to put this? I would suggest to have the main m-file function return the structure, as sort of a module loading step, with a function handle that points to the subfunction (or nested function) that does the real work. This preserves the single-file setup that I'm sure you want to keep, and makes for a much more configurable setup for your modules.
function module = divide_load()
module.fn = #my_divide;
module.name = 'Divide';
module.description = 'Divide two signals';
module.param(1).name = 'left';
module.param(1).description = 'left signal';
module.param(1).required_shape = 'columnvector';
% Etc, etc.
function [value, remain] = my_divide(left, right)
value = floor(left / right);
remain = left / right - value;
end
end
When you can't get information from a programming langauge about its contents (e.g., "reflection"), you have to step outside the language.
Another poster suggested "regular expressions", which always fail when applied to parsing real programs because regexps cannot parse context free langauges.
To do this reliably, you need a real M language parser, that will give you access to the parse tree. Then this is fairly easy.
Our DMS Software Reengineering Toolkit has an M language parser available for it, and could do this.
Have you considered using map containers?
You can write your functions along these lines . . .
function [outMAP] = divide(inMAP)
outMAP = containers.Map();
outMAP('value') = floor(inMAP('left') / inMAP('right'));
outMAP('remain') = inMAP('left') / inMAP('right') - outMAP('value');
end
...and call them like this ...
inMAP = containers.Map({'left', 'right'}, {4, 5});
outMAP = divide(inMAP);
...and then simply examine tha variable names using the following syntax...
>> keys(inMAP)
ans =
'left' 'right'
inputname(argnum) http://www.mathworks.com/help/techdoc/ref/inputname.html .