How do I create a vector that accepts strings? - matlab

Ok the problem is, I want to receive mathematical functions. And I won't know how many until the program runs.
When it runs i ask for an n number of functions i am going to receive and it starts saving them from the input.
So far I have this
function test()
n = input('number of equations?');
v = [1:n]
%in an ideal world, this ^ here would allow me to put a string in each position but
% they are not the same type and I understand that.. but how can I build a vector for saving my functions
%I want a vector where I can put strings in each position that is what I need
for i=1:n
x = input('what is the function?','s');
v(i)=x
end
v
%this would be my vector already changed with a function in each position.
end

When you want to store strings of different lengths, use cell arrays:
v = cell(1,n);
for i=1:n
v{i} = input('what is the function?','s'); #% note the curly braces
end
To use these as functions, use str2func:
for i=1:n
fh{i} = str2func(v{i});
end
fh is now a cell array containing handles to the functions defined by the user-input strings.

Related

How do I adjust this code so that I can enter how many runs I want and it will store each run in a matrix?

I have created this code to generate a 1 set of lottery numbers, but I am trying to make it so that the user can enter how many sets they want (input n), and it will print out as one long matrix of size nX6? I was messing around with a few options from online suggestions, but to no avail. I put the initial for i=1:1:n at the beginning, but I do not know how to store each run into a growing matrix. Right now it still generates just 1 set.
function lottery(n)
for i=1:1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
m=1;
lottonum1=floor(ylow+rand*(yhigh-ylow+1));
z = horzcat(lottonum, lottonum1);
end
disp('The lotto numbers picked are')
fprintf('%g ',z)
disp (' ')
The problem is that you are not storing or displaying the newly generated numbers, only the last set. To solve this, initialize z with NaNs or zeros, and later index z to store each set in a row of z, by using z(i,:) = lottonum.
However, you are using i as iterator in the while loop already, so you should use another variable, e.g. k.
You can also set z as an output of the function, so you can use this matrix in some other part of a program.
function z = lottery(n)
% init z
z = NaN(n,6);
for k = 1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
lottonum1 = floor(ylow+rand*(yhigh-ylow+1));
z(k,:) = horzcat(lottonum, lottonum1); % put the numbers in a row of z
end
disp('The lotto numbers picked are')
disp(z) % prettier display than fprintf in this case.
disp (' ')
end
The nice answer from rinkert corrected your basic mistakes (like trying to modify your loop iterator i from within the loop => does not work), and answered your question on how to store all your results.
This left you with a working code, however, I'd like to propose to you a different way to look at it.
The porposed architecture is to divide the tasks into separate functions:
One function draw_numbers which can draw N numbers randomly (and does only that)
One function draw_lottery which call the previous function as many times as it needs (your n), collect the results and display them.
draw_lottery
This architecture has the benefit to greatly simplify your main function. It can now be as simple as:
function Draws = draw_lottery(n)
% define your draw parameters
xmin = 1 ; % minimum number drawn
xmax = 69 ; % maximum number drawn
nballs = 5 ; % number of number to draw
% pre allocate results
Draws = zeros( n , nballs) ;
for iDraw=1:1:n
% draw "nballs" numbers
thisDraw = draw_numbers(xmin,xmax,nballs) ;
% add them to the result matrix
Draws(iDraw,:) = thisDraw ;
end
disp('The lotto numbers picked are:')
disp (Draws)
disp (' ')
end
draw_numbers
Instead of using a intricated set of if conditions and several iterators (i/m/k) to branch the program flow, I made the function recursive. It means the function may have to call itself a number of time until a condition is satisfied. In our case the condition is to have a set of nballs unique numbers.
The function:
(1) draws N integer numbers randomly, using randi.
(2) remove duplicate numbers (if any). Using unique.
(3) count how many unique numbers are left Nu
(4a) if Nu = N => exit function
(4b) if Nu < N => Call itself again, sending the existing Nu numbers and asking to draw an additional N-Nu numbers to add to the collection. Then back to step (2).
in code, it looks like that:
function draw = draw_numbers(xmin,xmax,nballs,drawn_set)
% check if we received a partial set
if nargin == 4
% if yes, adjust the number of balls to draw
n2draw = nballs - numel(drawn_set) ;
else
% if not, make a full draw
drawn_set = [] ;
n2draw = nballs ;
end
% draw "nballs" numbers between "xmin" and "xmax"
% and concatenate these new numbers with the partial set
d = [drawn_set , randi([xmin xmax],1,n2draw)] ;
% Remove duplicate
drawn_set = unique(d) ;
% check if we have some more balls to draw
if numel(drawn_set) < nballs
% draw some more balls
draw = draw_numbers(xmin,xmax,nballs,drawn_set) ;
else
% we're good to go, assign output and exit funtion
draw = drawn_set ;
end
end
You can have both functions into the same file if you want.
I encourage you to look at the documentation of a couple of Matlab built-in functions used:
randi
unique

Printing multiple disp functions with one for loop

So, I have a series of display functions, ranging from x1 to x7. These all contain both strings and variables like:
x1 = ['The result of the scalar multiplication of V and U: ',num2str(scalar_uv)];
x2 = similar to above but with for example a value on the cross multiplication of the two scalars.
Instead of printing out each one through:
disp(x1);
disp(x2);
disp(x3);
I thought it would be possible to print them all out through a for loop or perhaps a nested for loop but I just can't figure out how to do it. I preferably don't want straight up solutions (I won't say no to them) but rather some hints or tips of possible.
A simple example solution would be to make a cell array and loop through it, or use celldisp() to display it. But if you want to print nicely, i.e. formatted specifically, to the command window you can use the fprintf function and format in line breaks. For example:
for displayValue = {x1, x2, x3, x4}
fprintf('%s\n', displayValue{1});
end
If you want more formatting options, such as precision, or fieldwidth, the formatspec code (%s in the example) has many configurations. You can see them on the fprintf helpdoc. The \n just tells the fprintf function to create a newline when it prints.
Instead of creating seven different variables (x1...x7), just create a cell array to hold all your strings:
x{1} = ['The result of the scalar multiplication of V and U: ',num2str(scalar_uv)];
x{2} = ['Some other statement with a value at the end: ',num2str(somevar)];
Now you can write a loop:
for iX = 1:length(x)
disp(x{iX})
end
Or use cellfun to display them without a for loop:
cellfun(#disp,x)
If you really want to keep them named x1...x7, then you can use an eval statement to get your variable names:
for iX = 1:7
disp(eval(['x' num2str(iX)]));
end

Defining a function with multiple outputs that can't be organised into a matrix

Is there any natural way to define a MATLAB function with multiple outputs that cannot or are inappropriate to "stack" into a matrix? For example, what if I want a function f that returns a 3x3 matrix A and a 4x4 matrix B?
I'm really surprised that this would even be an issue in MATLAB. Because in Python, all we need to do is return A, B which returns a tuple of the two. However it seems that MATLAB doesn't quite support the idea of containers. As a non-elegant workaround, I can use a struct to put the two pieces of data in, and the function goes something like:
function re = f(x)
%f: returns two dimensional-inconsistent matrices A and B
% function body as follows
....
A = ...;
B = ...;
% put data into the struct 're'
re.A = A;
re.B = B;
end
Apart from possible performance issues, this approach looks very unnatural and clumsy. Is there any better approach?
In MATLAB you can return any number of outputs with this syntax:
function [A,B] = f(x)
A = ...;
B = ...;
end
that is an even elegant solution than tuples used in python.
You can even control the behavior with the number of inputs and outputs (nargin and nargout) and discard outputs with a tilde. More information here.
I cannot think of a more elegant syntax.
Usually when having several outputs, one should declare the function as follows:
function [out1, out2, ... , outN] = funcName(in1,...,inM)
...
end
MATLAB also allows you to alter the behavior of your function based on the amount of requested inputs/outputs via the nargin/nargout functions, respectively (you can think of this as a form of overloading).
For example, you can specify as one of the inputs an array indicating which outputs you want the function to give, then populate the varargout cell array accordingly:
function varargout = funcName(in1,...,whichOut)
...
for indO = 1:numel(whichOut)
switch whichOut{indO}
case 'out1'
varargout{indO} = out1;
case 'out2'
... etc
case 'out6'
varargout{indO} = out6;
end
end
then call it using [out6, out1] = funcName(inp, {'out6','out1'});
See also varargin.

How to convert cell variable to classified variable inside of parfor loop in matlab? [duplicate]

I have this (quite long) Matlab code with nested loops where I want to parallelize the main time-consuming iteration. The only variable that (apparently) gives me problems is DMax, where I get the error:
Error: The variable DMax in a `parfor` cannot be classified.
See Parallel for Loops in MATLAB, "Overview".
This is a draft of my code:
t0=matrix (Maxiter,1); % This is a big matrix whose dimensions are reported in brachets
Maxiter = 1E6;
DMax = zeros(Maxiter,40);
% Other Stuff
for j=1:269
% Do more stuff
for soil=1:4
parfor i =1:Maxiter
k(i,soil) = a %k is a real number
a(i,soil) = b %similar to k
% Do a lot of stuff
for t= (floor(t0(i,soil))+1):40
DMax(i,t) = k(i,soil)*((t-t0(i,soil))^a(i,soil));
% Do some more stuff
end
end
end
end
for time=1:40
% Do the final stuff
end
I guess the problem is in the way I defined DMax, but I do not know what it could be more precisely. I already looked on the web but with not very satisfying results.
It is very clearly described in the documentation that each variable inside parfor must be classified into one of several types. Your DMax variable should be a sliced variable (arrays whose segments are operated on by different iterations of the loop), but in order to be classified as such, all the following conditions must hold:
Type of First-Level Indexing — The first level of indexing is either parentheses, (), or braces, {}.
Fixed Index Listing — Within the first-level parenthesis or braces, the list of indices is the same for all occurrences of a
given variable.
Form of Indexing — Within the list of indices for the variable, exactly one index involves the loop variable.
Shape of Array — The array maintains a constant shape. In assigning to a sliced variable, the right-hand side of the assignment cannot be [] or '', because these operators attempt to
delete elements.
Clearly, Fixed Index Listing property does not hold since you reference it as DMax(i,t) where t changes its values. There's an identical example described in the documentation, please pay attention. So one workaround would be to use a temporary variable inside the inner loop, and then assign the whole row back to DMax.
Also note that variable a cannot be classified into any category either. That's not to mention that it's not defined in your example at all. Please read the guide carefully and make sure it can be classified into one of the categories. Rewrite the code if needed, e.g. introducing new temporary variables.
Here's the code where DMax usage is corrected:
Maxiter = 1E6;
t0 = randn(Maxiter,1); % This is a big matrix whose dimensions are reported in brachets
DMax = zeros(Maxiter,40);
% Other Stuff
for j = 1:269
% Do more stuff
for soil = 1:4
parfor i = 1:Maxiter
k(i,soil) = a %k is a real number
a(i,soil) = b %similar to k
% Do a lot of stuff
tmp = zeros(1,40);
for t = (floor(t0(i,soil))+1):40
tmp(t) = k(i,soil)*((t-t0(i,soil))^a(i,soil));
% Do some more stuff
end
DMax(i,:) = tmp;
end
end
end
for time = 1:40
% Do the final stuff
end

Flip order of elements function in MATLAB R2011a

I am using MATLAB version R2011a, a friend of mine is using R2014b which contains the function "Flip", which flips the order of elements, this function is vital to our program that compares Matrix'es.
My problem is R2011a does not have this function, it has fliplr,flipud and flipdim. I have tried using fliplr and then flipud to try and recreate the same function but eventually it doesn't work since i'm using the function corr which requires using that it's two arguments be the same dimensions.
I need advise on how to create the flip function that is available on R2014b.
The function that is problematic:
%This function gets the DNA signiture with the relative freq of each perm at
%the refernce text, the DNA signiture with the relative freq of each perm at
%the compare text, and the MaxPerm, and return the relative editor distance
%between the 2 texts.
function [distance]=EditorDistance2 (RefDNAWithFreq,CmpDNAWithFreq,MaxPerm)
if MaxPerm>2
MaxPerm=2;
end
str='Editor Distance compare begun';
disp(str);
distance=[];
for PermLength=1:MaxPerm
freq=sum(0:PermLength);
PermInitial=freq+1;
permEnd=freq+PermLength;
%create an ordered matrix of all the perms with length "PermLength"
%in the ref text
CurRefPerms=RefDNAWithFreq(:,freq:permEnd);
OrderedRefCurPerms=sortrows(CurRefPerms);
OrderedRefCurPerms=flip(OrderedRefCurPerms);
OrderedRefCurPerms(:,1)=[];
OrderedRefCurPerms=ZeroCutter(OrderedRefCurPerms);
%create an ordered matrix of all the perms with length "PermLength"
%in the cmp text
CurcmpPerms=CmpDNAWithFreq(:,freq:permEnd);
OrderedCmpCurPerms=sortrows(CurcmpPerms);
OrderedCmpCurPerms=flip(OrderedCmpCurPerms);
OrderedCmpCurPerms(:,1)=[];
OrderedCmpCurPerms=ZeroCutter(OrderedCmpCurPerms);
len1=size(OrderedRefCurPerms,1);
len2=size(OrderedCmpCurPerms,1);
edit=1;
matrix=zeros(len2,len1);
%initiate first row of the first stirng
for i=2:len1
matrix(1,i)=matrix(1,i-1)+1;
end
%initiate first column of the second stirng
for i=2:len2
matrix(i,1)=matrix(i-1,1)+1;
end
%start algoritem
for i=2:len2
for j=2:len1
if OrderedRefCurPerms(j-1,:)==OrderedCmpCurPerms(i-1,:)
edit=0;
end
if (i>2 & j>2 & OrderedRefCurPerms(j-1,:)==OrderedCmpCurPerms(i-2,:) & RefDNAWithFreq(j-2)==CmpDNAWithFreq(i-1) )
matrix(i,j)= min([matrix(i-1,j)+1,... deletion
matrix(i,j-1)+1,... insertion
matrix(i-2,j-2)+1,... substitution
matrix(i-1,j-1)+edit... transposition
]);
else
matrix(i,j) = min([matrix(i-1,j)+1,... deletion
matrix(i,j-1)+1,... insertion
matrix(i-1,j-1)+edit... substitution
]);
end
edit=1;
end
end
%The Distance is the last elment of the matrix.
if i~=1
tempdistance = matrix( floor( len2 / 3 ) , floor( len1 / 3 ) );
tempdistance=tempdistance/floor(len2/3);
else
tempdistance = matrix( len2,len1 );
tempdistance= tempdistance/len2;
end
tempdistance=1-tempdistance;
distance=[distance tempdistance];
end
end
I will further explain myself, the function which I am trying to use is A=flip(A)
The function that causes me problems is this one
%This function gets the DNA signiture with the relative freq of each perm at
%the refernce text, the DNA signiture with the relative freq of each perm at
%the compare text, and the MaxPerm, and return the corralation between the 2 texts.
function [Corvector]=CorrelationCompare(RefDNAWithFreq,CmpDNAWithFreq,MaxPerm)
str='corraltion compare begun';
disp(str);
%this vector will contain the corralation between the freqs of
%each perms vector(each length)
Corvector=[];
for PermLength=1:MaxPerm
freq=sum(0:PermLength);
PermInitial=freq+1;
permEnd=freq+PermLength;
%Cor is correlation between the 2 texts
refPerms=RefDNAWithFreq(:,freq);
cmpPerms=CmpDNAWithFreq(:,freq);
refPerms=ZeroCutter(refPerms);
cmpPerms=ZeroCutter(cmpPerms);
tempCor=corr(refPerms,cmpPerms);
Corvector =[Corvector tempCor];
% making a graph of the perms, and the relative freq of the texts.
x=ZeroCutter ( RefDNAWithFreq(:,PermInitial:permEnd) );
y1=refPerms;
y2=cmpPerms;
xchars=char(x);
Xcols=size(x,1);
o=ones(Xcols,1);
xco=mat2cell(xchars,o,PermLength);
xaxis=(1:Xcols);
figure
stem(xaxis,y1,'r');
hold
stem(xaxis,y2,'g');
set(gca,'XTick',xaxis)
set(gca,'XTickLabel',xco,'fontname','david');
xlabel('Perms');
ylabel('Perm frequency');
TitleOfGraph=sprintf('comapre between reference text to the compared, %d letters perm\n correlation=%f',PermLength,Corvector(PermLength));
legend('reference','compared');
title(TitleOfGraph);
end
end
The Error that I recieve when using a diffrent flip command is
??? Error using ==> corr at 102
X and Y must have the same number of rows.
Error in ==> CorrelationCompare at 27
tempCor=corr(refPerms,cmpPerms);
I apologize for the long codes but it's hard to explain it all since it's a big project and a lot of it was done by my partner
This should work for you -
function out = flip_hacked(A,dim)
%// Get an array of all possible dimensions
dims = 1:ndims(A);
%// Interchange first dimension and dim
dims(dim) = 1;
dims(1) = dim;
A1 = permute(A,[dims]);
%// Reshape A1 into a 2D matrix and then flip along the first dimension,
%// which would correspond to the flipping along dim and then interchange dim
%// and first dim again to keep the size of data same as input and elements
%// being flipped along dim for the desired output
A2 = reshape(A1,size(A1,1),[]);
out = permute(reshape(A2(end:-1:1,:),size(A1)),dims);
return;
It follows the same syntax as the official flip function that's stated in the official documentation as follows -
B = flip(A,dim) reverses the order of the elements in A along
dimension dim. For example, if A is a matrix, then flip(A,1) reverses
the elements in each column, and flip(A,2) reverses the elements in
each row.
In addition to the generic solution provided by Divakar you could simply use:
flip = #(A) A(end:-1:1, :);
A = flip(A);
To reverse the elements in each column of a matrix A. Even simpler:
A = A(end:-1:1, :);