Calculation of quadratic form using broadcasting in Julia - multidimensional-array

I want to calculate a vector of a quadratic form, extracting the submatrix from 3 by 3 by 5 arrays. However, I cannot make the quadratic form using broadcasting (i.e., macro "#."). When using “for” statement, we can calculate the vector of the quadratic form. I have no idea how to conduct matrix operations using “#.” (I am reluctant to expand the quadratic form to calculate the vector.)
By contrast, the inner product is computable using “#.”.
The example code is as follows:
using LinearAlgebra
a1=[5 7 2; 2 1 5; 6 2 3]
a2=[2 7 1; 3 7 2; 1 2 3]
a3=[8 5 9; 1 1 3; 2 2 3]
a4=[2 5 6; 3 5 1; 1 1 1]
a5=[7 8 1; 5 1 3; 1 5 2]
z=cat(a1,a2,a3,a4,a5,dims=3)
##### case of inner product
x=zeros(5,3)
wz = reshape([],0)
for k in 1:5
w = hcat(z[[1],[1],k], z[2,2,k]) * hcat(z[[1],[1],k], z[[2],[2],k])'
#println(w)
wz=vcat(wz, w)
end
#. wz=convert(Float64,wz)
wz=Matrix{Float64}(wz)
x[:,3]=wz
# [inner product] same result, the 3rd column vector [26.0, 53.0, 65.0, 29.0, 50.0]
display(x)
x=zeros(5,3)
#. x[:,3] = dot(hcat(z[1,1,:],z[2,2,:]), hcat(z[1,1,:],z[2,2,:])) # ok, working
# [inner product] same result, the 3rd column vector [26.0, 53.0, 65.0, 29.0, 50.0]
display(x)
##### case of quadratic form
x=zeros(5,3)
wy = reshape([],0)
for k in 1:5
w = hcat(z[[1],[1],k], z[[2],[2],k]) * z[[1,3],[1,3],k] * hcat(z[[1],[1],k], z[[2],[2],k])'
#println(w)
wy=vcat(wy, w)
end
#. wy=convert(Float64,wy)
wy=Matrix{Float64}(wy)
x[:,3]=wy
# [quadratic form] distinct result, the 3rd column vector [168.0, 183.0, 603.0, 103.0, 359.0]
display(x)
# generating five 2 by 2 matrices, distinct result
#. dot(hcat(z[[1],[1],:],z[[2],[2],:]), z[[1,3],[1,3],:], hcat(z[[1],[1],:],z[[2],[2],:]))
# obtaining ERROR: DimensionMismatch("arrays could not be broadcast to a common size; got a dimension with lengths 2 and 5")
#. dot(hcat(z[1,1,:],z[2,2,:]), z[[1,3],[1,3],:], hcat(z[1,1,:],z[2,2,:]))
Would you mind giving helps and suggestions how to get the calculation of 3rd column vector [168.0, 183.0, 603.0, 103.0, 359.0] (which is made from the quadratic form) in the above code using "#."?

EDIT:
Perhaps the question is about specifically how to make broadcasting work in this case. If so:
#views dot.(vcat.(z[1,1,:],z[2,2,:]),getindex.(Ref(z),Ref([1,3]),Ref([1,3]),axes(z,3)),vcat.(z[1,1,:],z[2,2,:]))
should be a possible clarification. Or with the #. macro (though it doesn't seem simpler):
#. dot(vcat(z[1,1,:],z[2,2,:]),getindex($Ref(z),$Ref([1,3]),$Ref([1,3]),$axes(z,3)),vcat(z[1,1,:],z[2,2,:]))
ORIGINAL:
One way to calculate this:
[
[z[1,1,k] z[2,2,k]]*z[[1,3],[1,3],k]*[z[1,1,k] z[2,2,k]]' |> first
for k ∈ axes(z,3)
]
giving:
5-element Vector{Int64}:
168
183
603
103
359
(the |> first turns 1x1 matrix into scalar)
Option 2:
[let t = z[[1,3],[1,3],k] ; sum(z[i,i,k]*t[i,j]*z[j,j,k] for i ∈ (1,2), j ∈ (1,2)) ; end for k ∈ 1:5]
or:
[let t = z[[1,3],[1,3],k], v = [z[1,1,k],z[2,2,k]] ; dot(v,t,v) ; end for k ∈ 1:5]
or (this is pretty cool):
map((z;t=z[[1,3],[1,3]],v=[z[1,1],z[2,2]])->dot(v,t,v), eachslice(z,dims=3))

Related

Is there function to take the outer product of column vectors of a matrix?

I need to take the outer products of each column vector of a matrix with each column vector of another matrix
Example:
A=[1,2,3; 3,1,4; 4,1,3]
B=[2,1,3; 4,1,2; 3,2,1]
for each column of "A", I want to take it's outer product with each column of "B" and sum them all. I can do it in a loop but it is slow. Is there any other way of doing it fast?.
for example:
U=zeros(3,3)
for n=1:size(A,1)
for m=1:size(B,1)
U=U+A[:,n]'*B[:,m]
end
end
I think this is what the question wants:
function outsum1(A,B)
U = zeros(size(A,1), size(B,1))
for n=1:size(A,1) # independent loops n and m
for m=1:size(B,1)
U = U + A[:,n]*B[:,m]' # transpose the second for outer product?
end
end
U
end
A = [1 2 3; 3 1 4; 4 1 3]; # can't mix , (vectors) and ; / space (concatenation)
B = [2 1 3; 4 1 2; 3 2 1]
outsum1(A,B) == [36 42 36; 48 56 48; 48 56 48]
If so, there are ways that you can make this function more efficient (e.g. #views U .= U .+ A[:,n] .* B[:,m]'). But the most important one is probably to notice that these loops don't have to be nested. In index notation:
U[i,j] = sum_m,n A[i,n] * B[j,m]
= (sum_n A[i,n]) * (sum_m B[j,m])
The first form has 4 nested loops, the second has only 2. So this function will be much faster for large A, by roughly a factor length(A):
outsum2(A,B) = sum(A, dims=2) .* sum(B, dims=2)'
outsum2(A,B) == [36 42 36; 48 56 48; 48 56 48] # same answer
Another answer interprets "outer products of each column vector of a matrix with each column vector of another" to mean one sum over columns, not two. That is very different, and in index notation it reads:
U[i,j] = sum_n A[i,n] * B[j,n]
This is matrix multiplication, U = A * B'.

Is there a function f(n) that returns the n:th combination in an ordered list of combinations without repetition?

Combinations without repetitions look like this, when the number of elements to choose from (n) is 5 and elements chosen (r) is 3:
0 1 2
0 1 3
0 1 4
0 2 3
0 2 4
0 3 4
1 2 3
1 2 4
1 3 4
2 3 4
As n and r grows the amount of combinations gets large pretty quickly. For (n,r) = (200,4) the number of combinations is 64684950.
It is easy to iterate the list with r nested for-loops, where the initial iterating value of each for loop is greater than the current iterating value of the for loop in which it is nested, as in this jsfiddle example:
https://dotnetfiddle.net/wHWK5o
What I would like is a function that calculates only one combination based on its index. Something like this:
tuple combination(i,n,r) {
return [combination with index i, when the number of elements to choose from is n and elements chosen is r]
Does anyone know if this is doable?
You would first need to impose some sort of ordering on the set of all combinations available for a given n and r, such that a linear index makes sense. I suggest we agree to keep our combinations in increasing order (or, at least, the indices of the individual elements), as in your example. How then can we go from a linear index to a combination?
Let us first build some intuition for the problem. Suppose we have n = 5 (e.g. the set {0, 1, 2, 3, 4}) and r = 3. How many unique combinations are there in this case? The answer is of course 5-choose-3, which evaluates to 10. Since we will sort our combinations in increasing order, consider for a minute how many combinations remain once we have exhausted all those starting with 0. This must be 4-choose-3, or 4 in total. In such a case, if we are looking for the combination at index 7 initially, this implies we must subtract 10 - 4 = 6 and search for the combination at index 1 in the set {1, 2, 3, 4}. This process continues until we find a new index that is smaller than this offset.
Once this process concludes, we know the first digit. Then we only need to determine the remaining r - 1 digits! The algorithm thus takes shape as follows (in Python, but this should not be too difficult to translate),
from math import factorial
def choose(n, k):
return factorial(n) // (factorial(k) * factorial(n - k))
def combination_at_idx(idx, elems, r):
if len(elems) == r:
# We are looking for r elements in a list of size r - thus, we need
# each element.
return elems
if len(elems) == 0 or len(elems) < r:
return []
combinations = choose(len(elems), r) # total number of combinations
remains = choose(len(elems) - 1, r) # combinations after selection
offset = combinations - remains
if idx >= offset: # combination does not start with first element
return combination_at_idx(idx - offset, elems[1:], r)
# We now know the first element of the combination, but *not* yet the next
# r - 1 elements. These need to be computed as well, again recursively.
return [elems[0]] + combination_at_idx(idx, elems[1:], r - 1)
Test-driving this with your initial input,
N = 5
R = 3
for idx in range(choose(N, R)):
print(idx, combination_at_idx(idx, list(range(N)), R))
I find,
0 [0, 1, 2]
1 [0, 1, 3]
2 [0, 1, 4]
3 [0, 2, 3]
4 [0, 2, 4]
5 [0, 3, 4]
6 [1, 2, 3]
7 [1, 2, 4]
8 [1, 3, 4]
9 [2, 3, 4]
Where the linear index is zero-based.
Start with the first element of the result. The value of that element depends on the number of combinations you can get with smaller elements. For each such smaller first element, the number of combinations with first element k is n − k − 1 choose r − 1, with potentially some of-by-one corrections. So you would sum over a bunch of binomial coefficients. Wolfram Alpha can help you compute such a sum, but the result still has a binomial coefficient in it. Solving for the largest k such that the sum doesn't exceed your given index i is a computation you can't do with something as simple as e.g. a square root. You need a loop to test possible values, e.g. like this:
def first_naive(i, n, r):
"""Find first element and index of first combination with that first element.
Returns a tuple of value and index.
Example: first_naive(8, 5, 3) returns (1, 6) because the combination with
index 8 is [1, 3, 4] so it starts with 1, and because the first combination
that starts with 1 is [1, 2, 3] which has index 6.
"""
s1 = 0
for k in range(n):
s2 = s1 + choose(n - k - 1, r - 1)
if i < s2:
return k, s1
s1 = s2
You can reduce the O(n) loop iterations to O(log n) steps using bisection, which is particularly relevant for large n. In that case I find it easier to think about numbering items from the end of your list. In the case of n = 5 and r = 3 you get choose(2, 2)=1 combinations starting with 2, choose(3,2)=3 combinations starting with 1 and choose(4,2)=6 combinations starting with 0. So in the general choose(n,r) binomial coefficient you increase the n with each step, and keep the r. Taking into account that sum(choose(k,r) for k in range(r,n+1)) can be simplified to choose(n+1,r+1), you can eventually come up with bisection conditions like the following:
def first_bisect(i, n, r):
nCr = choose(n, r)
k1 = r - 1
s1 = nCr
k2 = n
s2 = 0
while k2 - k1 > 1:
k3 = (k1 + k2) // 2
s3 = nCr - choose(k3, r)
if s3 <= i:
k2, s2 = k3, s3
else:
k1, s1 = k3, s3
return n - k2, s2
Once you know the first element to be k, you also know the index of the first combination with that same first element (also returned from my function above). You can use the difference between that first index and your actual index as input to a recursive call. The recursive call would be for r − 1 elements chosen from n − k − 1. And you'd add k + 1 to each element from the recursive call, since the top level returns values starting at 0 while the next element has to be greater than k in order to avoid duplication.
def combination(i, n, r):
"""Compute combination with a given index.
Equivalent to list(itertools.combinations(range(n), r))[i].
Each combination is represented as a tuple of ascending elements, and
combinations are ordered lexicograplically.
Args:
i: zero-based index of the combination
n: number of possible values, will be taken from range(n)
r: number of elements in result list
"""
if r == 0:
return []
k, ik = first_bisect(i, n, r)
return tuple([k] + [j + k + 1 for j in combination(i - ik, n - k - 1, r - 1)])
I've got a complete working example, including an implementation of choose, more detailed doc strings and tests for some basic assumptions.

Julia: find maximum along columns in array

Suppose we have an array defined like this:
a=[1 2; 3 4; 5 5; 7 9; 1 2];
In Matlab, we could find the maximum values by writing:
[x y] = max(a)
x =
7 9
In Julia, we could use:
a=[1 2; 3 4; 5 5; 7 9; 1 2]
findmax(a,1)
returning:
([7 9],
[4 9])
However, I am interested not only in finding [7 9] for the two columns, but also their relative position within each column, like [4, 4]. Of course, I can write a bit more of coding lines, but can I do it directly with findmax?
The second matrix returned by findmax is the linear index of the locations of the maxima over the entire array. You want the position within each column; to get that, you can convert the linear indices into subscripts with ind2sub. Then the first element of the subscript tuple is your row index.
julia> vals, inds = findmax(a, 1)
(
[7 9],
[4 9])
julia> map(x->ind2sub(a, x), inds)
1×2 Array{Tuple{Int64,Int64},2}:
(4,1) (4,2)
julia> map(x->ind2sub(a, x)[1], inds)
1×2 Array{Int64,2}:
4 4
This is mentioned in the comments but I figured I'd do a response that's easy to see. I have version 1.0.3, so I don't know what's the earliest version that allows this. But now you can just do
julia> findmax(a) #Returns 2D index of overall maximum value
(9, CartesianIndex(4, 2))
julia> findmax(a[:,1]) #Returns 1D index of max value in column 1
(7, 4)
julia> findmax(a[:,2]) #Returns 1D index of max value in column 2
(9, 4)
Hope this makes things easier.
I've adopted the following function:
indmaxC(x) = cat(1, [indmax(x[:,c]) for c in 1:size(x,2)]...)
The Good: it's convenient and small
The Bad: it's only valid for 2-D arrays
A safer version would be:
function indmaxC(x::AbstractArray)
assert(ndims(x)==2)
cat(1, [indmax(x[:,c]) for c in 1:size(x,2)]...)
end

Summing elems of array using binary recursion

I wasn't starting to understand linear recursion and then I thought I practice up on sorting algorithms and then quick sort was where I had trouble with recursion. So I decided to work with a simpler eg, a binary sum that I found online. I understand that recursion, like all function calls, are executed one # a time and not at the same time (which is what multi-threading does but is not of my concern when tracing). So I need to execute all of recursive call A BEFORE recursive call B, but I get lost in the mix. Does anyone mind tracing it completely. The e.g. I have used of size, n = 9 where elems are all 1's to keep it simple.
/**
* Sums an integer array using binary recursion.
* #param arr, an integer array
* #param i starting index
* #param n size of the array
* floor(x) is largest integer <= x
* ceil(x) is smallest integer >= x
*/
public int binarySum(int arr[], int i, int n) {
if (n == 1)
return arr[i];
return binarySum(arr, i, ceil(n/2)) + binarySum(arr,i + ceil(n/2), floor(n/2));
}
What I personally do is start with an array of size 2. There are two elements.
return binarySum(arr, i, ceil(n/2)) + binarySum(arr,i + ceil(n/2), floor(n/2)) will do nothing but split the array into 2 and add the two elements. - case 1
now, this trivial starting point will be the lowest level of the recursion for the higher cases.
now increase n = 4. the array is split into 2 : indices from 0-2 and 2-4.
now the 2 elements inside indices 0 to 2 are added in case 1 and so are the 2 elements added in indices 2-4.
Now these two results are added in this case.
Now we are able to make more sense of the recursion technique, some times understanding bottom up is easier as in this case!
Now to your question consider an array of 9 elements : 1 2 3 4 5 6 7 8 9
n = 9 => ceil(9/2) = 5, floor(9/2) = 4
Now first call (top call) of binarySum(array, 0, 9)
now n = size is not 1
hence the recursive call....
return binarySum(array, 0, 5) + binarySum(array, 5, 4)
now the first binarySum(array, 0 ,5) operates on the first 5 elements of the array and the second binarySum(array,5,4) operates on the last 4 elements of the array
hence the array division can be seen like this: 1 2 3 4 5 | 6 7 8 9
The first function finds the sum of the elements: 1 2 3 4 5
and the second function finds the sum of the elements 6 7 8 9
and these two are added together and returned as the answer to the top call!
now how does this 1+2+3+4+5 and 6+7+8+9 work? we recurse again....
so the tracing will look like
1 2 3 4 5 | 6 7 8 9
1 2 3 | 4 5 6 7 | 8 9
1 2 | 3 4 | 5 6 | 7 8 | 9
[1 | 2]___[3]___[4 5]___[6 7]___[8 9]
Till this we are fine..we are just calling the functions recursively.
But now, we hit the base case!
if (n == 1)
return arr[i];
[1 + 2]____[3]____[4 + 5]____[6 + 7]____[8 + 9]
[3 + 3] ____ [9] ____[13 + 17]
[6 + 9] [30]
[15 + 30]
[45]
which is the sum.
So for understanding see what is done to the major instance of the problem and you can be sure that the same thing is going to happen to the minor instance of the problem.
This example explains binary sum with trace in java
the trace is based on index of array , where 0 - is yours starting index and 8 is length of the array
int sum(int* arr, int p, int k) {
if (p == k)
return arr[k];
int s = (p + k) / 2;
return sum(arr, p, s) + sum(arr, s + 1, k);
}

Element wise multiplication of a matrix and a vector?

Is there an in-built function in octave to multiply each column of a m X n element-wise with a column vector of size m that is more efficient than using a loop?
You can replicate the vector as many times as you need to turn it into a m x n matrix as well and then use the built-in element-wise multiplication operator .*:
>> A = [1 2; 3 4; 5 6];
>> B = [1; 2; 3];
>> A .* repmat(B, 1, columns(A))
ans =
1 2
6 8
15 18
I haven't tried Anna Lear's answer but as nobar commented in that answer, Octave now does broadcasting. So you just have to do A.*B. You will get a warning that'll say an automatic product broadcasting is being applied
>> A.*B
warning: product: automatic broadcasting operation applied
ans =
1 2
6 8
15 18

Resources