I have a matrix named l having size 20X3.
What I wanted to do was this :
Suppose I have this limits:
l1_max=20; l1_min=0.5;
l2_max=20; l2_min=0.5;
mu_max=20; mu_min=0.5;
I wanted to force all the elements of the matrix l within the limits.
The values of 1st column within l1_max & l1_min.
The values of 2nd column within l2_max & l2_min.
The values of 3rd column within mu_max & mu_min.
What I did was like this:
for k=1:20
if l(k,1)>l1_max
l(k,1) = l1_max;
elseif l(k,1)<l1_min
l(k,1) = l1_min;
end
if l(k,2)>l2_max
l(k,2) = l2_max;
elseif l(k,2)<l2_min
l(k,2) = l2_min;
end
if l(k,3)>mu_max
l(k,3) = mu_max;
elseif l(k,3)<mu_min
l(k,3) = mu_min;
end
end
Can it be done in a better way ?
You don't have to loop over rows, use vectorized operations on entire columns:
l(l(:, 1) > l1_max, 1) = l1_max;
l(l(:, 1) < l1_min, 1) = l1_min;
Similarily:
l(l(:, 2) > l2_max, 2) = l2_max;
l(l(:, 2) < l2_min, 2) = l2_min;
l(l(:, 3) > l2_max, 3) = mu_max;
l(l(:, 3) < l2_min, 3) = mu_min;
An alternative method, which resembles to Bas' idea, is to apply min and max as follows:
l(:, 1) = max(min(l(:, 1), l1_max), l1_min);
l(:, 2) = max(min(l(:, 2), l2_max), l2_min);
l(:, 3) = max(min(l(:, 3), mu_max), mu_min);
It appears that both approaches have comparable performance.
You don't even have to loop over all columns, the operation on the whole matrix can be done in 2 calls to bsxfun, independent of the number of columns:
column_max = [l1_max, l2_max, mu_max];
column_min = [l1_min, l2_min, mu_min];
M = bsxfun(#min, M, column_max); %clip to maximum
M = bsxfun(#max, M, column_min); %clip to minimum
This uses two tricks: to clip a value between min_val and max_val, you can do clipped_x = min(max(x, min_val), max_val). The other trick is to use the somewhat obscure bsxfun, which applies a function after doing singleton expansion. When you use it on two matrices, it 'extrudes' the smallest one to the same size as the largest one before applying the function, so the example above is equivalent to M = min(M, repmat(column_max, size(M, 1), 1)), but hopefully calculated in a more efficient way.
Below is a benchmark to test the various methods discussed so far. I'm using the TIMEIT function found on the File Exchange.
function [t,v] = testClampColumns()
% data and limits ranges for each column
r = 10000; c = 500;
M = randn(r,c);
mn = -1.1 * ones(1,c);
mx = +1.1 * ones(1,c);
% functions
f = { ...
#() clamp1(M,mn,mx) ;
#() clamp2(M,mn,mx) ;
#() clamp3(M,mn,mx) ;
#() clamp4(M,mn,mx) ;
#() clamp5(M,mn,mx) ;
};
% timeit and check results
t = cellfun(#timeit, f, 'UniformOutput',true);
v = cellfun(#feval, f, 'UniformOutput',false);
assert(isequal(v{:}))
end
Given the following implementations:
1) loop over all values and compare against min/max
function M = clamp1(M, mn, mx)
for j=1:size(M,2)
for i=1:size(M,1)
if M(i,j) > mx(j)
M(i,j) = mx(j);
elseif M(i,j) < mn(j)
M(i,j) = mn(j);
end
end
end
end
2) compare each column against min/max
function M = clamp2(M, mn, mx)
for j=1:size(M,2)
M(M(:,j) < mn(j), j) = mn(j);
M(M(:,j) > mx(j), j) = mx(j);
end
end
3) truncate each columns to limits
function M = clamp3(M, mn, mx)
for j=1:size(M,2)
M(:,j) = min(max(M(:,j), mn(j)), mx(j));
end
end
4) vectorized version of truncation in (3)
function M = clamp4(M, mn, mx)
M = bsxfun(#min, bsxfun(#max, M, mn), mx);
end
5) absolute value comparison: -a < x < a <==> |x| < a
(Note: this is not applicable to your case, since it requires a symmetric limits range. I only included this for completeness. Besides it turns out to be the slowest method.)
function M = clamp5(M, mn, mx)
assert(isequal(-mn,mx), 'Only works when -mn==mx')
idx = bsxfun(#gt, abs(M), mx);
v = bsxfun(#times, sign(M), mx);
M(idx) = v(idx);
end
The timing I get on my machine with an input matrix of size 10000x500:
>> t = testClampColumns
t =
0.2424
0.1267
0.0569
0.0409
0.2868
I would say that all the above methods are acceptably fast enough, with the bsxfun solution being the fastest :)
Related
The problem is there are c no. of firms bidding on p no. of projects. The winning bidders should collectively have the lowest cost on the client. Each firm can win a maximum of 2 projects.
I have written this code. It works, but takes forever to produce the result, and is very inefficient.
==========================================================================
function FINANCIAL_RESULTS
clear all; clc;
%This Matlab Program aims to select a large number of random combinations,
%filter those with more than two allocations per firm, and select the
%lowest price.
%number of companies
c = 7;
%number of projects
p = 9;
%max number of projects per company
lim = 2;
%upper and lower random limits
a = 1;
b = c;
%Results Matrix: each row represents the bidding price of one firm on all projects
Results = [382200,444050,725200,279250,750800,190200,528150,297700,297700;339040,393420,649520,243960,695760,157960,454550,259700,256980;388032,499002,721216,9999999,773184,204114,512148,293608,300934;385220,453130,737860,287480,9999999,188960,506690,274260,285670;351600,9999999,9999999,276150,722400,9999999,484150,266000,281400;404776,476444,722540,311634,778424,210776,521520,413130,442160;333400,403810,614720,232200,656140,165660,9999999,274180,274180];
Output = zeros(1,p+1);
n=1;
i=1;
for i = 1:10000000
rndm = round(a + (b-a).*rand(1,p));
%random checker with the criteria (max 2 allocations)
Check = tabulate(rndm);
if max(Check(:,2)) > lim
continue
end
Output(n,1:end-1) = rndm;
%Cumulative addition of random results
for k = 1:p
Output(n,end) = Output(n,end) + Results(rndm(k),k);
end
n = n+1;
end
disp(Results);
[Min_pay,Indx] = min(Output(:,end));
disp(Output(Indx,:));
%You know the program is done when Handel plays
load handel
sound(y,Fs);
%Done !
end
Since the first dimension is much greater than the second dimension it would be more efficient to perform loop along the second dimension:
i = 10000000;
rndm = round(a + (b-a) .* rand(i, p));
Check = zeros(size(rndm, 1), 1);
for k = 1:p
Check = max(Check, sum(rndm == k, 2));
end
rndm = rndm(Check <= lim, :);
OutputEnd = zeros(size(rndm, 1), 1);
for k = 1:p
OutputEnd = OutputEnd + Results(rndm(:, k), k);
end
Output = [rndm OutputEnd];
Note that if the compute has a limited memory put the above code inside a loop and concatenate the results of iterations to produce the final result:
n = 10;
Outputc = cell(n, 1);
for j = 1:n
i = 1000000;
....
Outputc{j} = Output;
end
Output = cat(1, Outputc{:});
Given an nxn matrix A_k and a nx1 vector x, is there any smart way to compute
using Matlab? x_i are the elements of the vector x, therefore J is a sum of matrices. So far I have used a for loop, but I was wondering if there was a smarter way.
Short answer: you can use the builtin matlab function polyvalm for matrix polynomial evaluation as follows:
x = x(end:-1:1); % flip the order of the elements
x(end+1) = 0; % append 0
J = polyvalm(x, A);
Long answer: Matlab uses a loop internally. So, you didn't gain that much or you perform even worse if you optimise your own implementation (see my calcJ_loopOptimised function):
% construct random input
n = 100;
A = rand(n);
x = rand(n, 1);
% calculate the result using different methods
Jbuiltin = calcJ_builtin(A, x);
Jloop = calcJ_loop(A, x);
JloopOptimised = calcJ_loopOptimised(A, x);
% check if the functions are mathematically equivalent (should be in the order of `eps`)
relativeError1 = max(max(abs(Jbuiltin - Jloop)))/max(max(Jbuiltin))
relativeError2 = max(max(abs(Jloop - JloopOptimised)))/max(max(Jloop))
% measure the execution time
t_loopOptimised = timeit(#() calcJ_loopOptimised(A, x))
t_builtin = timeit(#() calcJ_builtin(A, x))
t_loop = timeit(#() calcJ_loop(A, x))
% check if builtin function is faster
builtinFaster = t_builtin < t_loopOptimised
% calculate J using Matlab builtin function
function J = calcJ_builtin(A, x)
x = x(end:-1:1);
x(end+1) = 0;
J = polyvalm(x, A);
end
% naive loop implementation
function J = calcJ_loop(A, x)
n = size(A, 1);
J = zeros(n,n);
for i=1:n
J = J + A^i * x(i);
end
end
% optimised loop implementation (cache result of matrix power)
function J = calcJ_loopOptimised(A, x)
n = size(A, 1);
J = zeros(n,n);
A_ = eye(n);
for i=1:n
A_ = A_*A;
J = J + A_ * x(i);
end
end
For n=100, I get the following:
t_loopOptimised = 0.0077
t_builtin = 0.0084
t_loop = 0.0295
For n=5, I get the following:
t_loopOptimised = 7.4425e-06
t_builtin = 4.7399e-05
t_loop = 1.0496e-04
Note that my timings fluctuates somewhat between different runs, but the optimised loop is almost always faster (up to 6x for small n) than the builtin function.
I am trying to implement the following filter on a discrete signal x:
I'm supposed to write a MATLAB function that takes a length-M (> N) vector x and a scalar N as input. The output should be a length-M vector y.
I should then test the filter with M = 50, x[n]=cos(n*pi/5)+dirac[n-30]-dirac[n-35] and N = 4, 8, 12.
Here is my try, which returns Inf with the given input and N:
function y = filt( x, N )
% filter function
if(~isvector(x))
error('Input must be a vector')
end
y = zeros(1,length(x));
temp = zeros(1,length(x));
n=1;
for v = x(:)
temp(n) = v(n);
if(n <= N-1)
y(n) = max(x);
n = n+1;
elseif(n >= N-1)
y(n) = max(temp);
end
end
end
I also tried using the built-in filter function but I can't get it to work.
Code for using the filter:
p = zeros(1,50);
for i=0:50
p(i+1)= cos(i*pi/5)+dirac(i-30)-dirac(i-35)
end
y = filt(p,4)
Thanks in advance.
That's because dirac(0) gives you Inf. This will happen in two places in your signal, where n=30 and n=35. I'm assuming you want the unit impulse instead. As such, create a signal where at n = 31 and n = 36, the output is 1, then add this with your cosine signal. This is because MATLAB starts indexing at 1 and not 0, and so dirac[0] would mean that the first point of your signal is non-zero, so translating this over by 30: dirac[n-30] would mean that the 31st point is non-zero. Similar case for dirac[n-35], so the 36th point is non-zero:
p = zeros(1,50);
p(31) = 1; p(36) = 1;
p = p + cos((0:49)*pi/5);
y = filt(p,4);
I also have some reservations with your code. It doesn't do what you think it's doing. Specifically, I'm looking at this section:
n=1;
for v = x(:)
temp(n) = v(n);
if(n <= N-1)
y(n) = max(x);
n = n+1;
elseif(n >= N-1)
y(n) = max(temp);
end
end
Doing v = x(:) would produce a column vector, and using a loop with a column vector will have unintentional results. Specifically, this loop will only execute once, with v being the entire signal. You also aren't checking the conditions properly for each window. You are doing max(x), which applies the maximum to the entire signal, and not the window.
If I can suggest a rewrite, this is what you should be doing instead:
function y = filt( x, N )
% filter function
if(~isvector(x))
error('Input must be a vector')
end
y = zeros(1,length(x));
%///// CHANGE
for n = 1 : numel(x)
if (n <= N)
y(n) = max(x(1:n));
else
y(n) = max(x(n:-1:n-N+1));
end
end
end
Take note that the if statement is n <= N. This is because in MATLAB, we start indexing at 1, but the notation in your equation starts indexing at 0. Therefore, instead of checking for n <= N-1, it must now be n <= N.
I have 2 matrices = X in R^(n*m) and W in R^(k*m) where k<<n.
Let x_i be the i-th row of X and w_j be the j-th row of W.
I need to find, for each x_i what is the j that maximizes <w_j,x_i>
I can't see a way around iterating over all the rows in X, but it there a way to find the maximum dot product without iterating every time over all of W?
A naive implementation would be:
n = 100;
m = 50;
k = 10;
X = rand(n,m);
W = rand(k,m);
Y = zeros(n, 1);
for i = 1 : n
max_ind = 1;
max_val = dot(W(1,:), X(i,:));
for j = 2 : k
cur_val = dot(W(j,:),X(i,:));
if cur_val > max_val
max_val = cur_val;
max_ind = j;
end
end
Y(i,:) = max_ind;
end
Dot product is essentially matrix multiplication:
[~, Y] = max(W*X');
bsxfun based approach to speed-up things for you -
[~,Y] = max(sum(bsxfun(#times,X,permute(W,[3 2 1])),2),[],3)
On my system, using your dataset I am getting a 100x+ speedup with this.
One can think of two more "closeby" approaches, but they don't seem to give any huge improvement over the earlier one -
[~,Y] = max(squeeze(sum(bsxfun(#times,X,permute(W,[3 2 1])),2)),[],2)
and
[~,Y] = max(squeeze(sum(bsxfun(#times,X',permute(W,[2 3 1]))))')
I have two matrices of big sizes, which are something similar to the following matrices.
m; with size 1000 by 10
n; with size 1 by 10.
I would like to subtract each element of n from all elements of m to get ten different matrices, each has size of 1000 by 10.
I started as follows
clc;clear;
nrow = 10000;
ncol = 10;
t = length(n)
for i = 1:nrow;
for j = 1:ncol;
for t = 1:length(n);
m1(i,j) = m(i,j)-n(1);
m2(i,j) = m(i,j)-n(2);
m3(i,j) = m(i,j)-n(3);
m4(i,j) = m(i,j)-n(4);
m5(i,j) = m(i,j)-n(5);
m6(i,j) = m(i,j)-n(6);
m7(i,j) = m(i,j)-n(7);
m8(i,j) = m(i,j)-n(8);
m9(i,j) = m(i,j)-n(9);
m10(i,j) = m(i,j)-n(10);
end
end
end
can any one help me how can I do it without writing the ten equations inside the loop? Or can suggest me any convenient way especially when the two matrices has many columns.
Why can't you just do this:
m01 = m - n(1);
...
m10 = m - n(10);
What do you need the loop for?
Even better:
N = length(n);
m2 = cell(N, 1);
for k = 1:N
m2{k} = m - n(k);
end
Here we go loopless:
nrow = 10000;
ncol = 10;
%example data
m = ones(nrow,ncol);
n = 1:ncol;
M = repmat(m,1,1,ncol);
N = permute( repmat(n,nrow,1,ncol) , [1 3 2] );
result = bsxfun(#minus, M, N );
%or just
result = M-N;
Elapsed time is 0.018499 seconds.
or as recommended by Luis Mendo:
M = repmat(m,1,1,ncol);
result = bsxfun(#minus, m, permute(n, [1 3 2]) );
Elapsed time is 0.000094 seconds.
please make sure that your input vectors have the same orientation like in my example, otherwise you could get in trouble. You should be able to obtain that by transposements or you have to modify this line:
permute( repmat(n,nrow,1,ncol) , [1 3 2] )
according to your needs.
You mentioned in a comment that you want to count the negative elements in each of the obtained columns:
A = result; %backup results
A(A > 0) = 0; %set non-negative elements to zero
D = sum( logical(A),3 );
which will return the desired 10000x10 matrix with quantities of negative elements. (Please verify it, I may got a little confused with the dimensions ;))
Create the three dimensional result matrix. Store your results, for example, in third dimension.
clc;clear;
nrow = 10000;
ncol = 10;
N = length(n);
resultMatrix = zeros(nrow, ncol, N);
neg = zeros(ncol, N); % amount of negative values
for j = 1:ncol
for i = 1:nrow
for t = 1:N
resultMatrix(i,j,t) = m(i,j) - n(t);
end
end
for t = 1:N
neg(j,t) = length( find(resultMatrix(:,j,t) < 0) );
end
end