Related
I have a N×N general matrix H with rank n(<N).
Is there any way to get a n×n matrix with rank n from H?
For example,
|1 2 3|
H = |4 8 6|
|0 0 1|
has three eigenvalues 0,1,9 and its rank is 2. I want to get a 2×2 matrix with rank 2 which corresponds to the eigenspace sappaned by eigenvectors of 1,9.
We are given a 3x3 matrix H that is known to have rank r < 3:
1 2 3
4 8 6
0 0 1
One can obtain an nxn matrix comprised of the intersection of rows and columns of H that has rank n by computing the reduced row echelon form (RREF) of H (also called the row canonical form).
After doing so, for each of n row indices i there will be a column in the RREF that contains a 1 in row i (i.e., the row having index i) and zeroes in all other rows. It is seen here that the RREF of H is the following.
1 2 0
0 0 1
0 0 0
As column 0 (i.e., the column having index 0) in the RREF has a 1 in row 0 and zeroes in all other rows, and column 2 has a 1 in row 1 and zeroes in all other rows, and no other column has a 1 in one row and zeroes in all other rows, we conclude that:
H has rank 2; and
the nxn matrix comprised of elements in H that are in rows 0 and 1 and columns 0 and 2 has rank n.
Here an nxn matrix with rank n is therefore found to be
1 3
4 6
The same procedure is followed regardless of the size of H (which need not be square) and the rank of H need not be known in advance.
Using the RowEchelon.jl package, we can apply the method described in #CarySwoveland's answer pretty easily. (This is not my area of expertise though, so any corrections to it are welcome; specifically, the choice of rows as 1 to number of pivots is an educated guess based on some trials.)
julia> H = [1 2 3
4 8 6
0 0 1];
julia> using RowEchelon
julia> _, pivotcols = rref_with_pivots(H)
([1.0 2.0 0.0; 0.0 0.0 1.0; 0.0 0.0 0.0], [1, 3])
julia> result = H[1:length(pivotcols), pivotcols]
2×2 Matrix{Int64}:
1 3
4 6
The package is just a home for code that used to be in Base Julia, so you can even just copy the code if you don't want to add it as a dependency.
I've given a task in which the user enters some unit relations and we have to sort them from high to low.
What is the best algorithm to do that?
I put some input/output pairs to clarify the problem:
Input:
km = 1000 m
m = 100 cm
cm = 10 mm
Output:
1km = 1000m = 100000cm = 1000000mm
Input:
km = 100000 cm
km = 1000000 mm
m = 1000 mm
Output:
1km = 1000m = 100000cm = 1000000mm
Input:
B = 8 b
MiB = 1024 KiB
KiB = 1024 B
Mib = 1048576 b
Mib = 1024 Kib
Output:
1MiB = 8Mib = 1024KiB = 8192Kib = 1048576B = 8388608b
Input:
B = 8 b
MiB = 1048576 B
MiB = 1024 KiB
MiB = 8192 Kib
MiB = 8 Mib
Output:
1MiB = 8Mib = 1024KiB = 8192Kib = 1048576B = 8388608b
How to generate output based on given output?
My attempt at a graph-based solution. Example 3 is the most interesting, so I'll take that one, (multiple steps and multiple sinks.)
Transform B = n A to edge A -> B and label it n, n > 1. If it's not a connected DAG, it's inconsistent.
Reduce to a bipartite graph by making multiple connections I -> J -> K skip to I -> K by multiplying the n of I -> J by J -> K. Any inconsistencies are a sign that the problem is inconsistent.
The idea of this step is to produce only one single greatest value. A vertex on the left with a degree of greater than 1, P, and { Q, R } are in the right set, where, P -> Q labelled n1 and P -> R labelled n2, 1 < n1 < n2, (WLOG,) can be transformed into P -> R (unchanged) and Q -> R with label n2 / n1 (bringing Q, in this case Mib, from right to left.)
Is the graph bipartite with a single right node? No, goto 2.
Sort the edges.
X -> Z with n1 ... Y -> Z with n2 becomes 1 Z = n1 X = ... = n2 Y.
You can find the following algorithm:
1. detect all existing units: `n` units
2. create a `n x n` matrix `M` such that the same rows and columns show
the corresponding unit. put all elements of the main diagonal of the
matrix to `1`.
3. put the specified value in the input into the corresponding row and column.
4. put zero for the transpose of the row and the column in step 3.
5. put `-1` for all other elements
Now, based on `M` you can easily find the biggest unit:
5.1 candidate_maxs <-- Find columns with only one non-zero positive element
not_max <-- []
6. while len(candidate_max)> 1:
a. take a pair <i, l> and find a column h such that both (i, h)
and (l, h) are known, i.e., they are positive.
If M[i, h] > M[l, h]:
remove_item <-- l
Else:
remove_item <-- i
candidate_max.remove(remove_item)
not_max.append(remove_item)
b. if cannot find such a pair, find a pair <i, l>: i from
candidate_max and h from not_max with the same property.
If M[i, h] < M[l, h]:
candidate_max.remove(i)
not_max.append(i)
biggest_unit <-- The only element of candidate_max
By finding the biggest unit, you can order others based on their value in the corresponding row of the biggest_unit.
7. while there is `-1` value in the row `biggest_unit` on column `j`:
`(biggest_unit, j)`
a. find a non-identity and non-zero positive element in (column `j`
and row `k`) or (row `j` and column `k`), i.e., `(k,j)` or `(j, k)`, such that `(biggest_unit, k)` is strictly
positive and non-identity. Then, calculate the missing value
based on the found equivalences.
b. if there is not such a row, continue the loop with another `-1`
unit element.
8. sort units based on their column value in `biggest_unit` row in
ascending order.
However, the time complexity of the algorithm is Theta(n^2) that n is the number of units (if you implement the loop on step 6 wisely!).
Example
Input 1
km = 1000 m
m = 100 cm
cm = 10 mm
Solution:
km m cm mm
km 1 1000 -1 -1
m 0 1 100 -1
cm -1 0 1 10
mm -1 -1 0 1
M = [1 1000 -1 -1
0 1 100 -1
-1 0 1 10
-1 -1 0 1]
===> 6. `biggest_unit` <--- km (column 1)
7.1 Find first `-1` in the first row and column 3: (1,3)
Find strictly positive value in row 2 such that (1,2) is strictly
positive and non-identity. So, the missing value of `(1,3)` must be
`1000 * 100 = 100000`.
7.2 Find the second `-1` in the first row and column 4: (1,4)
Find strictly positive value in row 3 such that (1,3) is strictly
positive and non-identity. So, the missing value of `(1,4)` must be
`100000 * 10 = 1000000`.
The loop is finished here and we have:
M = [1 1000 100000 1000000
0 1 100 -1
-1 0 1 10
-1 -1 0 1]
Now you can sort the elements of the first row in ascending order.
Input 2
km = 100000 cm
km = 1000000 mm
m = 1000 mm
Solution:
km m cm mm
km 1 -1 100000 1000000
m -1 1 -1 1000
cm 0 -1 1 -1
mm 0 0 -1 1
M = [1 -1 100000 1000000
-1 1 -1 1000
0 -1 1 -1
0 0 -1 1]
===>
6.1 candidate_max = [1, 2]
6.2 Compare them on column 4 and remove 2
biggest_unit <-- column 1
And by going forward on step 7,
Find first `-1` in the first row and column 2: (1,2)
Find a strictly positive and non-identity value in row 2:(1,4)
So, the missing value of `(1,2)` must be `1000000 / 1000 = 1000`.
In sum, we have:
M = [1 1000 100000 1000000
-1 1 -1 1000
0 -1 1 -1
0 0 -1 1]
Now you can sort the elements of the first row in ascending order (step 8).
Suppose I have a matrix with a set of integers. I want to use the check rand > 0.5 to prepend a random vector of 1s and 0s to my matrix. How could I do this?
Only a 6x1 matrix but you should get the point.
octave:1> a = [7;8;2;3;6;7];
octave:2> a = [a, rand(size(a))>0.5]
a =
7 0
8 1
2 1
3 0
6 1
7 0
In Julia you can find the coordinates of elements in a matrix via:
julia> find( x -> x == 2, [ 1 2 3; 2 3 4; 1 0 2] )
3-element Array{Int64,1}:
2
4
9
These values are correct but I would prefer that I would get the (row,col) tuples instead.
(1,2)
(2,1)
(3,3)
What is the easiest way to achieve this in Julia?
I don't believe there is an inbuilt way to do it, but here is a function to do it
function findmat(f, A::AbstractMatrix)
m,n = size(A)
out = (Int,Int)[]
for i in 1:m, j in 1:n
f(A[i,j]) && push!(out,(i,j))
end
out
end
e.g.
julia> findmat(x->x==2, [ 1 2 3; 2 3 4; 1 0 2] )
3-element Array{(Int64,Int64),1}:
(1,2)
(2,1)
(3,3)
If a large number of items satisfy the condition it might be more efficient to do it in two passes, but I doubt it.
Edit:
For newer versions of Julia replace
out = (Int,Int)[]
with
out = Tuple{Int, Int}[]
In case anyone else finds this you can now use:
ind2sub(a, index)
It returns a tuple of subscripts into array a corresponding to the linear index index
The closest thing that I can find in the Julia standard library is findn :
julia> A = [1 2 3; 2 3 4; 1 0 2]
3x3 Array{Int64,2}:
1 2 3
2 3 4
1 0 2
julia> findn(A .== 2)
([2,1,3],[1,2,3])
This gives a tuple of vectors instead of a vector of tuples, though.
Another thing to note is that the match at (2,1) is reported before the one at (1,2). This is because arrays in Julia are stored in column major order, so scanning the array A in storage order will look at the position (2,1) before (1,2).
if you wish to avoid defining "new" functions, perhaps:
collect(zip(ind2sub((3,3),find( x -> x == 2, [ 1 2 3; 2 3 4; 1 0 2] ))...))
is what you are looking for. the (3,3) is implicit in the size of the matrix. if the matrix was given by a variable it would look more natural with a size(M)
on julia 1.7, find does not exist (it was deprecated on julia 1.0), findall is the equivalent that gives the same result as the original question.
On matrices, findall will return CartesianIndex locations:
julia> idx = findall( x -> x == 2, [ 1 2 3; 2 3 4; 1 0 2])
3-element Vector{CartesianIndex{2}}:
CartesianIndex(2, 1)
CartesianIndex(1, 2)
CartesianIndex(3, 3)
julia> ans[1][1]
2
There are two vectors:
a = 1:5;
b = 1:2;
in order to find all combinations of these two vectors, I am using the following piece of code:
[A,B] = meshgrid(a,b);
C = cat(2,A',B');
D = reshape(C,[],2);
the result includes all the combinations:
D =
1 1
2 1
3 1
4 1
5 1
1 2
2 2
3 2
4 2
5 2
now the questions:
1- I want to decrease the number of operations to improve the performance for vectors with bigger size. Is there any single function in MATLAB that is doing this?
2- In the case that the number of vectors is more than 2, the meshgrid function cannot be used and has to be replaced with for loops. What is a better solution?
For greater than 2 dimensions, use ndgrid:
>> a = 1:2; b = 1:3; c = 1:2;
>> [A,B,C] = ndgrid(a,b,c);
>> D = [A(:) B(:) C(:)]
D =
1 1 1
2 1 1
1 2 1
2 2 1
1 3 1
2 3 1
1 1 2
2 1 2
1 2 2
2 2 2
1 3 2
2 3 2
Note that ndgrid expects (rows,cols,...) rather than (x,y).
This can be generalized to N dimensions (see here and here):
params = {a,b,c};
vecs = cell(numel(params),1);
[vecs{:}] = ndgrid(params{:});
D = reshape(cat(numel(vecs)+1,vecs{:}),[],numel(vecs));
Also, as described in Robert P.'s answer and here too, kron can also be useful for replicating values (indexes) in this way.
If you have the neural network toolbox, also have a look at combvec, as demonstrated here.
One way would be to combine repmat and the Kronecker tensor product like this:
[repmat(a,size(b)); kron(b,ones(size(a)))]'
ans =
1 1
2 1
3 1
4 1
5 1
1 2
2 2
3 2
4 2
5 2
This can be scaled to more dimensions this way:
a = 1:3;
b = 1:3;
c = 1:3;
x = [repmat(a,1,numel(b)*numel(c)); ...
repmat(kron(b,ones(1,numel(a))),1,numel(c)); ...
kron(c,ones(1,numel(a)*numel(b)))]'
There is a logic! First: simply repeat the first vector. Secondly: Use the tensor product with the dimension of the first vector and repeat it. Third: Use the tensor product with the dimension of (first x second) and repeat (in this case there is not fourth, so no repeat.