Is there a fast way to expand matrices n times by duplicating each line? - arrays

For example, [1 1 ; 2 2 ; 3 3] becomes
[1 1
1 1
1 1
2 2
2 2
2 2
3 3
3 3
3 3]
I am using this:
expander(orig,mult::Int) = orig[ceil(Int,(1:size(orig,1)*mult)/mult),:]; in Julia and the following in Matlab:
function expanded = expander(original,multiplier)
expanded = original(ceil((1:size(original,1)*multiplier)/multiplier),:);
end
Another matlab only way to do it is this:
expanded = kron(original,ones(multiplier,1));
I would prefer a superfast julia option if it exists.

This doesn't prove that kron is fastest, but I compared its time to how long it would just take to populate a similarly sized Array with ones, and kron did quite well:
original = [1 1 ; 2 2 ; 3 3];
multiplier = 3*10^6;
#time begin
for idx = 1:100
expanded = kron(original,ones(multiplier));
end
end
## 9.199143 seconds (600 allocations: 15.646 GB, 9.05% gc time)
#time begin
for idx = 1:100
myones = [ones(multiplier*size(original,1)) ones(multiplier*size(original,1))];
end
end
## 12.746123 seconds (800 allocations: 26.822 GB, 14.86% gc time)
Update In response to comments by David Sanders, here are tests wrapped in a function. The reason I did the tests globally, which I know isn't normal best practice, is because it seemed quite plausible to me that the objects might get created globally.
function kron_test(original, multiplier)
for idx = 1:100
expanded = kron(original,ones(multiplier));
end
end
function ones_test(original, multiplier)
for idx = 1:100
myones = [ones(multiplier*size(original,1)) ones(multiplier*size(original,1))];
end
end
## times given after first function call to compile
#time kron_test(original, multiplier); ## 11.107632 seconds (604 allocations: 15.646 GB, 23.98% gc time)
#time ones_test(original, multiplier); ## 15.849761 seconds (604 allocations: 26.822 GB, 33.50% gc time)

Personally, I'd just use repeat:
repeat(original, inner=(multiplier, 1))
Unlike kron, it's very readable and understandable. Unfortunately it is quite a bit slower. Even so, I'd only use kron if you've identified it as a performance bottleneck. While it's faster for computers to execute, it's much slower for humans to understand what's going on… and the performance of repeat should eventually get better (it's issue #15553).
Edit: As of Julia 1.2, repeat has indeed gotten significantly faster. It now rivals kron:
julia> #btime kron($original,ones($multiplier));
81.039 ms (6 allocations: 160.22 MiB)
julia> #btime repeat($original, inner=($multiplier, 1));
84.087 ms (27 allocations: 137.33 MiB)

You could do
a = [1 1 ; 2 2 ; 3 3]
a = a' #matrices are in column major order in julia, should be faster this way
a = repmat(a,1,n)
a = sortcols(a)
Unfortunatelly I have no clue wheter this method is "superfast" but it's relatively simple and intuitive

Related

Why is slice faster than view() when constructing a multidimensional array from a vector?

Consider the following Vector:
numbers = Int32[1,2,3,4,5,6,7,8,9,10]
If I want to create a 2x5 matrix with the result:
1 2 3 4 5
6 7 8 9 10
I can't use reshape(numbers,2,5) or else I'll get:
1 3 5 7 9
2 4 6 8 10
Using slice or view(), you can extract the top row and bottom row, convert them to a matrix row, and then use vcat().
I'm not saying using slice or view() is the only or best way of doing it, perhaps there is a faster way using reshape(), I just haven't figured it out.
numbers = Int32[1,2,3,4,5,6,7,8,9,10]
println("Using Slice:")
#time numbers_slice_matrix_top = permutedims(numbers[1:5])
#time numbers_slice_matrix_bottom = permutedims(numbers[6:10])
#time vcat(numbers_slice_matrix_top,numbers_slice_matrix_bottom)
println("Using view():")
#time numbers_view_matrix_top = permutedims(view(numbers,1:5))
#time numbers_view_matrix_bottom = permutedims(view(numbers,6:10))
#time vcat(numbers_view_matrix_top,numbers_view_matrix_bottom)
Output:
Using Slice:
0.026763 seconds (5.48 k allocations: 329.155 KiB, 99.78% compilation time)
0.000015 seconds (3 allocations: 208 bytes)
0.301833 seconds (177.09 k allocations: 10.976 MiB, 93.30% compilation time)
Using view():
0.103084 seconds (72.25 k allocations: 4.370 MiB, 99.90% compilation time)
0.000011 seconds (2 allocations: 112 bytes)
0.503787 seconds (246.63 k allocations: 14.537 MiB, 99.85% compilation time)
Why is slice faster? In a few rare cases view() was faster, but not by much.
From view() documentation:
For example, if x is an array and v = #view x[1:10], then v acts like
a 10-element array, but its data is actually accessing the first 10
elements of x. Writing to a view, e.g. v[3] = 2, writes directly to
the underlying array x (in this case modifying x[3]).
I don't know enough, but from my understanding, because view() has to convert the Vector to a matrix row (the original Vector) through another array (the view()), it's slower. Using slice we create a copy and don't have to worry about manipulating the original Vector.
Your results actually show that view is faster not slicing. The point is that only the second tests is measuring the time to run the code while in the tests 1 and 3 you are measuring the time to compile the code.
This is a common misunderstanding how to run benchmarks in Julia. The point is that when a Julia function is run for the first time it needs to be compiled to an assembly code. Normally in production codes compile times do not matter because you compile only once for a fraction of a second and then run computations for many minutes, hours or days.
More than that - your code is using a global variable so in such a microbenchmark you are also measuring "how long does it take to resolve a global variable type" which is slow in Julia and not used in a production code.
Here is the correct way to run the benchmark using BenchmarkTools:
julia> #btime vcat(permutedims($numbers[1:5]),permutedims($numbers[6:10]));
202.326 ns (7 allocations: 448 bytes)
julia> #btime vcat(permutedims(view($numbers,1:5)),permutedims(view($numbers,6:10)));
88.736 ns (1 allocation: 96 bytes)
Note the interpolation symbol $ that makes numbers a type stable variable.
reshape(numbers, 5, 2)' can be used also to create the desired 2x5 matrix.

MATLAB-style replacement of array values that meet certain condition in Julia [duplicate]

In Octave, I can do
octave:1> A = [1 2; 3 4]
A =
1 2
3 4
octave:2> A(A>1) -= 1
A =
1 1
2 3
but in Julia, the equivalent syntax does not work.
julia> A = [1 2; 3 4]
2x2 Array{Int64,2}:
1 2
3 4
julia> A[A>1] -= 1
ERROR: `isless` has no method matching isless(::Int64, ::Array{Int64,2})
in > at operators.jl:33
How do you conditionally assign values to certain array or matrix elements in Julia?
Your problem isn't with the assignment, per se, it's that A > 1 itself doesn't work. You can use the elementwise A .> 1 instead:
julia> A = [1 2; 3 4];
julia> A .> 1
2×2 BitArray{2}:
false true
true true
julia> A[A .> 1] .-= 1000;
julia> A
2×2 Array{Int64,2}:
1 -998
-997 -996
Update:
Note that in modern Julia (>= 0.7), we need to use . to say that we want to broadcast the action (here, subtracting by the scalar 1000) to match the size of the filtered target on the left. (At the time this question was originally asked, we needed the dot in A .> 1 but not in .-=.)
In Julia v1.0 you can use the replace! function instead of logical indexing, with considerable speedups:
julia> B = rand(0:20, 8, 2);
julia> #btime (A[A .> 10] .= 10) setup=(A=copy($B))
595.784 ns (11 allocations: 4.61 KiB)
julia> #btime replace!(x -> x>10 ? 10 : x, A) setup=(A=copy($B))
13.530 ns ns (0 allocations: 0 bytes)
For larger matrices, the difference hovers around 10x speedup.
The reason for the speedup is that the logical indexing solution relies on creating an intermediate array, while replace! avoids this.
A slightly terser way of writing it is
replace!(x -> min(x, 10), A)
There doesn't seem to be any speedup using min, though.
And here's another solution that is almost as fast:
A .= min.(A, 10)
and that also avoids allocations.
To make it work in Julia 1.0 one need to change = to .=. In other words:
julia> a = [1 2 3 4]
julia> a[a .> 1] .= 1
julia> a
1×4 Array{Int64,2}:
1 1 1 1
Otherwise you will get something like
ERROR: MethodError: no method matching setindex_shape_check(::Int64, ::Int64)

Multiplying arrays of matrices in MATLAB

I have a data set that consists of two 1800 x 900 x 3 x 3 arrays, which should each be interpreted as a 1800x900 array of 3x3 matrices. As part of the analysis, at one point I need to create another such array by, at each point of the 1800x900 array, multiplying the corresponding 3x3 matrices together.
There seem to be two ways to do this that I can think of. The obvious way is
C = zeros(size(A))
for i = 1:900
for j = 1:1800
C(i,j,:,:) = A(i,j,:,:)*B(i,j,:,:)
end
end
But that's quite a long loop and doesn't really take advantage of MATLAB's vectorization. The other way is
C = zeros(size(A))
for i = 1:3
for j = 1:3
for k = 1:3
C(:,:,i,j) = C(:,:,i,j) + A(:,:,i,k).*B(:,:,k,j)
end
end
end
where the large dimensions are getting vectorized and I'm basically using the for loops to implement the Einstein summation convention. This seems really inelegant, though, which makes me think there should be a better way. Is there?
Perfect job for bsxfun with permute:
C = permute(sum(bsxfun(#times, A, permute(B, [1 2 5 3 4])), 4), [1 2 3 5 4]);
In R2016b onwards you can avoid bsxfun thanks to implicit singleton expansion:
C = permute(sum(A .* permute(B, [1 2 5 3 4]), 4), [1 2 3 5 4]);

indices of occurence of each row in MATLAB

I have two matrices, A and B. (B is continuous like 1:n)
I need to find all the occurrences of each individual row of B in A, and store those row indices accordingly in cell array C. See below for an example.
A = [3,4,5;1,3,5;1,4,3;4,2,1]
B = [1;2;3;4;5]
Thus,
C = {[2,3,4];[4];[1,2,3];[1,3,4];[1,2]}
Note C does not need to be in a cell array for my application. I only suggest it because the row vectors of C are of unequal length. If you can suggest a work-around, this is fine too.
I've tried using a loop running ismember for each row of B, but this is too slow when the matrices A and B are huge, with around a million entries. Vectorized code is appreciated.
(To give you context, the purpose of this is to identify, in a mesh, those faces that are attached to a single vertex. Note I cannot use the function edgeattachments because my data are not of the form "TR" in triangulation representation. All I have is a list of faces and list of vertices.)
Well, the best answer for this would require knowledge of how A is filled. If A is sparse, that is, if it has few columns values and B is quite large, then I think the best way for memory saving may be using a sparse matrix instead of a cell.
% No fancy stuff, just fast and furious
bMax = numel(B);
nRows = size(A,1);
cLogical = sparse(nRows,bMax);
for curRow = 1:nRows
curIdx = A(curRow,:);
cLogical(curRow,curIdx) = 1;
end
Answer:
cLogical =
(2,1) 1
(3,1) 1
(4,1) 1
(4,2) 1
(1,3) 1
(2,3) 1
(3,3) 1
(1,4) 1
(3,4) 1
(4,4) 1
(1,5) 1
(2,5) 1
How to read the answer. For each column the rows show the indexes that the column index appears in A. That is 1 appears in rows [2 3 4], 2 appear in row [4], 3 rows [1 2 3], 4 row [1 3 4], 5 in row [1 2].
Then you can use cLogical instead of a cell as an indexing matrix in the future for your needs.
Another way would be to allocate C with the expected value for how many times an index should appear in C.
% Fancier solution using some assumed knowledge of A
bMax = numel(B);
nRows = size(A,1);
nColumns = size(A,2);
% Pre-allocating with the expected value, an attempt to reduce re-allocations.
% tic; for rep=1:10000; C = mat2cell(zeros(bMax,nColumns),ones(1,bMax),nColumns); end; toc
% Elapsed time is 1.364558 seconds.
% tic; for rep=1:10000; C = repmat({zeros(1,nColumns)},bMax,1); end; toc
% Elapsed time is 0.606266 seconds.
% So we keep the not fancy repmat solution
C = repmat({zeros(1,nColumns)},bMax,1);
for curRow = 1:nRows
curIdxMsk = A(curRow,:);
for curCol = 1:nColumns
curIdx = curIdxMsk(curCol);
fillIdx = ~C{curIdx};
if any(fillIdx)
fillIdx = find(fillIdx,1);
else
fillIdx = numel(fillIdx)+1;
end
C{curIdx}(fillIdx) = curRow;
end
end
% Squeeze empty indexes:
for curRow = 1:bMax
C{curRow}(~C{curRow}) = [];
end
Answer:
>> C{:}
ans =
2 3 4
ans =
4
ans =
1 2 3
ans =
1 3 4
ans =
1 2
Which solution will performs best? You do a performance test in your code because it depends on how big is A, bMax, the memory size of your computer and so on. Yet, I'm still curious with solutions other people can do for this x). I liked chappjc's solution although it has the cons that he has pointed out.
For the given example (10k times):
Solution 1: Elapsed time is 0.516647 seconds.
Solution 2: Elapsed time is 4.201409 seconds (seems that solution 2 is a bad idea hahaha, but since it was created to the specific issue of A having many rows it has to be tested in those conditions).
chappjc' solution: Elapsed time is 2.405341 seconds.
We can do it without making any assumptions about B. Try this use of bsxfun and mat2cell:
M = squeeze(any(bsxfun(#eq,A,permute(B,[3 2 1])),2)); % 4x3x1 #eq 1x1x5 => 4x3x5
R = sum(M); % 4x5 -> 1x5
[ii,jj] = find(M);
C = mat2cell(ii,R)
The cells in C above will be column vectors rather than rows as in your example. To make the cells contain row vectors, use C = mat2cell(ii',1,R)' instead.
My only concern is that mat2cell could be slow for millions of values of R, but if you want your output in a cell, I'm not sure how much better you can do. EDIT: If you can deal with a sparse matrix like in Werner's first solution with the loop, replace the last line of the above with the following:
>> Cs = sparse(ii,jj,1)
Cs =
(2,1) 1
(3,1) 1
(4,1) 1
(4,2) 1
(1,3) 1
(2,3) 1
(3,3) 1
(1,4) 1
(3,4) 1
(4,4) 1
(1,5) 1
(2,5) 1
Unfortunately, bsxfun will probably run out of memory if both size(A,1) and numel(B) are large! You may have to loop over the elements of A or B if memory becomes an issue. Here's one way to do it by looping over your vertexes in B:
for i=1:numel(B), C{i} = find(any(A==B(i),2)); end
Yup, that easy. Cell array growing is extremely fast in MATLAB as it similar to a sequence container that stores contiguous references to the data, rather than keeping the data itself contiguous. Perhaps ismember was the bottleneck in your test.

How can I efficiently remove zeroes from a (non-sparse) matrix?

I have a matrix:
x = [0 0 0 1 1 0 5 0 7 0];
I need to remove all of the zeroes, like so:
x = [1 1 5 7];
The matrices I am using are large (1x15000) and I need to do this multiple times (5000+), so efficiency is key!
One way:
x(x == 0) = [];
A note on timing:
As mentioned by woodchips, this method seems slow compared to the one used by KitsuneYMG. This has also been noted by Loren in one of her MathWorks blog posts. Since you mentioned having to do this thousands of times, you may notice a difference, in which case I would try x = x(x~=0); first.
WARNING: Beware if you are using non-integer numbers. If, for example, you have a very small number that you would like to consider close enough to zero so that it will be removed, the above code won't remove it. Only exact zeroes are removed. The following will help you also remove numbers "close enough" to zero:
tolerance = 0.0001; % Choose a threshold for "close enough to zero"
x(abs(x) <= tolerance) = [];
Just to be different:
x=x(x~=0);
or
x=x(abs(x)>threshold);
This has the bonus of working on complex numbers too
Those are the three common solutions. It helps to see the difference.
x = round(rand(1,15000));
y = x;
tic,y(y==0) = [];toc
Elapsed time is 0.004398 seconds.
y = x;
tic,y = y(y~=0);toc
Elapsed time is 0.001759 seconds.
y = x;
tic,y = y(find(y));toc
Elapsed time is 0.003579 seconds.
As you should see, the cheapest way is the direct logical index, selecting out the elements to be retained. The find is more expensive, since matlab finds those elements, returning a list of them, and then indexes into the vector.
Here's another way
y = x(find(x))
I'll leave it to you to figure out the relative efficiency of the various approaches you try -- do write and let us all know.
Though my timing results are not conclusive to whether it is significantly faster, this seems to be the fastest and easiest approach:
y = nonzeros(y)
x = [0 0 0 1 1 0 5 0 7 0]
y = [0 2 0 1 1 2 5 2 7 0]
Then x2 and y2 can be obtained as:
x2=x(~(x==0 & y==0))
y2=y(~(x==0 & y==0))
x2 = [0 1 1 0 5 0 7]
y2 = [2 1 1 2 5 2 7]
Hope this helps!

Resources