How can I use cellfun (or appropriate alternative) when the input arrays are different sizes, and get all combinations of results (i.e., evaluated for the cross join of the arrays)?
This example uses a dummy function; the actual function is more complicated, so I'm looking for answers that call a custom function. Using Matlab R2018a, so I'm looking for an answer that is compatible with that.
a = 0:0.1:0.3; b = 100:5:120;
test = cellfun(#(x,y) myfunc(x,y,0), num2cell(a), num2cell(b));
function [result] = myfunc(i, j, k)
% k is needed as fixed adjustment in "real life function"
result = 0.1 * i + sqrt(j) + k;
end
The above code returns the following error:
Error using cellfun
All of the input arguments must be of the same size and shape.
Previous inputs had size 4 in dimension 2. Input #3 has size 5
The expected output from this example is the "result" column below; i and j are shown for convenience.
i
j
result
0
100
10
0.1
100
10.01
0.2
100
10.02
0.3
100
10.03
0
105
10.24695077
0.1
105
10.25695077
0.2
105
10.26695077
0.3
105
10.27695077
0
110
10.48808848
etc
etc
etc
The answer here is bsxfun. A worked example is below.
% You need a function with the correct number of inputs.
% With your sample, I would do something like this.
myfunc = #(i,j,k) 0.1 * i + sqrt(j) + k;
myfunc_inner = #(i,j) myfunc(i,j,0);
% Side not: using separate files for functions is more
% efficient, but makes for worse examples on stackoverflow
%Setting up the inputs
a = 0:0.1:0.3;
b = 100:5:120;
%bsxfun, for two inputs, is called like this.
c = bsxfun(myfunc_inner, a', b)
bsxfun does the following:
Expands scalar dimensions of the inputs so that they match
Performs element-wise combinations of the inputs, using the provided function input
In this case, the result is:
c =
10 10.247 10.488 10.724 10.954
10.01 10.257 10.498 10.734 10.964
10.02 10.267 10.508 10.744 10.974
10.03 10.277 10.518 10.754 10.984
To get the input in the form you requested, simply run c(:).
Historical note:
Back in the time-before-time, we had to use bsxfun more often. Now Matlab expands single dimensions without notice when we perform simple operations on numbers. For example, I used to use the following style frequently:
a = [1 2 3];
b = [4 5 6];
c = bsxfun(#plus, a', b)
Whereas now we simply write:
c = a' + b
Related
This is not a question about MatLab, but it is a question about how to achieve something that would be easy in object-oriented programming when you're using a less sophisticated language.
I'm a mathematician who is writing some MatLab code to test an algorithm in linear algebra (I won't burden you with the details). The beginning of the program is to generate a random 500 by 50 matrix of floats (call it A). In the course of running my program, I will want to pick random rows of A, not uniformly at random, but rather according to a distribution where the likelihood of row i being picked is different, depending on the specific matrix that has been generated.
I want to write a function called "pickRandomRow" that I can call over and over when I need it. It will use the same probability distribution on the rows throughout each individual run of the program, but that distribution will change between runs of the program (because the random matrix will be different).
If I were using a more object-oriented language than MatLab, I would make a class called "rowPicker" which could be initialized with the information about the specific random matrix I'm using on this run. But here, I'm not sure how to make a function in MatLab that can know the information it needs to know about the random matrix A once and for all, without passing A to the function over and over (expensively), when it's not changing.
Possible options
Make pickRandomRow a script instead of a function, so it can see the workspace. Then I wouldn't be able to give pickRandomRow any arguments, but so far I don't see why I'd need to.
Start messing areound with classes in MatLab.
As far as I remember, MATLAB supports closures.
Closures are something like an object with bunch of private member variables and a single method.
So, you could do something like this:
function rowPicker = createRowPicker(matrix, param)
expensivePreparations = ... (use 'matrix' and 'param' here) ...
function pickedRow = someComplicatedSamplingFunction
... (use 'matrix', 'expensivePreparations' and 'param' here) ...
end
rowPicker = #someComplicatedSamplingFunction
end
and then you could generate a bunch of differently parameterized rowPickers in a loop, something like this:
for p = [p1, p2, p3]
matrix = generateMatrix()
picker = createRowPicker(matrix, p)
... (run expensive simulation, reuse 'picker')
end
In this way, the expensive intermediate result expensivePreparations will be saved inside the closure, and you won't have to recompute it in each step of your expensive simulation.
Warning: all of the above it matlab-esque pseudocode and not tested.
In order to achieve this task you could use the randsample function and, to be exact, its four arguments overload:
y = randsample(n,k,true,w) or y = randsample(population,k,true,w)
returns a weighted sample taken with replacement, using a vector of
positive weights w, whose length is n. The probability that the
integer i is selected for an entry of y is w(i)/sum(w). Usually, w is
a vector of probabilities. randsample does not support weighted
sampling without replacement.
An example:
M = [
1 1 1;
2 2 2;
3 3 3;
4 4 4;
5 5 5
];
idx = randsample(1:5,1,true,[0.2 0.2 0.1 0.1 0.4]);
row = M(idx,:);
If you have to pick more than one row every time you run the script and the fact that the weighted sampling without replacement is not supported, you could use the datasample function instead:
M = [
1 1 1;
2 2 2;
3 3 3;
4 4 4;
5 5 5
];
idx = datasample(1:5,2,'Replace',false,'Weights',[0.2 0.2 0.1 0.1 0.4]);
rows = M(idx,:);
For what concerns the choice between a class and a script, I honestly think you are overcomplicating your problem a little bit. An OOP class, in this case, looks like an overkill to me. If you want to use a script (actually, a function) without passing any argument to it, you could use the persistent modifier on an internally defined matrix and a variable representing its row probabilities. Let's assume that the first solution I proposed is the one that fits your need, then:
a = pickRandomRow();
b = pickRandomRow();
c = pickRandomRow();
function row = pickRandomRow()
persistent M;
persistent W;
if (isempty(M))
M = [
1 1 1;
2 2 2;
3 3 3;
4 4 4;
5 5 5
];
W = [
0.2
0.2
0.1
0.1
0.4
];
end
idx = randsample(1:size(M,1),1,true,W);
row = M(idx,:);
end
If you want to provide different weights according to previous computations, you could change the above code as follows:
w1 = WeightsFromDistributionX();
w2 = WeightsFromDistributionY();
a = pickRandomRow(w1);
b = pickRandomRow(w2);
c = pickRandomRow(w2);
function row = pickRandomRow(W)
persistent M;
if (isempty(M))
M = [
1 1 1;
2 2 2;
3 3 3;
4 4 4;
5 5 5
];
end
M_size = size(M,1);
W_size = numel(W);
if (M_size ~= W_size)
error('The weights vector must have the same length of matrix rows.');
end
idx = randsample(1:M_size,1,true,W);
row = M(idx,:);
end
If creating a class is too much work (you first class will be, it's quite different than in other languages), you have several alternatives.
A single distribution at the time
You can accomplish this using persistent variables in a function. The function will become some sort of unique object.
function out = func(arg)
persistent M; % matrix to pick rows from
persistent S; % status
if nargin == 1
M = randn(...);
S = ...;
else
% use M, S
return ...;
end
You call this using func('init') the first time, and data = func() after that.
Multiple different distributions
You can rewrite the above but returning a cell array with the internal data when called with 'init'. Other times you pass that cell array as input:
function out = func(arg)
if ischar(arg)
M = randn(...);
S = ...;
return {M,S};
else % iscell(arg)
% use M=arg{1}, S=arg{2}
return ...;
end
Of course, instead of a cell array it could be a struct. I see this as a "poor man's object". There's no control over the user modifying the status of the object, but if you're your own user, this is probably not a big deal.
New to MATLAB, and I need help with the following issue.
I want to create a function val=F(v,e) that takes in two inputs v, a 1xn vector, and a scalar e, and outputs a scalar val that counts the nonzero entries of the vector v-e, i.e. the vector v with e subtracted from all each of its entries. My code for the function is below:
function val = eff(vec, e)
val = sum( (vec - e > 0) );
end
When I evaluate the function at a single point it works as it should. but I want a plot of this function on (0,1). Plotting it gives a constant value over the entire range of e. I am using the following code on the main
figure
e = linspace(0,1);
plot(e, eff(rand(1,100),e),'o',e, e)
Also, when I use a small vector, say, rand(1,10), I get the following error message:
>Error using -
>
>Matrix dimensions must agree.
>
>Error in eff (line 3)
>
>val = sum( (vec - e > 0 ));
Is my function being too careless with matrix dimensions? Or is there an easier way to evaluate eff over a vector range?
Thanks in advance.
You have created a function which is designed to be applied only with a scalar e argument, and where passing e as an array would potentially cause errors ... but then you call it with e = linspace(0,1) which is an array.
The particular error when e is of size 10 is telling you that you cannot subtract it from a matrix of size 100.
When e happens to have the same size as vec, your function subtracts two equal-sized arrays, and returns their sum, which is a scalar. Therefore your plot is essentially doing something like plot(a_range, a_scalar), which is why it looks constant.
Instead, you should probably collect an array V for each value of e in a for loop, or using arrayfun, e.g.
e = linspace(0,1);
V = arrayfun(#eff, e);
and then plot e against V
Alternatively, you could rewrite your function such that it expects e to be an array, and your return value is an array of the same size as e, filled with the appropriate values.
without using arrayfun, your task can also be accomplished using broadcasting. I noticed you had this question tagged Octave as well as Matlab. Octave uses automatic broadcasting when you attempt elementwise operations with vectors in different dimensions. Matlab can do broadcasting with the bsxfun function. (if you want code that will run in either program, Octave also can use bsxfun.) Also, according to the release notes I believe Matlab 2016b will now include automatic broadcasting, although I cannot confirm yet that it will behave the same as Octave does.
Because your vectors vec and e are both row vectors, when you try to subtract them Matlab/Octave will subtract each element if they have the same size, or give a size mismatch error if they do not.
If you instead create one of the vectors as a column vector, broadcasting can take over. a simple example:
>> a = [1:4]
a =
1 2 3 4
>> b = [1:4]'
b =
1
2
3
4
>> a-b //Error in Matlab versions before 2016b
ans =
0 1 2 3
-1 0 1 2
-2 -1 0 1
-3 -2 -1 0
>> bsxfun(#minus,a,b) //works under Octave or Matlab
ans =
0 1 2 3
-1 0 1 2
-2 -1 0 1
-3 -2 -1 0
So, if you are running Octave, your code will run correctly if you just rewrite your function so the vectors use different dimensions. There are a number of ways to do this, but since both Matlab and Octave default to column ordering, you can use the : operator to force them to work the way you want. E.g.:
>> a = [1:4]
a =
1 2 3 4
>> a(:)
ans =
1
2
3
4
>> a(:)'
ans =
1 2 3 4
>> b = [1:4]'
b =
1
2
3
4
>> b(:)
ans =
1
2
3
4
>> b(:)'
ans =
1 2 3 4
So, after all that, you can rewrite your function:
function val = eff(vec, e)
vec = vec(:);
e = e(:)';
val = sum ( (vec-e ) > 0 );
end
If you're running matlab, or you want code that could run in both Octave and Matlab, you can just replace the last line of the function with:
sum ( bsxfun(#minus,vec,e) > 0 )
Finally, if you want, you can add some 'isvector' error checking at the beginning of the function in case you accidentally pass it an array. And note that had I chosen to make 'vec' a row vector and 'e' a column vector I would have had to tell the sum function which dimension to sum over. (it defaults to summing each column and returning a row vector, which matches the choices I made above.)
you function works fine as long as e is a scaler and not an array or matrix. You can then you looping or arrayfun (as already answered) to get a final answer
figure
e = rand(1,10); % create 10 random e numbers
vec = rand(1,100);
for inc = 1:length(e)
v(inc) = eff(vec,e(inc));
end
scatter(e,v);
I am trying out one of the matlab programming question.
Question:
Write a function called hulk that takes a row vector v as an input and
returns a matrix H whose first column consist of the elements of v,
whose second column consists of the squares of the elements of v, and
whose third column consists of the cubes of the elements v. For
example, if you call the function likes this, A = hulk(1:3) , then A
will be [ 1 1 1; 2 4 8; 3 9 27 ].
My Code:
function H = hulk(v)
H = [v; v.^2; v.^3];
size(H) = (n,3);
end
When I test my code using A = hulk(1:3), it throws an error on console.
Your function made an error for argument(s) 0
Am I doing something incorrect? Have I missed anything?
Remove the line size(H) = (n,3);
and add the line H = H';
Final code should be as follows
function H = hulk(v)
H = [v; v.^2; v.^3];
H = H';
end
Your code giving error in matlab editor on the size(H) = (n,3); line
That's why you should use the matlabeditor itself
For your future reference, you can very easily generalise this function in Matlab to allow the user to specify the number of cols in your output matrix. I also recommend that you make this function a bit more defensive by ensuring that you are working with column vectors even if your user submits a row vector.
function H = hulk(v, n)
%//Set default value for n to be 3 so it performs like your current function does when called with the same signature (i.e. only 1 argument)
if nargin < 2 %// nargin stands for "Number of ARGuments IN"
n = 3;
end if
%// Next force v to be a row vector using this trick (:)
%// Lastly use the very useful bsxfun function to perform the power calcs
H = bsxfun(#power, v(:), 1:n);
end
You could reduce the number of operations using cumprod. That way, each v.^k is computed as the previous v.^k times v:
function H = hulk(v, n)
H = cumprod(repmat(v,n,1),1);
The first input argument is the vector, and the second is the maximum exponent.
I'm trying to use MatLab code as a way to learn math as a programmer.
So reading I'm this post about subspaces and trying to build some simple matlab functions that do it for me.
Here is how far I got:
function performSubspaceTest(subset, numArgs)
% Just a quick and dirty function to perform subspace test on a vector(subset)
%
% INPUT
% subset is the anonymous function that defines the vector
% numArgs is the the number of argument that subset takes
% Author: Lasse Nørfeldt (Norfeldt)
% Date: 2012-05-30
% License: http://creativecommons.org/licenses/by-sa/3.0/
if numArgs == 1
subspaceTest = #(subset) single(rref(subset(rand)+subset(rand))) ...
== single(rref(rand*subset(rand)));
elseif numArgs == 2
subspaceTest = #(subset) single(rref(subset(rand,rand)+subset(rand,rand))) ...
== single(rref(rand*subset(rand,rand)));
end
% rand just gives a random number. Converting to single avoids round off
% errors.
% Know that the code can crash if numArgs isn't given or bigger than 2.
outcome = subspaceTest(subset);
if outcome == true
display(['subset IS a subspace of R^' num2str(size(outcome,2))])
else
display(['subset is NOT a subspace of R^' num2str(size(outcome,2))])
end
And these are the subset that I'm testing
%% Checking for subspaces
V = #(x) [x, 3*x]
performSubspaceTest(V, 1)
A = #(x) [x, 3*x+1]
performSubspaceTest(A, 1)
B = #(x) [x, x^2, x^3]
performSubspaceTest(B, 1)
C = #(x1, x3) [x1, 0, x3, -5*x1]
performSubspaceTest(C, 2)
running the code gives me this
V =
#(x)[x,3*x]
subset IS a subspace of R^2
A =
#(x)[x,3*x+1]
subset is NOT a subspace of R^2
B =
#(x)[x,x^2,x^3]
subset is NOT a subspace of R^3
C =
#(x1,x3)[x1,0,x3,-5*x1]
subset is NOT a subspace of R^4
The C is not working (only works if it only accepts one arg).
I know that my solution for numArgs is not optimal - but it was what I could come up with at the current moment..
Are there any way to optimize this code so C will work properly and perhaps avoid the elseif statments for more than 2 args..?
PS: I couldn't seem to find a build-in matlab function that does the hole thing for me..
Here's one approach. It tests if a given function represents a linear subspace or not. Technically it is only a probabilistic test, but the chance of it failing is vanishingly small.
First, we define a nice abstraction. This higher order function takes a function as its first argument, and applies the function to every row of the matrix x. This allows us to test many arguments to func at the same time.
function y = apply(func,x)
for k = 1:size(x,1)
y(k,:) = func(x(k,:));
end
Now we write the core function. Here func is a function of one argument (presumed to be a vector in R^m) which returns a vector in R^n. We apply func to 100 randomly selected vectors in R^m to get an output matrix. If func represents a linear subspace, then the rank of the output will be less than or equal to m.
function result = isSubspace(func,m)
inputs = rand(100,m);
outputs = apply(func,inputs);
result = rank(outputs) <= m;
Here it is in action. Note that the functions take only a single argument - where you wrote c(x1,x2)=[x1,0,x2] I write c(x) = [x(1),0,x(2)], which is slightly more verbose, but has the advantage that we don't have to mess around with if statements to decide how many arguments our function has - and this works for functions that take input in R^m for any m, not just 1 or 2.
>> v = #(x) [x,3*x]
>> isSubspace(v,1)
ans =
1
>> a = #(x) [x(1),3*x(1)+1]
>> isSubspace(a,1)
ans =
0
>> c = #(x) [x(1),0,x(2),-5*x(1)]
>> isSubspace(c,2)
ans =
1
The solution of not being optimal barely scratches the surface of the problem.
I think you're doing too much at once: rref should not be used and is complicating everything. especially for numArgs greater then 1.
Think it through: [1 0 3 -5] and [3 0 3 -5] are both members of C, but their sum [4 0 6 -10] (which belongs in C) is not linear product of the multiplication of one of the previous vectors (e.g. [2 0 6 -10] ). So all the rref in the world can't fix your problem.
So what can you do instead?
you need to check if
(randn*subset(randn,randn)+randn*subset(randn,randn)))
is a member of C, which, unless I'm mistaken is a difficult problem: Conceptually you need to iterate through every element of the vector and make sure it matches the predetermined condition. Alternatively, you can try to find a set such that C(x1,x2) gives you the right answer. In this case, you can use fminsearch to solve this problem numerically and verify the returned value is within a defined tolerance:
[s,error] = fminsearch(#(x) norm(C(x(1),x(2)) - [2 0 6 -10]),[1 1])
s =
1.999996976386119 6.000035034493023
error =
3.827680714104862e-05
Edit: you need to make sure you can use negative numbers in your multiplication, so don't use rand, but use something else. I changed it to randn.
I'm a little surprised that MATLAB doesn't have a Map function, so I hacked one together myself since it's something I can't live without. Is there a better version out there? Is there a somewhat-standard functional programming library for MATLAB out there that I'm missing?
function results = map(f,list)
% why doesn't MATLAB have a Map function?
results = zeros(1,length(list));
for k = 1:length(list)
results(1,k) = f(list(k));
end
end
usage would be e.g.
map( #(x)x^2,1:10)
The short answer: the built-in function arrayfun does exactly what your map function does for numeric arrays:
>> y = arrayfun(#(x) x^2, 1:10)
y =
1 4 9 16 25 36 49 64 81 100
There are two other built-in functions that behave similarly: cellfun (which operates on elements of cell arrays) and structfun (which operates on each field of a structure).
However, these functions are often not necessary if you take advantage of vectorization, specifically using element-wise arithmetic operators. For the example you gave, a vectorized solution would be:
>> x = 1:10;
>> y = x.^2
y =
1 4 9 16 25 36 49 64 81 100
Some operations will automatically operate across elements (like adding a scalar value to a vector) while others operators have a special syntax for element-wise operation (denoted by a . before the operator). Many built-in functions in MATLAB are designed to operate on vector and matrix arguments using element-wise operations (often applied to a given dimension, such as sum and mean for example), and thus don't require map functions.
To summarize, here are some different ways to square each element in an array:
x = 1:10; % Sample array
f = #(x) x.^2; % Anonymous function that squares each element of its input
% Option #1:
y = x.^2; % Use the element-wise power operator
% Option #2:
y = f(x); % Pass a vector to f
% Option #3:
y = arrayfun(f, x); % Pass each element to f separately
Of course, for such a simple operation, option #1 is the most sensible (and efficient) choice.
In addition to vector and element-wise operations, there's also cellfun for mapping functions over cell arrays. For example:
cellfun(#upper, {'a', 'b', 'c'}, 'UniformOutput',false)
ans =
'A' 'B' 'C'
If 'UniformOutput' is true (or not provided), it will attempt to concatenate the results according to the dimensions of the cell array, so
cellfun(#upper, {'a', 'b', 'c'})
ans =
ABC
A rather simple solution, using Matlab's vectorization would be:
a = [ 10 20 30 40 50 ]; % the array with the original values
b = [ 10 8 6 4 2 ]; % the mapping array
c = zeros( 1, 10 ); % your target array
Now, typing
c( b ) = a
returns
c = 0 50 0 40 0 30 0 20 0 10
c( b ) is a reference to a vector of size 5 with the elements of c at the indices given by b. Now if you assing values to this reference vector, the original values in c are overwritten, since c( b ) contains references to the values in c and no copies.
It seems that the built-in arrayfun doesn't work if the result needed is an array of function:
eg:
map(#(x)[x x^2 x^3],1:10)
slight mods below make this work better:
function results = map(f,list)
% why doesn't MATLAB have a Map function?
for k = 1:length(list)
if (k==1)
r1=f(list(k));
results = zeros(length(r1),length(list));
results(:,k)=r1;
else
results(:,k) = f(list(k));
end;
end;
end
If matlab does not have a built in map function, it could be because of efficiency considerations. In your implementation you are using a loop to iterate over the elements of the list, which is generally frowned upon in the matlab world. Most built-in matlab functions are "vectorized", i. e. it is more efficient to call a function on an entire array, than to iterate over it yourself and call the function for each element.
In other words, this
a = 1:10;
a.^2
is much faster than this
a = 1:10;
map(#(x)x^2, a)
assuming your definition of map.
You don't need map since a scalar-function that is applied to a list of values is applied to each of the values and hence works similar to map. Just try
l = 1:10
f = #(x) x + 1
f(l)
In your particular case, you could even write
l.^2
Vectorizing the solution as described in the previous answers is the probably the best solution for speed. Vectorizing is also very Matlaby and feels good.
With that said Matlab does now have a Map container class.
See http://www.mathworks.com/help/matlab/map-containers.html