How to transform multiple similar outputs into a single output array? - arrays

I have two issues that I desperately need help with, so I'm posting here.
I know this may sound like a much-asked question at first, but I didn't find anything like it in my research.
I'm trying to obtain an entire row of results, using this code:
mu = [0 0];
sigma = [1 0.3; 0.3 1];
for r1 = 1:7;
r2 = 1;
xu = [r1+1, r2+1];
xl = [r1, r2];
p1 = mvncdf(xl,xu,mu,sigma)
end
What I am trying to say is that, for every value that r1 takes (between 1 and 7), r2 will assume the value 1, and I want to generate the values for those 7 combinations. When I run the scripts, I get excatly the values that I want, but in this form:
p1 =
0.0301
p1 =
0.0062
p1 =
4.5904e-04
p1 =
1.2186e-05
p1 =
1.1389e-07
p1 =
3.7054e-10
p1 =
4.1622e-13
After that, when I go to my workspace, I have a variable there named p1, but is only equal to the last value generated - in this case, 4.1622e-13. Is it possible to make this generate an array with all the 7 numbers instead?
My second question is related to this one. As you saw, I use r1 ranging from 1 to 7, and r2 takes the value of 1. Truth is, I want to assess all combinations of them, with r2 also ranging from 1 to 7, but I'm doing it manually, with 7 other similar pieces of code, each one for a value of r2. Is it possible to combine everything and code it in a way that it generates a matrix of values based on all the combinations? I understand that might be more difficult, and I am more concerned with the first question.

For you first question, you want to create a vector of p1 values, so just modify your code like this:
p1(r1) = mvncdf(xl,xu,mu,sigma)
which when r1=1, the first time you loop, will put the result into the first element of p1 and so on.
For the second part of your question, you can nest another for loop, as follows:
for r1 = 1:7;
for r2 = 1:7;
xu = [r1+1, r2+1];
xl = [r1, r2];
p1(r1,r2) = mvncdf(xl,xu,mu,sigma)
end
end
and now you will have a matrix p1 where, for example, the entry in the (4,6) position corresponds to r1=4 and r2=6.
It is possible to compress this,
r1=1:7;
r2=1:7;
[R1,R2]=meshgrid(r1,r2);
p1=arrayfun(#(r1,r2) mvncdf([r1 r2],[r1+1 r2+1],mu,sigma),R1,R2)
but there is no real need to do so.

Related

Multiply elements in second column according to labels in the first

I'm working in Matlab.
I have a two-dimensional matrix with two columns. Lets consider elements in the first column as labels. Labels may be repeated.
How to multiply all elements in the second column for every label?
Example:
matrix = [1,3,3,1,5; 2,3,7,8,3]'
I need to get:
a = [1,3,5; 16,21,3]'
Can you help me with doing it without for-while cycles?
I would use accumarray. The preprocessing with unique assigns integer indices 1:n to the values in the first row, which allow accumarray to work without creating unnecessary bins for 2 and 4. It also enables the support for negative numbers and floats.
[ulable,~,uindex]=unique(matrix(:,1))
r=accumarray(uindex,matrix(:,2),[],#prod)
r=[ulable,r]
/You can also use splitapply:
[ulable,~,uindex]=unique(matrix(:,1))
r=splitapply(#prod,matrix(:,2),uindex)
r=[ulable,r]
You can do it without loops using accumarray and the prod function:
clear
clc
matrix = [1,3,3,1,5; 2,3,7,8,3]';
A = unique(matrix,'rows');
group = A(:,1);
data = A(:,2);
indices = [group ones(size(group))];
prods = accumarray(indices, data,[],#prod); %// As mentionned by #Daniel. My previous answer had a function handle but there is no need for that here since prod is already defined in Matlab.
a = nonzeros(prods)
Out = [unique(group) a]
Out =
1 16
3 21
5 3
Check Lauren blog's post here, accumarray is quite interesting and powerful!
Try something like this, I'm sure it can be improved...
unValues = unique(matrix(:,1));
bb = ones(size(unValues));
for ii = 1:length(unValues)
bb(ii) = bb(ii)*prod(matrix(matrix(:, 1) == unValues(ii), 2));
end
a = [unValues bb];

Create a matrix with a changing number of columns

I'm trying to do an homemade version of peakfinder.m, by making it work with multiple arrays instead of just one at a time, for more time efficient performance. (http://www.mathworks.com/matlabcentral/fileexchange/25500-peakfinder)
I have a 2D matrix where I need to find if the sign changes in the 2nd dimension.
dx0 = diff(x0,1,2); % Find derivative
dx0(dx0 == 0) = -eps; % This is so we find the first of repeated values
ind = find(dx0(:,1:end-1).*(dx0(:,2:end)) < 0)+1; % Find where the derivative changes sign
Now my problem is that it does find where the derivative changes sign, but it is one big vector. So if the signs changes twice in the same row (or doesn't in a row), I have no way to find out.
So if x0 is of size 1000x10, I'd like ind to be of size 1000xY, where Y is the number of times it changes sign in EACH row. I also need to know at which values of x0 there is a sign change. So each row will be in the style of :
2 4 7
4 8
2 5 6 8
etc.
Is this possible at all? Or should I change the code so it places a 0 if it doesn't change and a 1 if it does change, considering I'll be working with the values where it changes?
cellfun approach -
b1 = padarray(sign(dx0(:,1:end-1))~=sign(dx0(:,2:end)),[0 1],'pre')
out = cellfun(#find,mat2cell(b1,ones(1,size(b1,1)),size(b1,2)),'uni',0)
The above code assumes you have padarray which seems like a recent addition to MATLAB's Image Processing Toolbox. So, if you don't have it, you can concatenate zeros (with false) like this -
b1 = sign(dx0(:,1:end-1))~=sign(dx0(:,2:end))
b1 = [false(size(b1,1),1) b1]
out = cellfun(#find,mat2cell(b1,ones(1,size(b1,1)),size(b1,2)),'uni',0)
Alternative solution using cellfun with nonzeros function -
b1 = padarray(sign(dx0(:,1:end-1))~=sign(dx0(:,2:end)),[0 1],'pre')
out = cellfun(#nonzeros,mat2cell(bsxfun(#times,b1,1:size(b1,2)),ones(1,size(b1,1)),size(b1,2)),'uni',0)
out contains the locations of sign change across the rows, which can be displayed using celldisp(out).
The counts of the sign changes can be calculated using -
counts = cellfun(#numel,out)

Fortran select a vector by indicating its name

In a program coded in F90, I have a set of 11 vectors, each of a size (7), with names going from "S1" to "S11".
I need to be able to read a number of elements from one vector, by giving the name of this latter.
Although this problem seems an elementary one, with my beginner level, I am unable to find a way to code it...
any help ?
When a Fortran program executes it doesn't really have the information available to identify a variable based on the value of a string containing the name of a variable. You could write a sequence of if statements such as
if (mystr=='S1') x = s1
if (mystr=='S2') x = s2
...
You could pretty this up a bit with a select case construction
select case (mystr)
case ('S1')
x = s1
case ('S2')
x = s2
...
but that may not appeal much more.
A better approach by far would be to declare your vectors as elements of a rank-2 array:
real, dimension(11,7) :: s
and you can then do all sorts of computations, at run-time, to select the vector you want
myrow = an_expression_returning_an_integer_between_1_and_11_inclusive
x = s(myrow,:)

Dynamically creating and naming an array

Consider the following code snippet
for i = 1:100
Yi= x(i:i + 3); % i in Yi is not an index but subscript,
% x is some array having sufficient values
i = i + 3
end
Basically I want that each time the for loop runs the subscript changes from 1 to 2, 3, ..., 100. SO in effect after 100 iterations I will be having 100 arrays, starting with Y1 to Y100.
What could be the simplest way to implement this in MATLAB?
UPDATE
This is to be run 15 times
Y1 = 64;
fft_x = 2 * abs(Y1(5));
For simplicity I have taken constant inputs.
Now I am trying to use cell based on Marc's answer:
Y1 = cell(15,1);
fft_x = cell(15,1);
for i = 1:15
Y1{i,1} = 64;
fft_x{i,1} = 2 * abs(Y1(5));
end
I think I need to do some changes in abs(). Please suggest.
It is impossible to make variably-named variables in matlab. The common solution is to use a cell array for Y:
Y=cell(100,1);
for i =1:100
Y{i,1}= x(i:i+3);
i=i+3;
end
Note that the line i=i+3 inside the for-loop has no effect. You can just remove it.
Y=cell(100,1);
for i =1:100
Y{i,1}= x(i:i+3);
end
It is possible to make variably-named variables in matlab. If you really want this do something like this:
for i = 1:4:100
eval(['Y', num2str((i+3)/4), '=x(i:i+3);']);
end
How you organize your indexing depends on what you plan to do with x of course...
Yes, you can dynamically name variables. However, it's almost never a good idea and there are much better/safer/faster alternatives, e.g. cell arrays as demonstrated by #Marc Claesen.
Look at the assignin function (and the related eval). You could do what asked for with:
for i = 1:100
assignin('caller',['Y' int2str(i)],rand(1,i))
end
Another related function is genvarname. Don't use these unless you really need them.

How to remove repetitions using retract in this particular situation?

%Examples:
%days([saturday,sunday,monday,tuesday,wednesday,thursday]).
%slots([1,2,3,4,5]).
%course_meetings(csen402,tutorial,t07,nehal,'tutorial for t07').
%course_meetings(comm401,lecture,all_group_4,dr_amr_talaat,'lecture 1')
%tutorialrooms([c6301,b4108,c2201,c2301,c2202,c2203]).
day_tut(Day,Slot,Place,Course,Group,Instructor,Descr):-
days(X),member(Day,X),
tutorialrooms(X1),member(Place,X1),
course_meetings(Course,tutorial,Group,Instructor,Descr),
slots(X2),member(Slot,X2),
assert(day(Day,Slot,tutorial,Place,Course,Group,Instructor,Descr)).
I would like to find a way to remove certain facts after asserting for example
every (day) fact has to have only one room for each day and slot
example: we can have day(sat,1,_,c6301,_,_,_,_) and
day(sat,1,_,c6302,_,_,_,_) but we can't have
another occurrence of day(sat,1,_,c6301,_,_,_,_).
If you simply want to remove redundant solutions of a Goal – this is what you probably mean with removing repetitions – simply replace Goal by setof(t,Goal,_). This works as long as there are only ground solutions for Goal and as long as Goal terminates universally. Thus, there is no need for any data base manipulation to remove redundant solutions.
?- member(X, [a,b,a,c]).
X = a
; X = b
; X = a % redundant!
; X = c.
?- setof(t,member(X, [a,b,a,c]),_).
X = a
; X = b
; X = c.

Resources