Does MATLAB support truly 1d arrays? - arrays

It would really help me reason about my MATLAB code if I didn't have to worry about accidental 2d operations. For instance, if I want to do element-wise multiplication of 1d arrays, but one is a row and another is a column, I end up with a 2d result.
>> a = 1:8;
>> a = a(:);
>> a .* cumsum(ones(8))
ans =
1 1 1 1 1 1 1 1
4 4 4 4 4 4 4 4
9 9 9 9 9 9 9 9
16 16 16 16 16 16 16 16
25 25 25 25 25 25 25 25
36 36 36 36 36 36 36 36
49 49 49 49 49 49 49 49
64 64 64 64 64 64 64 64
I'd like to prevent this type of thing, and likely other problems that I can't foresee, by keeping all my arrays 1d wherever I can. But every time I check the size() of vector, I get at least 2 elements back:
>> size(1:1:6)
ans =
1 6
>> size(linspace(0, 5, 10))
ans =
1 10
I've tried the suggestions at How to create single dimensional array in matlab? and some of the options here (PDF download), and I can't get a "truly" 1d array. How would you deal with this type of issue?

There is no such thing as 1D array. The documentation says (emphasis mine):
All MATLAB variables are multidimensional arrays, no matter what type of data. A matrix is a two-dimensional array often used for linear algebra.
You may use isvector, isrow and iscolumn to identify vectors, row vectors and column vectors respectively.

#Sardar has already said the last word. Another clue is ndims:
N = ndims(A) returns the number of dimensions in the array A. The
number of dimensions is always greater than or equal to 2. ...
But about your other question:
How would you deal with this type of issue?
There's not much you can do. Debug, find the mistake and fix it. If it's some one-time script, you are done. But if you are writing functions that may be used later, it's better to protect them from accepting arguments with unequal dimensions:
function myFunc(A, B)
if ndims(A)~=ndims(B) || any(size(A)~=size(B))
error('Matrix dimensions must agree.');
end
% ...
end
Or, if your function really needs them to be vectors:
function myFunc(A, B)
if ~isvector(A) || ~isvector(B) || any(size(A)~=size(B))
error('A and B must be vectors with same dimensions.');
end
% ...
end
You can also validate different attributes of arguments using validateattributes:
function myFunc(A, B)
validateattributes(A, {'numeric'},{'vector'}, 'myFunc', 'A')
validateattributes(B, {'numeric'},{'size', size(A)}, 'myFunc', 'B')
% ...
end
Edit:
Also, if the function only needs the inputs to be vectors and their orientation does not matter, you can modify them inside the function (thanks to #CrisLuengo for commenting).
function myFunc(A, B)
if ~isvector(A) || ~isvector(B) || length(A)~=length(B)
error('A and B must be vectors with the same length.');
end
A = A(:);
B = B(:);
% ...
end
However, this is not recommended when the output of the function is also a vector with the same size as the inputs. This is because the caller expects the output to be in the same orientation as the inputs, and if this is not the case, problems may arise.

Related

Multi-Dimensional Arrays Julia

I am new to using Julia and have little experience with the language. I am trying to understand how multi-dimensional arrays work in it and how to access the array at the different dimensions. The documentation confuses me, so maybe someone here can explain it better.
I created an array (m = Array{Int64}(6,3)) and am trying to access the different parts of that array. Clearly I am understanding it wrong so any help in general about Arrays/Multi-Dimensional Arrays would help.
Thanks
Edit I am trying to read a file in that has the contents
58 129 10
58 129 7
25 56 10
24 125 25
24 125 15
13 41 10
0
The purpose of the project is to take these fractions (58/129) and round the fractions using farey sequence. The last number in the row is what both numbers need to be below. Currently, I am not looking for help on how to do the problem, just how to create a multidimensional array with all the numbers except the last row (0). My trouble is how to put the numbers into the array after I have created it.
So I want m[0][0] = 58, so on. I'm not sure how syntax works for this and the manual is confusing. Hopefully this is enough information.
Julia's arrays are not lists-of-lists or arrays of pointers. They are a single container, with elements arranged in a rectangular shape. As such, you do not access successive dimensions with repeated indexing calls like m[j][i] — instead you use one indexing call with multiple indices: m[i, j].
If you trim off that last 0 in your file, you can just use the built-in readdlm to load that file into a matrix. I've copied those first six rows into my clipboard to make it a bit easier to follow here:
julia> str = clipboard()
"58 129 10\n58 129 7\n25 56 10\n24 125 25\n24 125 15\n13 41 10"
julia> readdlm(IOBuffer(str), Int) # or readdlm("path/to/trimmed/file", Int)
6×3 Array{Int64,2}:
58 129 10
58 129 7
25 56 10
24 125 25
24 125 15
13 41 10
That's not very helpful in teaching you how Julia's arrays work, though. Constructing an array like m = Array{Int64}(6,3) creates an uninitialized matrix with 18 elements arranged in 6 rows and 3 columns. It's a bit easier to see how things work if we fill it with a sensible pattern:
julia> m .= [10,20,30,40,50,60] .+ [1 2 3]
6×3 Array{Int64,2}:
11 12 13
21 22 23
31 32 33
41 42 43
51 52 53
61 62 63
This has set up the values of the array to have the row number in their tens place and the column number in the ones place. Accessing m[r,c] returns the value in m at row r and column c.
julia> m[2,3] # second row, third column
23
Now, r and c don't have to be integers — they can also be vectors of integers to select multiple rows or columns:
julia> m[[2,3,4],[1,2]] # Selects rows 2, 3, and 4 across columns 1 and 2
3×2 Array{Int64,2}:
21 22
31 32
41 42
Of course ranges like 2:4 are just vectors themselves, so you can more easily and efficiently write that example as m[2:4, 1:2]. A : by itself is a shorthand for a vector of all the indices within the dimension it indexes into:
julia> m[1, :] # the first row of all columns
3-element Array{Int64,1}:
11
12
13
julia> m[:, 1] # all rows of the first column
6-element Array{Int64,1}:
11
21
31
41
51
61
Finally, note that Julia's Array is column-major and arranged contiguously in memory. This means that if you just use one index, like m[2], you're just going to walk down that first column. As a special extension, we support what's commonly referred to as "linear indexing", where we allow that single index to span into the higher dimensions. So m[7] accesses the 7th contiguous element, wrapping around into the first row of the second column:
julia> m[5],m[6],m[7],m[8]
(51, 61, 12, 22)

Julia - specify type with readdlm

I have a large text file with small numbers which I need to import using Julia.
A toy example is
7
31 16
90 2 53
I found readdlm. When I go
a = readdlm("FileName.txt")
it works but the resulting array is of type Any and the resulting computations are really slow.
I've tried and failed to specify the type as int or specifically Int16.
How do I do that correctly?
Also if I use readdlm, do I have to close the file.
Your toy example would give you errors in case you specify types as there are some missing values in there. These missing values are handled as strings in Julia so the Type of your table would end up being Any as readdlm can't figure out whether these are numeric/character values. Row1 has only 1 value while row2 has 2, etc, giving you the missing values.
In case all your data is nice and clean in the text file, you can set the Type of the table in readdlm:
int_table = readdlm("FileName2.txt", Int16)
int_table
3x3 Array{Int16,2}:
7 0 0
31 16 0
90 2 53
Where FileName2.txt is:
7 0 0
31 16 0
90 2 53
However, if your data has missing values, you will need to convert them to some numeric values or use the DataFrames package to handle them. I'm assuming here that you want a pure integer Array so I fill the values with 0:
any_table = readdlm("FileName.txt")
any_table
3x3 Array{Any,2}:
7 "" ""
31 16 ""
90 2 53
# fill missing values with 0
any_table[any_table .== ""] .= 0
# convert to integer table
clean_array = Array{Int16}(any_table)
clean_array
3x3 Array{Int16,2}:
7 0 0
31 16 0
90 2 53
Readdlm closes the file for you, so you don't have to worry about that.

Storing blocks of vector data into an array in Matlab

I have an array in Matlab
A = [1 2 3 4 5 6 7 8 9;
67 67 67 86 86 86 86 67 67]';
where every point in the first row of A corresponds to a "code" either 67 or 86. I am trying to extract these blocks of "67s" and "86s" such that every time a block starts the corresponding elements are put into the 3rd dimension of a different array called X, where the .
So for e.g. in A I have 3 different blocks, so I would like to end up with an array X of size 1x9x3. And for e.g. the first 67 block I would like to have X
X(1,:,1) = [1 2 3];
I understand that I would "fill up" this vector X using a for loop
for i=1:size(A,2)
for j=1:size(A,2) %actually j should be up till the number of blocks present
X(1,i,j) = A(1,i)
end
end
But this isn't correct or complete of course because firstly I'm unsure how to separate out the "blocks" and how to correctly "fill in" the j's in X(1,i,j). Secondly how can I get the code to recognise how many blocks there are?
Can anyone help?
Thanks
One possible approach, based on this answer:
>> B = accumarray([0; cumsum(diff(A(:,2)) ~= 0)] + 1, A(:,1), [], #(x) {x}, [])
Now you have this:
>> B{1}
ans =
1
2
3
>> B{2}
ans =
4
5
6
7
>> B{3}
ans =
8
9

How to identify breaks within an array of MATLAB?

I have an array in MATLAB containing elements such as
A=[12 13 14 15 30 31 32 33 58 59 60];
How can I identify breaks in values of data? For example, the above data exhibits breaks at elements 15 and 33. The elements are arranged in ascending order and have an increment of one. How can I identify the location of breaks of this pattern in an array? I have achieved this using a for and if statement (code below). Is there a better method to do so?
count=0;
for i=1:numel(A)-1
if(A(i+1)==A(i)+1)
continue;
else
count=count+1;
q(count)=i;
end
end
Good time to use diff and find those neighbouring differences that aren't equal to 1. However, this will return an array which is one less than the length of your input array because it finds pairwise differences up until the last element, so naturally there will be one less. As such, when you find the locations that aren't equal to 1, make sure you add 1 to the locations to account for this:
>> A=[12 13 14 15 30 31 32 33 58 59 60];
>> q = find(diff(A) ~= 1) + 1
q =
5 9
This tells us that locations 5 and 9 in your array is where the jump happens, and that's right for your example data.
However, if you want to find the locations before the jump happens, such as in your code, don't add 1 to the result:
>> q = find(diff(A) ~= 1)
q =
4 8

calculation of value from given matrix

suppose that we have following array :
a=[12 21 23 10 34 54 10 9 5 6 7 8]
a =
12 21 23 10 34 54 10 9 5 6 7 8
length(a)=
length(a)
ans =
12
now i want to create following vector b ,which b(1),b(2)...b(6) are following
b(1)=sqrt(a(1)^2+a(2)^2)
b(2)=sqrt(a(3)^2+a(4)^2)
b(3)=sqrt(a(5)^2+a(6)^2))
b(4)=sqrt(a(7)^2+a(8)^2)
b(5)=sqrt(a(9)^2+a(10)^2))
b(6)=sqrt(a(11)^2+a(12)^2)
i have wrote following code
or i=2:2:length(a)
b(i/2)=sqrt(a(i-1)^2+a(i)^2);
end
>> b
b =
24.1868 25.0799 63.8122 13.4536 7.8102 10.6301
but i am not sure if it is correct,pleas help me to clarify if everything is ok in my code
In matlab, loops are quite slow. Using vectors is much faster. I suggest therefore a solution without a loop:
a_1 = a(1:2:end);
a_2 = a(2:2:end);
b = sqrt(a_1.^2 + a_2.^2);
first, you create a vector a_1 containing all elements with odd indices of a and a vector a_2 containing all elements with even indices.
Then you square them element wise (.^) and take the square of the sum.
For you example of a, this is 75 times faster. As you increase the size of the array, you will save even more time.

Resources