Consider a 2x2 matrix of 2x2 blocks, e.g.,
using LinearAlgebra
using StaticArrays
M = zeros(SMatrix{2, 2, Float64, 4}, 2, 2)
M[1,1] = SA[1 0; 0 2]
M[2,2] = SA[0 3; 4 0]
What is the best way to convert M into a 4x4 matrix of scalars?
# how to convert M into this?
M2 = [1 0 0 0;
0 2 0 0;
0 0 0 3;
0 0 4 0]
In my real problem the matrix sizes will be larger, but the general question remains: How to flatten a block matrix into one larger matrix.
I recommend using BlockArrays.jl:
julia> using BlockArrays
julia> mortar(M)
2×2-blocked 4×4 BlockMatrix{Float64, Matrix{SMatrix{2, 2, Float64, 4}}, Tuple{BlockedUnitRange{Vector{Int64}}, BlockedUnitRange{Vector{Int64}}}}:
1.0 0.0 │ 0.0 0.0
0.0 2.0 │ 0.0 0.0
──────────┼──────────
0.0 0.0 │ 0.0 3.0
0.0 0.0 │ 4.0 0.0
You can of course do Matrix(mortar(M)) to get back to a "normal" matrix. However, if you have this kind of data structure you should like staying with the BlockArray.
Related
x1=[1,2,3]
x2=[2,3,4]
how to find the Pairwise distance matrix between x1 and x2 (distance matrix should be a 3 x 3 matrix)
This is not a Euclidean distance matrix, but it is 3 X 3. Is it what you want?
julia> x1 = [1,2,3]
3-element Vector{Int64}:
1
2
3
julia> x2 = [2,3,4]
3-element Vector{Int64}:
2
3
4
julia> [(a-b)^2 for a in x1, b in x2]
3×3 Matrix{Int64}:
1 4 9
0 1 4
1 0 1
With Distances.jl:
julia> pairwise(Euclidean(), x1, x2)
3×3 Matrix{Float64}:
1.0 2.0 3.0
0.0 1.0 2.0
1.0 0.0 1.0
(Although this will not return integers, as it uses BLAS stuff internally.)
Since you ask for Euclidean distance between all combinations of vector pairs from x1 and x2, that's, the distance between [1, 2] and [2, 3], [1, 2] and [2, 4], ..., [2, 3] and [3, 4], this can be done as follows:
Using Combinatorics.jl, construct all pairs from x1 by taking 2 elements at a time. Do the same for x2. Now you have c1 and c2, just loop over the two sequences applying the formal definition of Euclidean distance, sqrt(sum((x-y)^2)), to get the 3-by-3 matrix of pairwise distances that you want.
using Combinatorics
x1 = [1, 2, 3]
x2 = [2, 3, 4]
c1 = combinations(x1, 2)
c2 = combinations(x2, 2)
pairwise = [sqrt(sum((i.-j).^2)) for i in c1, j in c2]
3×3 Matrix{Float64}:
1.41421 2.23607 2.82843
1.0 1.41421 2.23607
0.0 1.0 1.41421
If you like higher-order index notations similar to math books, you can use Tullio.jl like this:
using Tullio
x = collect(combinations(x1, 2))
y = collect(combinations(x2, 2))
#tullio pairwise[i,j] := sqrt(sum((x[i].-y[j]).^2))
3×3 Matrix{Float64}:
1.41421 2.23607 2.82843
1.0 1.41421 2.23607
0.0 1.0 1.41421
You can try:
abs.(x1 .- x2')
#3×3 Array{Int64,2}:
# 1 2 3
# 0 1 2
# 1 0 1
Where x2' turns x2 in a column vector and .- and abs. makes element wise operations.
Or creating the desired pairs (1,2)and(2,3), (1,2)and(2,4), ... (2,3)and(3,4) and calculating the distance using norm.
using LinearAlgebra
#Create pairs
c1 = [(x1[i], x1[j]) for i in 1:lastindex(x1)-1 for j in i+1:lastindex(x1)]
c2 = [(x2[i], x2[j]) for i in 1:lastindex(x2)-1 for j in i+1:lastindex(x2)]
#Calc distance
[norm(i.-j) for i in c1, j in c2]
#3×3 Array{Float64,2}:
# 1.41421 2.23607 2.82843
# 1.0 1.41421 2.23607
# 0.0 1.0 1.41421
#Calc cityblock distance
[norm(i.-j, 1) for i in c1, j in c2]
#3×3 Array{Float64,2}:
# 2.0 3.0 4.0
# 1.0 2.0 3.0
# 0.0 1.0 2.0
I have a function f1 that take a pair of real numbers (x, y) and returns a triple of real numbers. I would like to collect all outputs of this function for all x in a vector a and y in a vector b. Could you please elaborate on how to do so?
f1 <- function(x, y){
return (c(x+y, x-y, x*y))
}
a <- seq(0, pi, 0.1)
b <- seq(0, 2 * pi, 0.1)
Update: I mean for all pair $(x, y) \in a \times b$.
Here is a data.table option
setDT(expand.grid(a, b))[, fval := do.call(Vectorize(f1, SIMPLIFY = FALSE), unname(.SD))][]
where expand.grid + do.call + Vectorize are used, giving
Var1 Var2 fval
1: 0.0 0.0 0,0,0
2: 0.1 0.0 0.1,0.1,0.0
3: 0.2 0.0 0.2,0.2,0.0
4: 0.3 0.0 0.3,0.3,0.0
5: 0.4 0.0 0.4,0.4,0.0
---
2012: 2.7 6.2 8.90,-3.50,16.74
2013: 2.8 6.2 9.00,-3.40,17.36
2014: 2.9 6.2 9.10,-3.30,17.98
2015: 3.0 6.2 9.2,-3.2,18.6
2016: 3.1 6.2 9.30,-3.10,19.22
A more compact one is using CJ(a,b) instead of setDT(expand.grid(a, b)) (Thank #akrun's advise)
We can use expand.grid to expand the data between 'a', and 'b' values, then loop over the row with apply, MARGIN = 1 and apply the f1
out <- as.data.frame(t(apply(expand.grid(a, b), 1, function(x) f1(x[1], x[2]))))
Or with tidyverse
library(dplyr)
library(purrr)
library(tidyr)
out2 <- crossing(x = a, y = b) %>%
pmap_dfr(f2)
-output
head(out2)
# A tibble: 6 x 3
# add subtract multiply
# <dbl> <dbl> <dbl>
#1 0 0 0
#2 0.1 -0.1 0
#3 0.2 -0.2 0
#4 0.3 -0.3 0
#5 0.4 -0.4 0
#6 0.5 -0.5 0
where f2
f2 <- function(x, y){
return (tibble(add = x+y, subtract = x-y, multiply = x*y))
}
It may be better to return a list or tibble so that it becomes easier
Create all possible combinations with expand.grid and use Map to apply f1 to every pair.
val <- expand.grid(a, b)
result <- do.call(rbind, Map(f1, val$Var1, val$Var2))
head(result)
# [,1] [,2] [,3]
#[1,] 0.0 0.0 0
#[2,] 0.1 0.1 0
#[3,] 0.2 0.2 0
#[4,] 0.3 0.3 0
#[5,] 0.4 0.4 0
#[6,] 0.5 0.5 0
This question already has answers here:
Creating copies in Julia with = operator
(2 answers)
Closed 3 years ago.
Here is the example code. I can't understand why the first element in array B also be revised. Can I keep the same element in array B?
julia> A = [0.0 0.1 0.2 0.3];
julia> B = A;
julia> A[1] = 0.1;
julia> A
1×4 Array{Float64,2}:
0.1 0.1 0.2 0.3
julia> B
1×4 Array{Float64,2}:
0.1 0.1 0.2 0.3
Julia Array is passed by reference. You need to create a copy:
julia> A = [0.0 0.1 0.2 0.3];
julia> B = deepcopy(A)
1×4 Array{Float64,2}:
0.0 0.1 0.2 0.3
julia> A[1] = 0.1;
julia> A, B
([0.1 0.1 0.2 0.3], [0.0 0.1 0.2 0.3])
Note that for this code just copy will be also enough but if for example you have an Array of objects that you mutate deepcopy should be used.
is there an easy way to create a sparse symmetric random matrix in Julia?
Julia has the command
sprand(m,n,d)
which "Creates a [sparse] m-by-n random matrix (of density d) with iid non-zero elements distributed uniformly on the half-open interval [0,1)[0,1)." But as far as I can tell this doesn't necessarily return a symmetric matrix.
I am looking for an equivalent command to MATLAB's
R = sprandsym(n,density)
which automatically creates a sparse symmetric random matrix. If such a command isn't implemented yet, what would be a workaround to transform the matrix returned by sprand(m,n,d) into a symmetric one?
Thank you!
You could Symmetric(sprand(10,10,0.4))
To avoid extra memory caveat mentioned in the comment to Michael Borregaard's answer, the following function takes a sparse matrix and drops the entries in the lower triangular part. If the SparseMatrixCSC format is unfamiliar, it also serves as a good presentation of how the format is manipulated:
function droplower(A::SparseMatrixCSC)
m,n = size(A)
rows = rowvals(A)
vals = nonzeros(A)
V = Vector{eltype(A)}()
I = Vector{Int}()
J = Vector{Int}()
for i=1:n
for j in nzrange(A,i)
rows[j]>i && break
push!(I,rows[j])
push!(J,i)
push!(V,vals[j])
end
end
return sparse(I,J,V,m,n)
end
Example usage:
julia> a = [0.5 1.0 0.0 ; 2.0 0.0 0.0 ; 0.0 0.0 0.0]
3×3 Array{Float64,2}:
0.5 1.0 0.0
2.0 0.0 0.0
0.0 0.0 0.0
julia> b = sparse(a)
3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries:
[1, 1] = 0.5
[2, 1] = 2.0
[1, 2] = 1.0
julia> c = droplower(b)
3×3 SparseMatrixCSC{Float64,Int64} with 2 stored entries:
[1, 1] = 0.5
[1, 2] = 1.0
julia> full(Symmetric(c)) # note this is symmetric although c isn't
3×3 Array{Float64,2}:
0.5 1.0 0.0
1.0 0.0 0.0
0.0 0.0 0.0
Operations on the SparseMatrixCSC often need to be customized for maximum efficiency. So, to get from a sparse matrix A to a symmetric sparse matrix with the same upper part, here is a custom version (it is a bit cryptic, but working):
function symmetrize(A::SparseMatrixCSC)
m,n = size(A)
m == n || error("argument expected to be square matrix")
rows = rowvals(A) ; vals = nonzeros(A)
a = zeros(Int,n) ; b = zeros(Int,n) ; c = 0
for i=1:n
for j in nzrange(A, i)
if rows[j]>=i
if rows[j]==i a[i] += 1 ; c += 1 ; end
break
end
a[i] += 1 ; b[rows[j]] += 1 ; c += 2
end
end
c == 0 && return SparseMatrixCSC(n, n, ones(n+1), nrows, nvals)
ncolptr = Vector{Int}(n+1)
nrows = Vector{Int}(c) ; nvals = Vector{eltype(A)}(c)
idx = 1
for i=1:n
ncolptr[i] = idx
if a[i]==0 a[i] = idx ; idx += b[i] ; continue ; end
for j in (0:a[i]-1)+first(nzrange(A, i))
nvals[idx] = vals[j] ; nrows[idx] = rows[j] ; idx += 1
rows[j] >= i && break
nvals[a[rows[j]]] = vals[j] ; nrows[a[rows[j]]] = i
a[rows[j]] += 1
end
a[i] = idx ; idx += b[i]
end
ncolptr[n+1] = idx
return SparseMatrixCSC(n, n, ncolptr, nrows, nvals)
end
And a sample run:
julia> f = sprand(5,5,0.2)
5×5 SparseMatrixCSC{Float64,Int64} with 5 stored entries:
[1, 1] = 0.981579
[3, 1] = 0.330961
[5, 1] = 0.527683
[4, 5] = 0.196898
[5, 5] = 0.579006
julia> full(f)
5×5 Array{Float64,2}:
0.981579 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.330961 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.196898
0.527683 0.0 0.0 0.0 0.579006
julia> full(symmetrize(f))
5×5 Array{Float64,2}:
0.981579 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.196898
0.0 0.0 0.0 0.196898 0.579006
This version should be faster than others, but this still needs to be benchmarked (and some #inbounds added in the for loops).
How are regular, non-integer sequences generated in julia?
I'm trying to get 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
In MATLAB, I would use
0.1:0.1:1
And in R
seq(0.1, 1, by = 0.1)
But I can't find anything except integer sequences in julia (e.g., 1:10). Searching for "sequence" in the docs only gives me information about how strings are sequences.
Similarly to Matlab, but with the difference that 0.1:0.1:1 defines a Range:
julia> typeof(0.1:0.1:1)
Range{Float64} (constructor with 3 methods)
and thus if an Array is needed:
julia> [0.1:0.1:1]
10-element Array{Float64,1}:
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
Unfortunately, this use of Range is only briefly mentioned at this point of the documentation.
Edit: As mentioned in the comments by #ivarne it is possible to achieve a similar result using linspace:
julia> linspace(.1,1,10)
10-element Array{Float64,1}:
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
but note that the results are not exactly the same due to rounding differences:
julia> linspace(.1,1,10)==[0.1:0.1:1]
false
The original answer is now deprecated. You should use collect() to generate a sequence.
## In Julia
> collect(0:.1:1)
10-element Array{Float64,1}:
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
## In R
> seq(0, 1, .1)
[1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
They are generated the same way as in Matlab
julia> sequence = 0:.1:1
0.0:0.1:1.0
Alternatively, you can use the range() function, which allows you to specify the length, step size, or both
julia> range(0, 1, length = 5)
0.0:0.25:1.0
julia> range(0, 1, step = .01)
0.0:0.01:1.0
julia> range(0, step = .01, length = 5)
0.0:0.01:0.04
You can still do all of the thinks you would normally do with a vector, eg indexing
julia> sequence[4]
0.3
math and stats...
julia> sum(sequence)
5.5
julia> using Statistics
julia> mean(sequence)
0.5
This will (in most cases) work the same way as a vector, but nothing is actually allocated. It can be comfortable to make the vector, but in most cases you shouldn't (it's less performant). This works because
julia> sequence isa AbstractArray
true
If you truly need the vector, you can collect(), splat (...) or use a comprehension:
julia> v = collect(sequence)
11-element Array{Float64,1}:
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
julia> v == [sequence...] == [x for x in sequence]
true