Vectorization in MATLAB - arrays

I'm trying to create a vector of size 121x101 such that the ith column is made up of V_t*e, where V_t = 1000*10^((i-1)/20) and e is a 121 long column of ones.
Clearly i is to be varied from 1 to 101 million, but how would I apply that to a matrix without only yielding the final value in the results (applying this to every column without repeating commands)?

From your question, it looks like each row is the same. Thus, you can just calculate one row using REPMAT as
iRow = 1:101;
V_t = 1000*10.^((iRow-1)/20);
V_te = repmat(V_t,121,1);
If you want to have e be 1 in row 1, 2 in row 2, etc, you can use NDGRID to create two arrays of the same size as the output, which contain the values of e and i for every element (i,j) of the output
[ee,ii] = ndgrid(1:121,1:101);
V_te = 1000*10.^((i-1)/20) .* ee;
or you can use BSXFUN to do the expansion of e and i for you
iRow = 1:101;
V_t = 1000*10.^((iRow-1)/20);
V_te = bsxfun(#times,V_t,(1:121)');

Related

construct a matrix by removing different elements from an array without loops in matlab

Given a vector X of discrete positive integers with size 160*1, and a table Tb1 in size 40*200, that contains a list of indices to be deleted from X Each column from the 200 columns in Tb1 points to 40 elements to be deleted from original X.
I create a new matrix of the remaining 120*200 elements by using a for loop with 200 iterations, that at round i deletes 40 elements from a copy of the original X according to the indices listed in Tb1(:,i), but it takes too much time and memory.
How can I get the result without using loops and with a minimum number of operations?
Here are different methods:
Method1:
idx = ~hist(tbl, 1:160);
[f,~]=find(idx);
result1 = reshape(M(f),120,200);
Method2:
idx = ~hist(tbl, 1:160);
M2=repmat(M,200,1);
result2 = reshape(M2(idx),120,200);
Method 3 & 4:
% idx can be generated using accumarray
idx = ~accumarray([tbl(:) reshape(repmat(1:200,40,1),[],1)],true,[160,200],#any);
%... use method 1 and 2
Method5:
M5=repmat(M,200,1);
M5(bsxfun(#plus,tbl,0:160:160*199))=[];
result5 = reshape(M5,120,200);
Assuming that M is an array of integers and tbl is the table of indices.
It can be tested with the following data:
M = rand(160,1);
[~,tbl] = sort(rand(160,200));
tbl = tbl(1:40,:);
However it is more efficient if you generate indices of elements to be remained instead of indices of elements to be removed.

Substitute a vector value with two values in MATLAB

I have to create a function that takes as input a vector v and three scalars a, b and c. The function replaces every element of v that is equal to a with a two element array [b,c].
For example, given v = [1,2,3,4] and a = 2, b = 5, c = 5, the output would be:
out = [1,5,5,3,4]
My first attempt was to try this:
v = [1,2,3,4];
v(2) = [5,5];
However, I get an error, so I do not understand how to put two values in the place of one in a vector, i.e. shift all the following values one position to the right so that the new two values fit in the vector and, therefore, the size of the vector will increase in one. In addition, if there are several values of a that exist in v, I'm not sure how to replace them all at once.
How can I do this in MATLAB?
Here's a solution using cell arrays:
% remember the indices where a occurs
ind = (v == a);
% split array such that each element of a cell array contains one element
v = mat2cell(v, 1, ones(1, numel(v)));
% replace appropriate cells with two-element array
v(ind) = {[b c]};
% concatenate
v = cell2mat(v);
Like rayryeng's solution, it can replace multiple occurrences of a.
The problem mentioned by siliconwafer, that the array changes size, is here solved by intermediately keeping the partial arrays in cells of a cell array. Converting back to an array concenates these parts.
Something I would do is to first find the values of v that are equal to a which we will call ind. Then, create a new output vector that has the output size equal to numel(v) + numel(ind), as we are replacing each value of a that is in v with an additional value, then use indexing to place our new values in.
Assuming that you have created a row vector v, do the following:
%// Find all locations that are equal to a
ind = find(v == a);
%// Allocate output vector
out = zeros(1, numel(v) + numel(ind));
%// Determine locations in output vector that we need to
%// modify to place the value b in
indx = ind + (0:numel(ind)-1);
%// Determine locations in output vector that we need to
%// modify to place the value c in
indy = indx + 1;
%// Place values of b and c into the output
out(indx) = b;
out(indy) = c;
%// Get the rest of the values in v that are not equal to a
%// and place them in their corresponding spots.
rest = true(1,numel(out));
rest([indx,indy]) = false;
out(rest) = v(v ~= a);
The indx and indy statements are rather tricky, but certainly not hard to understand. For each index in v that is equal to a, what happens is that we need to shift the vector over by 1 for each index / location of v that is equal to a. The first value requires that we shift the vector over to the right by 1, then the next value requires that we shift to the right by 1 with respect to the previous shift, which means that we actually need to take the second index and shift by the right by 2 as this is with respect to the original index.
The next value requires that we shift to the right by 1 with respect to the second shift, or shifting to the right by 3 with respect to the original index and so on. These shifts define where we're going to place b. To place c, we simply take the indices generated for placing b and move them over to the right by 1.
What's left is to populate the output vector with those values that are not equal to a. We simply define a logical mask where the indices used to populate the output array have their locations set to false while the rest are set to true. We use this to index into the output and find those locations that are not equal to a to complete the assignment.
Example:
v = [1,2,3,4,5,4,4,5];
a = 4;
b = 10;
c = 11;
Using the above code, we get:
out =
1 2 3 10 11 5 10 11 10 11 5
This successfully replaces every value that is 4 in v with the tuple of [10,11].
I think that strrep deserves a mention here.
Although it's called string replacement and warns for non-char input, it still works perfectly fine for other numbers as well (including integers, doubles and even complex numbers).
v = [1,2,3,4]
a = 2, b = 5, c = 5
out = strrep(v, a, [b c])
Warning: Inputs must be character arrays or cell arrays of strings.
out =
1 5 5 3 4
You are not attempting to overwrite an existing value in the vector. You're attempting to change the size of the vector (meaning the number of rows or columns in the vector) because you're adding an element. This will always result in the vector being reallocated in memory.
Create a new vector, using the first and last half of v.
Let's say your index is stored in the variable index.
index = 2;
newValues = [5, 5];
x = [ v(1:index), newValues, v(index+1:end) ]
x =
1 2 5 5 3 4

Identify missing values from array

I am striving to create a function in VBA that calculates the number of missing values in each column of a matrix of nxn dimensions.
Each column should contain the numbers 1 to n only once.
However if this is not the case I want to the function to state how many values are missing. For example in a column of 4x4 matrix (1,2,1,3) there is one missing value which is 4, and the function should return the value 1, for the 1 missing value.
I am very new to VBA and by no means a master, but this is what I have done so far...
Function calcCost(sol() As Integer, n As Integer) As Integer
Dim ArrayOfTruth(1 To n) As Boolean
For Row = 1 To n
For i = 1 To n
If ProbMatrix(Column, Row) = i Then
ArrayOfTruth(i) = True
cost = 0
For i = 1 To n
If ArrayOfTruth(i) = True Then
cost = cost + 1
Assuming that the requirement of a square range of cells supersedes the description of the 'matrix's' values, I'm not sure why an array is needed at all.
Function calcCost(rTopLeft As Range, n As Long)
Dim c As Long, r As Long
For c = 1 To n
If Not CBool(Application.CountIf(rTopLeft.Resize(n, n), c)) Then _
r = r + 1
Next c
calcCost = r
End Function
Syntax:
    =calcCost(<top left corner of desired range>, <number of cells both right and down>)
Example:
=calcCost(E9, 18)
The above implementation could also be written as,
=18-SUMPRODUCT(--SIGN(COUNTIF(OFFSET(E9,0,0,18,18), ROW(1:18))))

Trimming vals in a matrix of arbitrary dimensions in a specified dimension

I'm writing a function that requires some values in a matrix of arbitrary dimansions to be dropped in a specified dimension.
For example, say I have a 3x3 matrix:
a=[1,2,3;4,5,6;7,8,9];
I might want to drop the third element in each row, in which case I could do
a = a(:,1:2)
But what if the dimensions of a are arbitrary, and the dimension to trim is defined as an argument in the function?
Using linear indexing, and some carefully considered maths is an option but I was wondering if there is a neater soltion?
For those interested, this is my current code:
...
% Find length in each dimension
sz = size(dat);
% Get the proportion to trim in each dimension
k = sz(d)*abs(p);
% Get the decimal part and integer parts of k
int_part = fix(k);
dec_part = abs(k - int_part);
% Sort the array
dat = sort(dat,d);
% Trim the array in dimension d
if (int_part ~=0)
switch d
case 1
dat = dat(int_part + 1 : sz(1) - int_part,:);
case 2
dat = dat(:,int_part + 1 : sz(2) - int_part);
end
end
...
It doesn't get any neater than this:
function A = trim(A, n, d)
%// Remove n-th slice of A in dimension d
%// n can be vector of indices. d needs to be scalar
sub = repmat({':'}, 1, ndims(A));
sub{d} = n;
A(sub{:}) = [];
This makes use of the not very well known fact that the string ':' can be used as an index. With due credit to this answer by #AndrewJanke, and to #chappjc for bringing it to my attention.
a = a(:, 1:end-1)
end, used as a matrix index, always refers to the index of the last element of that matrix
if you want to trim different dimensions, the simplest way is using and if/else block - as MatLab only supports 7 dimensions at most, you wont need an infinite number of these to cover all bases
The permute function allows to permute the dimension of an array of any dimension.
You can place the dimension you want to trim in a prescribed position (the first, I guess), trim, and finally restore the original ordering. In this way you can avoid running loops and do what you want compactly.

Turning an array in to a matrix in MATLAB

I need to turn a large array into a matrix in the following way: to take the first m entries of the array and make that the 1st row of the matrix.
For example: if I had an array that was 100 entries long, the corresponding matrix would be 10 rows and each row would be 10 entries of the array with the order preserved.
I've tried the following code:
rows = 10
row_length = 10
a = randi(1,100);
x = zeros(rows,row_length)
for i=1:rows
x(i) = a(i:i+row_length)
end
but with no luck. I'm stuck on how to slide the window along by row_length so that i will start from row_length+1 in the second (and subsequent) iterations of the loop.
The best way to do it is to use Matlab's reshape function:
reshape(a,row_length,[]).'
It will reshape by first assigning down the columns which is why I transpose at the end (i.e. .')
However just for the sake of your learning, this is how you could have done it your way:
rows = 10
row_length = 10
a = rand(1,100)
x = zeros(rows,row_length)
for i=1:row_length:rows*row_length %// use two colons here, the number between them is the step size
x(i:i+row_length-1) = a(i:i+row_length-1) %// You need to assign to 10 elements on the left hand side as well!
end

Resources