Broadcasting vectors and matrices in Julia - julia

I would like to use a dotted version of a scalar function to calculate values for an entire matrix of inputs. The function is defined as follows:
function SpecificCharge(U, r, B)
( 2 * U ) / ( r^2 * B^2 )
end
and I would like to give it the following inputs:
const Us = [ # voltages U
228.9, 243, 257, 271, 285, 300
]
const Rs = [ # radii r
9 7 5.8 5 4.3 3.9;
10.5 8.1 6.7 5.7 4.9 4.5;
10.1 8.3 7.1 6.5 6 4.8;
11.1 9.0 7.2 6.5 5.6 5.1;
10.5 8.3 7.8 6.5 5.7 5.4;
11.9 8.9 8.0 7.4 6.2 5.5
]
const Bs = [ # flux densities B
0.0007332339999999999, 0.00089328, 0.0010421599999999999, 0.00119104, 0.00133992, 0.0014873112
]
# Calling the dotted version of the function
specific_charges = SpecificCharge.(Us, Rs, Bs)
The result should be a matrix of same dimensions as Rs, with each radius replaced by the corresponding specific charge, given by SpecificCharge. There is one flux density corresponding to each U--B pair, and the rows in Rs correspond to voltages U and columns to flux densities B.
The problem is, I'm not sure how broadcasting works in Julia. Does the function SpecificCharge. work as is, if I just transpose the vectors Us and Bs appropriately, or do I need to complicate the function itself to make this work?

Does the function SpecificCharge. work as is, if I just transpose the vectors Us and Bs appropriately, or do I need to complicate the function itself to make this work?
Did you try it? It works as written, however, I am guessing you want to transpose either Us or Bs to get the correct "coupling".
When you use broadcast with different array dimensions (vectors and matrices in your example) Julia will "extend" arrays in the singleton dimensions. E.g. a vector will be extended to a matrix with a copy of the vector in each column. Here is an example to illustrate this
julia> A = ["A1", "A2"];
julia> B = ["B11" "B12" "B13";
"B21" "B22" "B23"];
julia> f(args...) = join(args, ", ");
julia> f.(A, B)
2×3 Array{String,2}:
"A1, B11" "A1, B12" "A1, B13"
"A2, B21" "A2, B22" "A2, B23"
As you can see, the vector A has been extended in the singleton dimension to
julia> A2 = [A A A]
2×3 Array{String,2}:
"A1" "A1" "A1"
"A2" "A2" "A2"
such that it has the same size as B, and then f is applied to each pair. To extend a vector in the other dimension you need to permute it;
julia> C = ["C1", "C2", "C3"];
julia> f.(B, permutedims(C))
2×3 Array{String,2}:
"B11, C1" "B12, C2" "B13, C3"
"B21, C1" "B22, C2" "B23, C3"
and now C has been extended in the first dimension (the singleton dimension), essentially
julia> C2 = [permutedims(C); permutedims(C); permutedims(C)]
3×3 Array{String,2}:
"C1" "C2" "C3"
"C1" "C2" "C3"
"C1" "C2" "C3"

Related

What is the function of $y at the end of an interpolation function?

I am learning interpolation using R. I found a code online and I am not sure about the function of $y at the end of the code. I tried to run the code with and without $y and I cannot really tell the differences.
test <- approx(x, y, xout=c, rule=2) $y
$ is one way to access elements of a list in R.
(Some more explanation: https://stackoverflow.com/a/1169495/6851825 or https://stackoverflow.com/a/32819641/6851825)
This code will produce a list of x values (from the c term we provided) and interpolated y values.
x = 1:3
y = 4:6
c = seq(1,3,by = 0.5)
approx (x, y, xout=c, rule=2)
The output R gives us tells us that it's a list with components called x and y.
$x
[1] 1.0 1.5 2.0 2.5 3.0
$y
[1] 4.0 4.5 5.0 5.5 6.0
We could examine the structure of this output by running:
str(approx (x, y, xout=c, rule=2))
#List of 2
# $ x: num [1:5] 1 1.5 2 2.5 3
# $ y: num [1:5] 4 4.5 5 5.5 6
If we just want the y part, the interpolated values, we can run approx (x, y, xout=c, rule=2)$y to get it. Instead of a list, this is a numeric vector.
[1] 4.0 4.5 5.0 5.5 6.0

Julia: How can we compute the adjoint or classical adjoint (Linear Algebra)?

I wan to compute the classical adjoint in Julia 1.0
For this I copied the matrix given as an example in wikipedia
julia> B = [-3 2 -5; -1 0 -2; 3 -4 1]
3×3 Array{Int64,2}:
-3 2 -5
-1 0 -2
3 -4 1
That seems to me to compute the transpose of B and not its adjoint. Instead, we should get this (from wikipedia):
and tried to get its adjoint using the adjoint() function which is mentionned in the Julia documentation here despite that the doc does not specifically said what this function does
julia> adjoint(B)
3×3 Adjoint{Int64,Array{Int64,2}}:
-3 -1 3
2 0 -4
-5 -2 1
Instead I want to get this:
In Matlab I get indeed:
>> adjoint(B)
ans =
-8.0000 18.0000 -4.0000
-5.0000 12.0000 -1.0000
4.0000 -6.0000 2.0000
Julia's adjoint is defined as the transpose of the complex conjugate of the input matrix. However, you seem to want the adjugate matrix:
The adjugate has sometimes been called the "adjoint", but today the "adjoint" of a matrix normally refers to its corresponding adjoint operator, which is its conjugate transpose.
You can compute the adjugate matrix by inverting, and then multiplying by the determinant:
julia> det(B) * inv(B)
3×3 Array{Float64,2}:
-8.0 18.0 -4.0
-5.0 12.0 -1.0
4.0 -6.0 2.0
Thanks to #Antoine Levitt and #Syx Pek on the Julia Slack for giving the suggestion of inverting and multiplying by determinant.
Original answer:
The adjugate matrix seems to be the transpose of the matrix of cofactors. Below is a naïve implementation of finding cofactors:
# import Pkg; Pkg.add("InvertedIndices")
using InvertedIndices # for cleaner code, you can remove this if you really want to.
function cofactor(A::AbstractMatrix, T = Float64)
ax = axes(A)
out = similar(A, T, ax)
for col in ax[1]
for row in ax[2]
out[col, row] = (-1)^(col + row) * det(A[Not(col), Not(row)])
end
end
return out
end
Then, to find the adjugate, you only need to transpose (transpose(cofactor(B))).
The answer is:
julia> cofactor(B, Float64) |> transpose
3×3 Transpose{Float64,Array{Float64,2}}:
-8.0 18.0 -4.0
-5.0 12.0 -1.0
4.0 -6.0 2.0
which is equivalent to what Matlab gives.
Edit: #Antoine Levitt on the Julia slack pointed out that this is essentially a rescaled inverse matrix, so if you figure out the scaling factor, you can just do inv(B) * scaling_factor (in the case of this matrix, it's 6).

Using a Function With 2 Inputs in a Loop With Combinations of Inputs to Create a Data Frame

I've created a custom function to calculate values based on two inputs.
# function
info.theta <- function(theta, delta) {
P = 1/(1+exp(-1*(theta-delta)))
Q = 1 -P
1*P*Q
}
I'd like to use the function to calculate the value for all possible combinations of values for two sequences of interest.
# for each input of the function create sequences of values to explore
thetas <- seq(-4, 4, by = .5)
deltas <- seq(-4, 4, by = .5)
I'd like to end up with a data frame with a column labeled thetas, deltas and information, where both theta and delta are the values for the sequence that were used in the function, and information is the output of the function for each combination of theta and delta.
I'm at a loss for how to execute the last point, as this level of coding is new to me. My hunch was maybe a nested for loop. This is obviously not correct, but it is as close as I can get to a start. How would I use the function in the way I described to generate the desired data frame?
#nested for loop
y <- NULL
for(i in sequence) {
for(j in deltas) {
tmp <- info.theta(i, j)
y <- rbind(y, tmp)
}
}
y
You can use outer to get matrix of values:
outer(thetas,deltas,info.theta)
A slight change to your original function:
info.theta <- function(theta, delta) {
P = 1/(1+exp(-1*(theta-delta)))
Q = 1 -P
data.frame(theta=theta,delta=delta, information=1*P*Q)
}
Because data.frames are cooler.
Now:
td_grid<-expand.grid(thetas, deltas)
info.theta(td_grid[,1],td_grid[,2])
results in:
theta delta information
1 -4.0 -4.0 0.2500000000
2 -3.5 -4.0 0.2350037122
3 -3.0 -4.0 0.1966119332
4 -2.5 -4.0 0.1491464521
5 -2.0 -4.0 0.1049935854
6 -1.5 -4.0 0.0701037165
7 -1.0 -4.0 0.0451766597
8 -0.5 -4.0 0.0284530239
9 0.0 -4.0 0.0176627062
10 0.5 -4.0 0.0108662297
11 1.0 -4.0 0.0066480567

Weighted rowSums of a matrix

I have a matrix like this:
I would like to sum every value of a single row but weighted.
Example: Given a specific row, the sum would be:
S = x1 * loan + x2 * mortdue + x3 * value + ...
x1, x2, x3, ... are predefined values.
I tried rowSums() and things like that but I have not been able to figure out how to do it properly.
You are looking for a matrix-vector multiplication. For example, if you have a matrix:
set.seed(0)
A <- matrix(round(rnorm(9), 1), 3)
# [,1] [,2] [,3]
#[1,] 1.3 1.3 -0.9
#[2,] -0.3 0.4 -0.3
#[3,] 1.3 -1.5 0.0
And you have another vector x, which is what you called "ponderation":
x <- round(rnorm(3), 1)
#[1] 2.4 0.8 -0.8
You can do
drop(A %*% x)
#[1] 4.88 -0.16 1.92
The drop just convert the result single column matrix into a 1D vector.
You can have a quick check to see this is what you want:
sum(A[1, ] * x)
#[1] 4.88
sum(A[2, ] * x)
#[1] -0.16
sum(A[3, ] * x)
#[1] 1.92
Compared with rowSums(), you can also think such computation as a "weighted rowSums".
At the moment, it seems more likely that you have a data frame rather than a matrix. You can convert this data frame to matrix by as.matrix().

Multiply each component of vector by another vector (resulting in vector of length m*n)

Say I am making parts that come in three sizes, and each size has a certain tolerance:
target <- c(2, 4, 6)
tolerance <- c(0.95, 1.05)
What I'd like to end up with is an array that contains the limits of the tolerance for each target (i.e. target*0.95, target*1.05):
tol = (2*0.95, 2*1.05, 4*0.95, 4*1.05, 6*0.95, 6*1.05)
Here's a really ugly way of getting there, but I know there is a simple way to do this.
j<-1
tol<-NULL
for (i in target){
tol[j] <- i*tolerance[1]
tol[j+1] <- i*tolerance[2]
j<-j+2
}
The vector tol can be calculated using outer() like this:
tol <- c(outer(tolerance,target))
#> tol
#[1] 1.9 2.1 3.8 4.2 5.7 6.3
You can achieve that using matrix product:
target <- c(2, 4, 6)
tolerance <- c(0.95, 1.05)
target %*% t(tolerance)
[,1] [,2]
[1,] 1.9 2.1
[2,] 3.8 4.2
[3,] 5.7 6.3
The other answer would have my preference, but this alternative might generalise better in some specific context (more than two vectors)
Reduce("*", expand.grid(list(tolerance, target)))
Mostly for fun - using R's recycling:
rep(target, each = length(tolerance)) * tolerance
#[1] 1.9 2.1 3.8 4.2 5.7 6.3

Resources