Why matrices are [rows, columns] and not [columns, rows]? - math

For the sake of simplicity, I will refer to column as col.
Why are matrices defined as [rows, columns] and not [columns, rows]?
It has just caused me a ton of headaches and confusions.
My thinking goes this way:
A regular array:
[1, 3, 5, 2, 4]
is like a matrix with one row and multiple cols. And it is notated like that: arr[n].
And so if we had another dimension:
[1, 3, 5, 2, 4]
[1, 3, 6, 3, 6]
there are now rows. So let us notate the rows after the 'n', arr[n, rows], but the reality shows us otherwise.
In addition, a matrix of 2 dimensions can be looked at as a cartesian coordinate system (where the direction of the y axis is flipped, the origin is element [0,0]). in the plane, we notate points like that: (X,Y).
It looks like the cols are sitting on the x axis and the rows are on the y axis, so why not notate the elements of matrices like that: [Cols, Rows]?
Sorry if I've confused you, and sorry for my ignorance.

IMO, this is bound to latin typographical conventions.
Latin writes from left to right, then top to bottom.
Following these conventions, a Matrix is decomposed into nRow rows.
Each row is then decomposed into nColum elements, much like you would decompose a text in sentences, and sentences in words.
Information is thus organized with a most significant arrangement (rows) and least significant (column).
Following same convention as latin (err arabic) number notation, we have most significant nRow on the left (first if you are latin), and least significant nColumn on the right, thus (nRow,nColumn) for describing the layout.
Naturally, accessing a single element at row iRow and column jCol follows same convention (iRow,jCol).
Note that information can be arranged completely differently in underlying software. For example, for multi-dimensional arrays in FORTRAN and Matlab, first indice vary first, and the sequence in memory is x(1,1) x(2,1) x(3,1) ... x(1,2) x(2,2) x(3,2) ... sort of column-wise order if we consider that left (first) is row index, right (last) is column index. Or maybe some optimized library will have arranged a block layout for the matrix.

Related

plotting a series of coordinates stored in a 2D array

So let's say I define the following array in Julia:
M=[[1,1],[2,4],[3,9],[4,16],[5,25],[6,36],[7,49],[8,64],[9,81],[10,100],[11,121],[12,144]]
Clearly each element [x,y] follows the quadratic rule $y=x^2$ and so I expect to get a parabolic shape when I plot it by using the command plot(M).
But instead I'm getting something like this:
[][1
What am I doing wrong, and what should I do to get my desired result -- a parabolic shape?
From the docs for Plots.jl:
The plot function has several methods:
plot(y): treats the input as values for the y-axis and yields a unit-range as x-values.
i.e. when you pass a single argument to plot, the values in the argument get interpreted as y-axis values, with the x-axis being 1, 2, 3, ....
Here, because M is a vector of vectors, a line plot is created for each of the inner vectors. For example, [3, 9] results in a line plot from (1, 3) to (1, 9).
To plot the parabola, in this case, you can do:
plot(first.(M), last.(M))
which will extract each first element of the inner array to form the x-axis, and each second element for the y-axis.
Of course, it's better to just create them as separate vectors in the first place, if you don't require M to be a vector of vectors for some other reason.
In case M is changed into a Matrix instead (which is the recommended way to create 2D arrays in Julia), for eg.
julia> M
12×2 Matrix{Int64}:
1 1
2 4
3 9
etc.
then you can plot it with
julia> #views plot(M[:, 1], M[:, 2])
M[:, 1] gets all values on the first column (the x-axis), M[:, 2] the same on the second column (y-axis), and the #views at the beginning avoids these being allocated a new memory area unnecessarily, instead being read and used directly from M itself.
Interestingly, since Plots handles an array of Tuples as an array of (x, y) points, this works:
plot(Tuple.(M))

Series vector for approximating pi

I've been set a question about Madhava's approximation of pi. The first part of it is to create a vector which contains the first 20 terms in the series. I know I could just input the first 20 terms into a vector, however that seems like a really long winded way of doing things. I was wondering if there is an easier way to create the vector?
Currently I have the vector
g = c((-3)^(-0)/(2*0+1), (-3)^(-1)/(2*1+1), (-3)^(-2)/(2*2+1), (-3)^(-3)/(2*3+1), (-3)^(-4)/(2*4+1), (-3)^(-5)/(2*5+1), (-3)^(-6)/(2*6+1), (-3)^(-7)/(2*7+1), (-3)^(-8)/(2*8+1), (-3)^(-9)/(2*9+1), (-3)^(-10)/(2*10+1), (-3)^(-11)/(2*11+1), (-3)^(-12)/(2*12+1), (-3)^(-13)/(2*13+1), (-3)^(-14)/(2*14+1), (-3)^(-15)/(2*15+1), (-3)^(-16)/(2*16+1), (-3)^(-17)/(2*17+1), (-3)^(-18)/(2*18+1), (-3)^(-19)/(2*19+1), (-3)^(-20)/(2*20+1))
And
h = sqrt(12)
So I have done g*h to get the approximation of pi. Surely there's an easier way of doing this?
Apologies if this is relatively basic, I am very new to R and still learning how to properly use stack overflow.
Thanks.
One of the best features of R is that it is vectorised. This means that we can do operations element-wise on entire vectors rather than having to type out the operation for each element. For example, if you wanted to find the square of the first five natural numbers (starting at one), we can do this:
(1:5)^2
which results in the output
[1] 1 4 9 16 25
instead of having to do this:
c(1^2, 2^2, 3^2, 4^2, 5^2)
which gives the same output.
Applying this amazing property of R to your situation, instead of having to manually construct the whole vector, we can just do this:
series <- sqrt(12) * c(1, -1) / 3^(0:19) / seq(from=1, by=2, length.out=20)
sum(series)
which gives the following output:
[1] 3.141593
and we can see more decimal places by doing this:
sprintf("%0.20f", sum(series))
[1] "3.14159265357140338182"
To explain a little further what I did in that line of code to generate the series:
We want to multiply the entire thing by the square root of 12, hence the sqrt(12), which will be applied to every element of the resulting vector
We need the signs of the series to alternate, which is accomplished via * c(1, -1); this is because of recycling, where R recycles elements of vectors when doing vector operations. It will multiply the first element by one, the second element by -1, then recycle and multiply the third element by 1, the fourth by -1, etc.
We need to divide each element by 1, 3, 9, etc., which is accomplished by / 3^(0:19) which gives / c(3^0, 3^1, ...)
Lastly, we also need to divide by 1, 3, 5, 7, etc. which is accomplished by seq(from=1, by=2, length.out=20) (see help(seq))

Count blocks in a series

This is a simple problem, however I cannot find an elegant solution for:
Given is the following vector series:
series=c(1,2,4,5,6,1,2,4,5,6,7,8,2,4)
I now want to count blocks of this vector in the same vector; e.g. if I have a block size of 2, I would like to count the pairs 1&2, 2&4, 4&5 and so on (in total 8 unique blocks if I did the counting right).
Can you think of an easy way to program that so that I receive an output matrix with a column for the "unique block number" and a corresponding column for the counts?
One idea is to can use rollapply from zoo,
nrow(unique(rollapply(series, 2, by = 1, paste0)))
#[1] 8
You can change '2' to get combinations(block sizes) of 3, 4, etc...

Piecewise / Noncontiguous Ranges?

Is there any kind of object class for piecewise / noncontiguous ranges in Julia? For instance, I can create a regular range:
a = UnitRange(1:5)
But, if I wanted to combine this with other ranges:
b = UnitRange([1:5, 8:10, 4:7])
I cannot currently find an object or method. There is a PiecewiseIncreasingRanges module (https://github.com/simonster/PiecewiseIncreasingRanges.jl) that would be just what I want in this situation, except that it, as the name implies, requires the ranges be monotonically increasing.
The context for this is that I am looking for a way to create a compressed, memory efficient version of the SparseMatrixCSC type for sparse matrices with repeating rows. The RLEVectors module will work well to save space on the nonzerovalue vector in the sparse matrix class. Now though I am trying to find something to save space for the rowvalue vector that also defines the sparse matrix, since series of repeating rows will result in ranges of values in that vector (e.g. if the first 10 rows, or even certain columns in the first ten rows, of a sparse matrix are identical, then there will be a lot of 1:10 patterns in the row value vector).
More generally, I'd like a range such as the b object that I try to create above over which I could do an iterated loop, getting:
for (idx, item) in enumerate(hypothetical_object)
println("idx: $idx, item: $item")
end
idx: 1, item: 1
idx: 2, item: 2
...
idx: 5, item: 5
idx: 6, item: 8
idx: 7, item: 9
idx: 8, item: 10
idx: 9, item: 4
idx: 10, item: 5
...
Update: One thing I'm considering, and will probably try implementing if I don't hear other suggestions here, will be to just create an array of PiecewiseIncreasingRange objects, one for each column in my sparse matrix. (I would probably also then break the nonzero value vector into an array of separate pieces, one for each column of my sparse matrix as well). This would at least be relatively simple to implement. I don't have a good sense off the bat how this would compare in terms of computational efficiency to the kind of object I am searching for in this question. I suspect that memory requirements would be about the same.
To loop over a sequence of ranges (or other iterators), you can use the chain function in the Iterators.jl package.
For example:
using Iterators
b = chain(1:5, 8:10, 4:7)
for i in b
println(i)
end
outputs the elements of each range.

Generating two sets of numbers where the sum of each set and the sum of their dot product is N

In this question Getting N random numbers that the sum is M, the object was to generate a set of random numbers that sums to a specific number N. After reading this question, I started playing around with the idea of generating sets of numbers that satisfy this condition
sum(A) == sum(B) && sum(B) == sum(A * B)
An example of this would be
A <- c(5, 5, -10, 6, 6, -12)
B <- c(5, -5, 0, 6, -6, 0)
In this case, the three sums equal zero. Obviously, those sets aren't random, but they satisfy the condition. Is there a way to generate 'random' sets of data that satisfy the above condition? (As opposed to using a little algorithm as in the above example.)
(Note: I tagged this as an R question, but the language really doesn't matter to me.)
You'd need to define the first vector in n-dimensional space, and the 2nd one will have N-2 degrees of freedom (i.e. random numbers) since the sum and one angle are already determined.
The 2nd vector would need to be transformed into N-dimensional space; There are infinitely many transforms that could work, so if you don't care about the probability distribution of the resulting vectors, just choose the one that's most intuitive to you.
There's a nice geometrical interpretation to the first constraint: it constrains the 2nd vector to a (hyper-)plane in N-dimensional space; the 2nd constraint doesn't have a simple geometric interpretation.
check out hyperspherical cooridnates.
You can generate one set completely randomly. And generate randomly all numbers in set B except for two numbers. Since you have two equations you should be able to solve for those two numbers.

Resources