Caching result of pre-computed function in Matlab - matlab

I have two arrays, x and y. x is the input of the function and y is the function values.
For example, x = [ 1 2 3 4 5 6 7 8 9 10], y = [ 3 6 2 4 1 6 7 0 1 8 ]. Both are the same length.
Suppose I have an another array z containing [ 2 3 8 9 10 3] (not the same length as x and y),
Is there any functions that produce the output [6 2 0 1 8 2] (return value at corresponding indices) without using for-loop through each element of array?
Thank you so much
edit1* How can I do if the numbers in the arrays are not integer?

y(z)
That's all you need......

I think that you just want:
y(z);
This will return the z'th elements of the y vector. You may want
y(x(z));
Which will return the same result in your example, since x is just the value 1 through 10.
With both of these z can contain only positive integers, and in the second case x must also contain only positive integers.

If you are using a MATLAB version newer than 2008b, you can use the containers.Map class to do what you want, even with non-integer, non-consecutive or non-numeric values:
x = [ 1 2 3 4 5 6 7 8 9 10];
y = [ 3 6 2 4 1 6 7 0 1 8 ];
z = [ 2 3 8 9 10 3];
F = containers.Map(x,y);
% for a single element:
Fz1 = F(z(1))
% for multiple elements at the same time, you need to use arrayfun
Fz = arrayfun(#(x)(F(x)),z)
The Map class actually creates a so-called hashmap, so you can map almost any value to other values (e.g. strings, cells, array, ...).
When the item is not present, it will return an error.
If you cannot use MATLAB 2008b or newer, there are three possibilities for non-integer domain values.
Use an interpolation method such as interp1. That might give false values (at values that weren't provided beforehand). You can check for that case by using ismember(z, x).
Secondly, you could invent your own scheme from non-integers to integers (e.g. if all your values are multiples of 0.5, multiply by 2) and use the solution Oli has shown.
The other solution is to use structs to mimic the behavior of a map. Then you only need a conversion from your domain values to valid field names (i.e. strings that are valid variable names in MATLAB, that may be possible by using the genvarname function).
These last two solutions are somewhat dirty and prone to errors if you don't take rounding into consideration. So I see them only as a last resort.

Related

Matlab: How to create a CDF array

I am fairly new to Matlab and am trying to learn for school. I have created a vector of values with fixed differences between consecutive values. E.g. A = [1 2.5 4 5.5 7 8.5 10 ...].
I also have another vector of random values, e.g. B = [3 7 1 2 3 4 8 0 ...].
I want to create a new vector of the same size of A, which has numbers indicating the number of values in B which are less than or equal to each value in A.
In this example, C = [2 3 6 6 7 8 ...]
Thanks in advance!
Context: I am working on a CDF function
You can use bsxfun() to implement element-wise comparisons between arrays:
C = sum( bsxfun(#le, B', A) )
Here we're passing bsxfun() the "less than or equal to" function handle, #le . This produces a length(B) by length(A) logical array. We simply sum down the rows to get the total number of TRUE's.

matrix of objects' array properties

I have an array of classes (we'll call it a, size Mx1) that contains a property (feature) which holds a 1xN array. I'm trying to get a new matrix that is MxN which contains rows of each of the feature property of the objects. For example:
M = 3
N = 4
a(1,1).feature = [1 2 3 4]
a(2,1).feature = [5 6 7 8]
a(3,1).feature = [9 10 11 12]
then, given some function, the answer would end up as:
ans = [1 2 3 4; 5 6 7 8; 9 10 11 12]
Currently, I've been using the following:
ans = cell2mat({a.feature}')
however I feel there should be a way to do this without having to convert to a cell, switch the dimensions, and then convert to a matrix. Am I correct or would this be the best way to solve the issue? I haven't been able to find any such function in the documentation.
When you have an array of objects and you access a property using dot referencing, a comma separated list is returned. This comma separated list can be passed to a function and will appear as multiple input arguments.
In your case, you can pass this comma separated list to cat and specify that you want each value to be concatenated to the next along the first dimension. So this would simply become:
features = cat(1, a.feature)
%// 1 2 3 4
%// 5 6 7 8
%// 9 10 11 12
This is functionally equivalent to:
features = cat(1, a(1).feature, a(2).feature, a(3).feature, ..., a(end).feature);

Merge two matrix and find the maximum of its attributes

I've two matrix a and b and I'd like to combine the rows in a way that in the first row I got no duplicate value and in the second value, columns in a and b which have the same row value get the maximum value in new matrix. i.e.
a = 1 2 3
8 2 5
b = 1 2 5 7
2 4 6 1
Desired output
c = 1 2 3 5 7
8 4 5 6 1
Any help is welcomed,please.( the case for accumulation is asked here)
Accumarray accepts functions both anonymous as well as built-in functions. It uses sum function as default. But you could change this to any in-built or anonymous functions like this:
In this case you could use max function.
in = horzcat(a,b).';
[uVal,~,idx] = unique(in(:,1));
out = [uVal,accumarray(idx,in(:,2),[],#max)].'
Based upon your previous question and looking at the help file for accumarray, which has this exact example.
[ii, ~, kk] = unique([a(1,:) b(1,:)]);
result = [ ii; accumarray(kk(:), [a(2,:) b(2,:)], [], #max).'];
The only difference is the anonymous function.

Matlab matrices dimension

I am new to matlab and just wondering if you guys can help me out with this problem.
For instance, I have two matrices:
A = [X1 X2 X3 X4]
B = [Y1; Y2; Y3]
now what I really want to achieve is to multiply these two matrices in this way:
[X1Y1 X2Y1 X3Y1 X4Y1;
X1Y2 X2Y2 X3Y2 X4Y2;
X1Y3 X2Y3 X3Y3 X4Y3;
.... and so on]
I tried using A(1,:).*B(:,1) but matlab is saying that matrix dimensions must agree.
I just don't know how to manipulate this on matlab but in excel is possible.
This is a simple outer product. kron is not needed (although it will work.) bsxfun is wild overkill, although will yield what you have asked for. repmat is inappropriate, because while it will help you do what you wish, it replicates the arrays in memory, using more resources than are needed. (Avoid using inefficient programming styles when there are good ones immediately at your disposal.)
All you need use is the simple * operator.
A is a row vector. B a column vector.
C = B*A
will yield the result C(i,j)=B(i)*A(j), which is exactly what you are looking for. Note that this works because B is 3x1 and A is 1x4, so the "inner" dimensions of B and A do conform.
In MATLAB, IF you are unsure if something works, TRY IT!
A = [1 2 3 4];
B = [1;2;3];
C = B*A
ans =
1 2 3 4
2 4 6 8
3 6 9 12
See that kron did indeed work, although I'd bet that use of kron here is probably less efficient than is the simple outer product multiply.
C = kron(B,A)
C =
1 2 3 4
2 4 6 8
3 6 9 12
As well, bsxfun will work here too, although since we are using a general tool to do something that a basic operator will do, I'd bet it is slightly less efficient.
C = bsxfun(#times,B,A)
C =
1 2 3 4
2 4 6 8
3 6 9 12
The WORST choice is repmat. Again, since it artificially replicates the vectors in memory FIRST, it must go out and grab big chunks of memory in the case of large vectors.
C = repmat(B,1,4).*repmat(A,3,1)
C =
1 2 3 4
2 4 6 8
3 6 9 12
I suppose for completeness, you could also have used meshgrid or ndgrid. See that it is doing exactly what repmat did, but here it explicitly creates new matrices. Again, this is a poor programming style when there are good tools to do exactly what you wish.
[BB,AA] = ndgrid(B,A)
BB =
1 1 1 1
2 2 2 2
3 3 3 3
AA =
1 2 3 4
1 2 3 4
1 2 3 4
C = BB.*AA
C =
1 2 3 4
2 4 6 8
3 6 9 12
What you need to understand is exactly why each of these tools COULD have been used for the job, and why they are different.
In Matlab there is * and .* and they are very different.
* is normal matrix multiplication which is what you want i.e. B*A, note the B must come first as the inner dimension must match. You can multiply a column by a row but not a row by a column (unless they have the same number of elements).
.* is element by element multiplication in which case the matrices must be exactly the same size and shape so for example [1 2 3].*[4 5 6] = [1*4 2*5 3*6] = [4 10 18]
Do not do a ".*". You should rather do a "*".
The ".*" is for index by index multiplication and should have given you [X1Y1 X2Y2 X3Y3] were they vectors have been equal in size.
If you do the regular multiplication "*", this is actually matrix multiplication.
I think you just need to transpose one of the vectors. You are multiplying a column vector (A(1,:)) with a row vector (B(:,1)). This should work:
C = A(1,:).*B(:,1)';

Averaging every n elements of a vector in matlab

I would like to average every 3 values of an vector in Matlab, and then assign the average to the elements that produced it.
Examples:
x=[1:12];
y=%The averaging operation;
After the operation,
y=
[2 2 2 5 5 5 8 8 8 11 11 11]
Therefore the produced vector is the same size, and the jumping average every 3 values replaces the values that were used to produce the average (i.e. 1 2 3 are replaced by the average of the three values, 2 2 2). Is there a way of doing this without a loop?
I hope that makes sense.
Thanks.
I would go this way:
Reshape the vector so that it is a 3×x matrix:
x=[1:12];
xx=reshape(x,3,[]);
% xx is now [1 4 7 10; 2 5 8 11; 3 6 9 12]
after that
yy = sum(xx,1)./size(xx,1)
and now
y = reshape(repmat(yy, size(xx,1),1),1,[])
produces exactly your wanted result.
Your parameter 3, denoting the number of values, is only used at one place and can easily be modified if needed.
You may find the mean of each trio using:
x = 1:12;
m = mean(reshape(x, 3, []));
To duplicate the mean and reshape to match the original vector size, use:
y = m(ones(3,1), :) % duplicates row vector 3 times
y = y(:)'; % vector representation of array using linear indices