Lower Triangular Matrix equal to value in Julia - julia

I am trying to find a lower triangular matrix in Julia and place that matrix in a zeros matrix (replacing the zeros). I then want to set the lower triangular matrix equal to the value c. In R this would look something like this:
mat <- matrix(0, n,n)
mat[lower.tri(mat, diag=FALSE)] <- c
with an output that looks like this:
[,1] [,2]
[1,] 0.0000000 0
[2,] 0.4646787 0
I am able to make the zeros matrix in Julia, but I do not know how to place the lowertriangular function inside of the it along with the c value.

Here's probably the closest equivalent in Julia:
julia> n = 3; c = 0.4646787; A = zeros(n,n);
julia> A[tril!(trues(size(A)), -1)] .= c;
julia> A
3×3 Array{Float64,2}:
0.0 0.0 0.0
0.464679 0.0 0.0
0.464679 0.464679 0.0
Of course, one of the big advantages in Julia is that you don't need to worry about creating these clever one-liners nearly as much. Writing out the naive for loops is quite easy and should have similar performance:
julia> for j in 1:size(A, 2), i in j+1:size(A, 1)
A[i, j] = c
end
julia> A
3×3 Array{Float64,2}:
0.0 0.0 0.0
0.464679 0.0 0.0
0.464679 0.464679 0.0

Related

How to normalize the columns of a matrix in Julia

Given a matrix A of dimensions m,n, how would one normalize the columns of that matrix by some function or other process in Julia (the goal would be to normalize the columns of A so that our new matrix has columns of length 1)?
If you want a new matrix then mapslices is probably what you want:
julia> using LinearAlgebra
julia> x = rand(5, 3)
5×3 Matrix{Float64}:
0.185911 0.368737 0.533008
0.957431 0.748933 0.479297
0.567692 0.477587 0.345943
0.743359 0.552979 0.252407
0.944899 0.185316 0.375296
julia> y = mapslices(x -> x / norm(x), x, dims=1)
5×3 Matrix{Float64}:
0.112747 0.327836 0.582234
0.580642 0.66586 0.523562
0.344282 0.424613 0.377893
0.450816 0.491642 0.275718
0.573042 0.164761 0.409956
julia> map(norm, eachcol(y))
3-element Vector{Float64}:
1.0
1.0
1.0
If by length 1 you mean like with norm 1 maybe this could work
using LinearAlgebra
# if this is your matrix
m = rand(10, 10)
# norm comes from LinearAlgebra
# or you can define it as
# norm(x) = sqrt(sum(i^2 for i in x))
g(x) = x ./ norm(x)
# this has columns that have approximately norm 1
normed_m = reduce(hcat, g.(eachcol(m)))
Though there are likely better solutions I don't know!
mapslices seems to have some issues with performance. On my computer (and v1.7.2) this is 20x faster:
x ./ norm.(eachcol(x))'
This is an in-place version (because eachcol creates views), which is faster still (but still allocates a bit):
normalize!.(eachcol(x))
And, finally, some loop versions that are 40-70x faster than mapslices for the 5x3 matrix:
# works in-place:
function normcol!(x)
for col in eachcol(x)
col ./= norm(col)
end
return x
end
# creates new array:
normcol(x) = normcol!(copy(x))
Edit: Added a one-liner with zero allocations:
foreach(normalize!, eachcol(x))
The reason this does not allocate anything, unlike normalize!., is that foreach doesn't return anything, which makes it useful in cases where output is not needed.

broadcasting vector multiplication with a 3 vector and n vector in julia

I have a 3-vector c = [0.7, 0.5, 0.2] and I want to multiply it with everything in an n-vector x = rand((-1,1),n) such that I get a resulting n+2-vector y where y[i] == x[i]*c[3] + x[i-1]*c[2] + x[i-2]*c[1]
How should I do this in julia? I feel like there should be a way to broadcast the smaller 3 vector to all the values in the n vector. And for the edge cases, if i-1 or i-2 is out of bounds I just want zero for those components.
If I understand your question correctly you want a convolution, with a twist that in a standard convolution the vector c would be reversed. You can use e.g. DSP.jl for this.
Is this what you want?
julia> using DSP
julia> c = [0.7, 0.5, 0.2]
3-element Array{Float64,1}:
0.7
0.5
0.2
julia> conv([10, 100, 1000, 10000], reverse(c))
6-element Array{Float64,1}:
1.9999999999996967
25.0
257.0000000000003
2569.9999999999995
5700.0
6999.999999999998
You can also manually implement it using dot from the LinearAlgebra module like this:
julia> using LinearAlgebra
julia> x = [10, 100, 1000, 10000]
4-element Array{Int64,1}:
10
100
1000
10000
julia> y = [0;0;x;0;0]
8-element Array{Int64,1}:
0
0
10
100
1000
10000
0
0
julia> [dot(#view(y[i:i+2]), c) for i in 1:length(x)+2]
6-element Array{Float64,1}:
2.0
25.0
257.0
2570.0
5700.0
7000.0
Here's one approach that uses ShiftedArrays.jl.
using ShiftedArrays
c = [0.7, 0.5, 0.2]
Create lagged versions of x, with initial zeros:
x = 1:5
xminus1 = lag(x, 1, default=0)
xminus2 = lag(x, 2, default=0)
Horizontally concatenate the vectors and use matrix multiplication with c:
X = [xminus2 xminus1 x]
X * c
Here's what X and X * c look like at the REPL:
julia> X = [xminus2 xminus1 x]
5×3 Array{Int64,2}:
0 0 1
0 1 2
1 2 3
2 3 4
3 4 5
julia> X * c
5-element Array{Float64,1}:
0.2
0.9
2.3
3.7
5.1
Note that this produces an output vector of length length(x), not length(x) + 2. I'm not sure how it would make sense for the output to be of length length(x) + 2, as you requested in the question.
I have a package for doing such things. The simplest use is like this:
julia> c = [0.7, 0.5, 0.2]; # from question
julia> x = [10, 100, 1000, 10_000]; # from another answer
julia> using Tullio, OffsetArrays
julia> #tullio y[i] := x[i]*c[3] + x[i-1]*c[2] + x[i-2]*c[1]
2-element OffsetArray(::Vector{Float64}, 3:4) with eltype Float64 with indices 3:4:
257.0
2570.0
julia> #tullio y[i] := x[i+k-3] * c[k] # sum over all k, range of i that's safe
2-element OffsetArray(::Array{Float64,1}, 3:4) with eltype Float64 with indices 3:4:
257.0
2570.0
Since eachindex(c) == 1:3, that's the range of k-values which this sums over, and the range of i is as big as it can be so that i+k-3 stays inside eachindex(x) == 1:4.
To extend the range of i by padding x with two zeros in each direction, write pad(i+k-3, 2). And to compute the shift of i needed to produce an ordinary 1-based Array, write i+_ on the left (and then the -3 makes no difference). Then:
julia> #tullio y[i+_] := x[pad(i+k, 2)] * c[k]
6-element Array{Float64,1}:
2.0
25.0
257.0
2570.0
5700.0
7000.0
On larger arrays, this won't be very fast (at the moment) as it must check at every step whether it is inside x or out in the padding. It's very likely that DSP.conv is a bit smarter about this. (Edit -- DSP.jl seems never to be faster for this c; with a kernel of length 1000 it's faster with 10^6 elements in x.)

Eigenvalues of a matrix, assuming symmetry

I am trying to find the eigenvalues of the following 2 X 2 matrix (equal to a) in Julia:
2×2 Array{Float64,2}:
0.120066 0.956959
0.408367 0.422321
I have the same array in R, and running the following R command I get this output:
eigen(a, symmetric=T, only.values=T)
$values
[1] 0.706626 -0.164245
In Julia, however, when I run this command I get this output:
eigvals(LowerTriangular(a))
2-element Array{Float64,1}:
0.120066
0.422321
Is there a way to replicate the R eigen() function for symmetric matrices in Julia because my way with the LowerTriangular function is not working?
Use Symmetric function like this:
julia> eigvals(Symmetric(x, :L))
2-element Array{Float64,1}:
-0.164241
0.706628
Since Julia 0.7 you will have to use using LinearAlgebra to import the functions.
> x
[,1] [,2]
[1,] 0.120066 0.956959
[2,] 0.408367 0.422321
In Julia, eigvals(LowerTriangular(a)) computes the eigen values of the lower triangular part of x (that is, the entries of the strict upper triangular part are set to 0):
> xx <- x
> xx[1,2] <- 0
> eigen(xx, only.values = TRUE)
$values
[1] 0.422321 0.120066 # same as Julia
While in R, eigen(x, symmetric=TRUE) assumes x is symmetric and takes the lower triangular part to derive the other entries:
> xx <- x
> xx[1,2] <- x[2,1]
> eigen(xx, only.values = TRUE)
$values
[1] 0.7066279 -0.1642409
> eigen(x, only.values = TRUE, symmetric = TRUE)
$values
[1] 0.7066279 -0.1642409

Tabular data to matrix in R

I'm trying to remove the shackles of some legacy code that we use to make decision trees in a retail setting. I got to playing with hclust in R and it's beautiful and I'd like to use it. The heavy lifting for calculating distances is done in SQL and I get an output like this:
main with dist
A A 0.00
A B 1.37
A C 0.64
B B 0
B C 0.1
C C 0
That's loaded as a data frame right now (just reading the SQL query dump), but hclust wants a matrix of distances. E.g.,:
A B C
--+-----------------
A | 0
B | 1.37 0
C | 0.64 0.1 0
My thinking is too procedural and I'm trying to do it in nested loops at the moment. Can someone point me in the direction of something more R-idiomatic to do this?
Thank!
If you are looking for an actual distance matrix in R, try:
as.dist(xtabs(dist ~ with + main, mydf), diag = TRUE)
# A B C
# A 0.00
# B 1.37 0.00
# C 0.64 0.10 0.00
I'm presuming that the combinations of "main" and "with" are unique, otherwise xtabs would sum the "dist" values.
I would suggest to change from letters to numbers (which is straight forward using the ASCII codes) and then use the linearized indices of R matrices to access each pair in a vectorwise manner.
Minimal example:
N <- 3
d <- data.frame(x = c(1,2), y = c(2,3), v = c(0.1, 0.2))
m <- matrix(0, N, N)
m[(d$y-1)*N+d$x] = d$v
The output is:
[,1] [,2] [,3]
[1,] 0 0.1 0.0
[2,] 0 0.0 0.2
[3,] 0 0.0 0.0
EDIT: To preserve arbitrary strings as row and col names, consider the following example:
codes <- c('A','B','C')
N <- 3
d <- data.frame(x = c('A','B'), y = c('B','C'), v = c(0.1, 0.2))
m <- matrix(0, N, N)
m[(vapply(d$y, function(x) which(codes == x), 0)-1)*N+
vapply(d$x, function(x) which(codes == x), 0)] = d$v
rownames(m) = codes
colnames(m) = codes

Looping through vector elements using macro variables

Suppose the user sets dim (1, ...., n), and then one or more x_i variables values, with i = 1,..., n.
After some more computations I need to automatically return a dim-dimensional vector vec of the form: (0, 0, 0.2, 0, 0, ..., 0.3), where in this specific case the user has set:
dim <- 10
x_3 <- 0.2
x_10 <- 0.3
Of course it is immediate to do:
vec <- rep(0, dim)
vec[3] <- x_3
vec[10] <- x_10
However, since I want to automatize as much operations as possible, I ask you how would you link the x_i variables together with the "respective" element of vec, taking into account that a priori it is not known which/how many variables will be set different from 0.
In other languages this could be done using a for-loop with macro variables... the syntax is wrong, but the idea is something like this:
vec <- rep(0, dim)
for (i in 1:dim) {
if (as.integer(exists(x_i))==1) {
vec[i] <- x_i
}
}
what would you suggest? Thanks!
sapply(paste("x_",seq(dim),sep=""),function(x) if(exists(x)) get(x) else 0)
x_1 x_2 x_3 x_4 x_5 x_6 x_7 x_8 x_9 x_10
0.0 0.0 0.2 0.0 0.0 0.0 0.0 0.0 0.0 0.3

Resources