Imagine we have the following 5x5 matrix populated with integers between 1 and 3. The 1s are across the diagonals. The 2s are "second diagonal" close to the 1s. The 3s are also diagonal but the matrix is too small to see it properly.
1, 2, 3, 2, 1
2, 1, 2, 1, 2
3, 2, 1, 2, 3
2, 1, 2, 1, 2
1, 2, 3, 2, 1
What simple algorithm can generate this odd square matrix in 5x5 or NxN where N is odd?
7x7 would have integers up to 4.
This is not homework.
Diagonals in a matrix can be defined with equations similar to the equation of a line in the plane. You know that a line in the plane, if it's not vertical, can be expressed by an equation of the form y = a * x + b.
Similarly, a diagonal in a matrix consists in the cells (i,j) that satisfy an equation i = a * j + b.
Furthermore, a is the directing coefficient of the line, and in the case of a diagonal, which is a line with angle 45°, a has got to be +1 or -1.
Now you just need to identify the value of parameter b for each diagonal.
For the main first diagonal (upperleft-bottomright), the equation is i = j; the parameters are a = 1 and b = i - j = 0.
For the reversed first diagonal (bottomleft-upperright), the equation is i = N - j - 1; the parameters are a = -1 and b = i + j = N - 1.
If two diagonals are adjacent, then the b parameters for these two diagonals must differ by exactly 1. So for instance, the second diagonals will have b in {-1, +1, N, N-2}; the third diagonals will have b in {-2, +2, N+1, N-3}, etc.
Every cell is at the intersection of two diagonals. Since b can always be computed as i-j for the upperleft-bottomright diagonals, and i+j for the bottomleft-upperright diagonals, we can easily find which two diagonals we are on by computing i-j and i+j. Then, since you want to populate the cell with a number corresponding to the diagonal closest to center, use min to choose which of the two diagonals is relevant.
We get the following algorithm:
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
M(i,j) = min(abs(i-j), abs(i+j - (N-1))) + 1
Illustration in python3:
def f(i,j, N):
return min(abs(i-j), abs(i+j - (N-1))) + 1
def M(N):
return [[f(i,j,N) for j in range(N)] for i in range(N)]
print(M(3))
#[[1, 2, 1],
# [2, 1, 2],
# [1, 2, 1]]
print(M(7))
#[[1, 2, 3, 4, 3, 2, 1],
# [2, 1, 2, 3, 2, 1, 2],
# [3, 2, 1, 2, 1, 2, 3],
# [4, 3, 2, 1, 2, 3, 4],
# [3, 2, 1, 2, 1, 2, 3],
# [2, 1, 2, 3, 2, 1, 2],
# [1, 2, 3, 4, 3, 2, 1]]
OK, got it this time...
Try this:
CellValue[x,y] = MIN(ABS(x-y), ABS(N-(x+y)+1))+1
This is assuming a ones-based matrix. If you are using a zero-based array. then you would have to adjust it
CellValue[x,y] = MIN(ABS(x-y), ABS(N-(x+y)-1))+1
Related
I was wondering if there would be the possibility to identify the position of the range values according to a condition. This condition is determined by the longest sequence of values lower than 3.
For instance,
x <- c(4, 1, 2, 1, 1, 4, 1, 1, 1, 1, 2, 1, 1, 1, 1, 4, 1, 1)
Desired output:
c(7:15)
It may be that split() and rle() could be useful in this case but any help will be more than helpful.
You could do the rle on x < 3, then find which of the TRUEs is max. Then sum the lengths before the match plus one as well as the match itself (which will be the final position). Finally do a sequence with the values.
rl <- rle(x < 3)
w <- which(rl$lengths == max(rl$lengths) & rl$values)
do.call(seq.int, list(sum(rl$lengths[1:(w - 1)]) + 1, sum(rl$lengths[1:w])))
# [1] 7 8 9 10 11 12 13 14 15
Thanks to lots of help, I've got an expression that substitutes the value from a rbinom into a vector, when certain conditions are met. My problem is that it always substitutes the same value, i.e. does not do a new evaluation for each instance of the conditions being met. I think I just need to wrap it in a sapply statement but haven't got the syntax correct. MWE:
arr1 <- c(8, 2, 5, 2, 3, 2, 2, 2, 8, 2, 4)
arr2 <- c(0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0)
arr1
arr1[Reduce("&", list(arr1 == 2, arr2 ==1))] <- rbinom(1,1,0.5) * 2
arr1
arr1
[1] 8 2 5 0 3 0 0 0 8 0 4
I would have hoped that it changed some of the values but not others, so evaluated the result again for each instance. Is this a good application of purrr::modify2 ? Thx. J
Probably, you mean to use :
inds <- arr1 == 2 & arr2 == 1
arr1[inds] <- rbinom(sum(inds), 1, 0.5) * 2
I have 5 vectors t1,...,t5, of respective unequal lengths n1, .. ,n5. How can I generate an (n1*...*n5)x(5) matrix in Julia, which would be:
What you may be looking for is Iterators.product though it does not generate exactly what you request
julia> n1, n2, n3, n4, n5 = 2, 3, 4, 5, 6;
julia> a = Iterators.product(1:n1, 1:n2, 1:n3, 1:n4, 1:n5)
Base.Iterators.ProductIterator{NTuple{5,UnitRange{Int64}}}((1:2, 1:3, 1:4, 1:5, 1:6))
julia> first(a)
(1, 1, 1, 1, 1)
julia> reduce(vcat, a)
600-element Array{NTuple{5,Int64},1}:
(1, 1, 1, 1, 1)
(2, 1, 1, 1, 1)
(1, 2, 1, 1, 1)
(2, 2, 1, 1, 1)
....
It doesn't create the Matrix you requested, but most of the time you'll generate a Matrix like that to use it for something else. In this case this is better, as it avoids allocating a temporary Matrix.
#BogumiłKamiński wrote in a comment below that you can get a Matrix (not ordered exactly like the one in your example though) from the object by
julia> reduce(vcat, reduce.(hcat, a))
720×5 Array{Int64,2}:
1 1 1 1 1
2 1 1 1 1
1 2 1 1 1
...
which is maybe not the first thing one would think about, but gets the job done nicely.
So, I have a vector full of 1s and 0s. I need to plot a graph that starts at (0, 0) and rises by 1 for every 1 in the vector and dips by 1 for every 0 in the vector. For example if my vector is [ 1, 1, 1, 0, 1, 0, 1, 1 ] I should get something that looks like
I thought about creating another vector that would hold the sum of the first i elements of the original vector at index i (from the example: [ 1, 2, 3, 3, 4, 4, 5, 6 ]) but that would not account for the dips at 0s. Also, I cannot use loops to solve this.
I would convert the zeros to -1, add a zero at the very beginning to make sure it starts from [0,0] and then plot the cumulative sum:
#starting vec
myvec <- c(1, 1, 1, 0, 1, 0, 1, 1)
#convert 0 to -1
myvec[myvec == 0] <- -1
#add a zero at the beginning to make sure it starts from [0,0]
myvec <- c(0, myvec)
#plot cumulative sum
plot(cumsum(myvec), type = 'line')
#points(cumsum(myvec)) - if you also want the points on top of the line
I'm looking at a gene in 10 people. And this gene has two alleles, say a and b. And each allele has 3 forms: type 2, 3 or 4.
a <- c(2, 2, 2, 2, 3, 3, 3, 2, 4, 3)
b <- c(4, 2, 3, 2, 4, 2, 3, 4, 4, 4)
I wish to code a variable that tells me how many type 4 alleles the person has: 0, 1, or 2.
var <- ifelse(a==4 & b==4, 2, 0)
The code above doesn't work since I didn't account for the individuals who have just one copy of the type 4 allele. I feel like I might need 2 ifelse statements that work simultaneously?
EDIT: You don't actually need ifelse or any fancy operations other than plus and equal to.
var <- (a == 4) + (b == 4)
If you're set on ifelse, this can be done with
var <- ifelse(a == 4, 1, 0) + ifelse(b == 4, 1, 0)
However, I prefer the following solution using apply. The following will give you three cases, the result being the number of 4's the person has (assuming each row is a person).
a = c(2, 2, 2, 2, 3, 3, 3, 2, 4, 3)
b = c(4, 2, 3, 2, 4, 2, 3, 4, 4, 4)
d <- cbind(a,b)
apply(d, 1, function(x) {sum(x == 4)})
For this operation, I first combined the two vectors into a matrix since it makes applying the function easier. In R, generally if data are the same type it is easier (and faster for the computer) to combine the data into a matrix/data frame/etc., then create a function to be performed on each row/column/etc.
To understand the output, consider what happens to the first row of d.
> d[1, ]
a b
2 4
> d[1, ] == 4
a b
FALSE TRUE
Booleans are interpreted as integers under addition, so
> FALSE + TRUE
[1] 1
It doesn't seem to matter whether the 4 came from a or b, so we end up with three cases: 0, 1, and 2, depending on the number of 4's.