R: summing specific elements in a symmetrical matrix - matrix
If I have a correlation matrix, I know I can use upper.tri or lower.tri to sum all values, but is there a way to sum just specific parts of the matrix?
For example, a correlation matrix of 5 variables:
> Matrix
[,1] [,2] [,3] [,4] [,5]
[1,] 0 4 3 1 2
[2,] 4 0 3 2 1
[3,] 3 3 0 2 1
[4,] 1 2 2 0 1
[5,] 2 1 1 1 0
If the first 2 variables belong to one group, while 3-5 belong to another, is there a way to just ask for the sum of the inter-group values? e.g., 3+3+1+2+2+1 = 12.
A long winded answer but hopefully generic one to help you!
matrix <- matrix (c(0,4,3,1,2,4,0,3,2,1,3,3,0,2,1,1,2,2,0,1,2,1,1,1,0), nrow=5, ncol=5)
group <- list(group1=c(1,2), group2=c(3,4,5))
sum_matrix <- matrix(data <- rep(NA), nrow = length(group), ncol= length(group))
for (i in 1:length(group))
{
for(j in 1:length(group))
{
ifelse(i==j, sum_matrix[i,j]<- NA, sum_matrix[i,j] <- sum(matrix[group[[i]], group[[j]] ]) )
}
}
sum_matrix
sum(matrix[group2, group1])
sum(matrix[group1, group2])
Related
Intersection of two matrices in Julia?
Is there any function or method in Julia that would allow one to compute the intersection of two matrices A and B?
There are many possible definitions for intersection. Suppose that you have: julia> a=[1 2 3;4 5 6;3 2 1] 3×3 Matrix{Int64}: 1 2 3 4 5 6 3 2 1 julia> b = a' 3×3 adjoint(::Matrix{Int64}) with eltype Int64: 1 4 3 2 5 2 3 6 1 and if you mean by intersection you mean matrix with elements who have the same values in both matrices and zero otherwise you could do: julia> (a .== b) .* a 3×3 Matrix{Int64}: 1 0 3 0 5 0 3 0 1
Matrices in Julia - Sorting and Sort Permutations
How can matrices be sorted in Julia. Let's define a matrix: a = [1 1 1; 1 3 1; 1 2 2; 1 2 1] I'm looking for several things here: Sort by multiple Columns So, you can sort the matrix by all columns from left to right with sortslices(a, dims = 1) 4×3 Array{Int64,2}: 1 1 1 1 2 1 1 2 2 1 3 1 Sort by particular Column Order But what if want to sort by the 3rd then the 2nd and then the 1st column? Expected output: 4×3 Array{Int64,2}: 1 1 1 1 2 1 1 3 1 1 2 2 Sort permutation Let's assume I had a Vector b = ["a", "d", "c", "b"] and I would like to sort its elements by the sort permutation of the matrix' columns. As seen above sortslices() let's me sort the matrix so I get the rows in the order [1,4,3,2]. How can I get this vector to sort b to 4-element Array{String,1}: "a" "b" "c" "d" I know there are other similar questions, but they seem either address other issues or they seem to be outdated (e.g. Julia: Sort Matrix by column 2 then 3).
It isn't ideal to ask multiple questions within a single post. It makes searching for questions much harder. Anyway, here we go: Sort by multiple Columns julia> a = [1 1 1; 1 3 1; 1 2 2; 1 2 1] 4×3 Matrix{Int64}: 1 1 1 1 3 1 1 2 2 1 2 1 julia> sortslices(a, dims = 1, by=x->(x[1], x[2], x[3])) 4×3 Matrix{Int64}: 1 1 1 1 2 1 1 2 2 1 3 1 Sort by particular Column Order julia> a = [1 1 1; 1 3 1; 1 2 2; 1 2 1] 4×3 Matrix{Int64}: 1 1 1 1 3 1 1 2 2 1 2 1 julia> sortslices(a, dims = 1, by=x->(x[3], x[2], x[1])) 4×3 Matrix{Int64}: 1 1 1 1 2 1 1 3 1 1 2 2 Sort permutation julia> b = ["a", "d", "c", "b"] 4-element Vector{String}: "a" "d" "c" "b" julia> sortperm(b) 4-element Vector{Int64}: 1 4 3 2 julia> b[sortperm(b)] 4-element Vector{String}: "a" "b" "c" "d"
Building on #mcabbot's comment, I think that by clause is unnecessary. This suffices: p = sortperm(collect(eachrow(a))). Whether this is the most performant solution, I don't know.
Example of compress column format for rank-deficient matrices
It is the first time I deal with column-compress storage (CCS) format to store matrices. After googling a bit, if I am right, in a matrix having n nonzero elements the CCS is as follows: -we define a vector A_v of dimensions n x 1 storing the n non-zero elements of the matrix - we define a second vector A_ir of dimensions n x 1 storing the rows of the non-zero elements of the matrix -we finally define a third vector A_jc whose elements are the indices of the elements of A_v which corresponds to the beginning of new column, plus a final value which is by convention equal t0 n+1, and identifies the end of the matrix (pointing theoretically to a virtual extra-column). So for instance, if M = [1 0 4 0 0; 0 3 5 2 0; 2 0 0 4 6; 0 0 7 0 8] we get A_v = [1 2 3 4 5 7 2 4 6 8]; A_ir = [1 3 2 1 2 4 2 3 3 4]; A_jc = [1 3 4 7 9 11]; my questions are I) is what I wrote correct, or I misunderstood anything? II) what if I want to represent a matri with some columns which are zeroes, e.g., M2 = [0 1 0 0 4 0 0; 0 0 3 0 5 2 0; 0 2 0 0 0 4 6; 0 0 0 0 7 0 8] wouldn't the representation of M2 in CCS be identical to the one of M? Thanks for the help!
I) is what I wrote correct, or I misunderstood anything? You are perfectly correct. However, you have to take care that if you use a C or C++ library offsets and indices should start at 0. Here, I guess you read some Fortran doc for which indices are starting at 1. To be clear, here is below the C version, which simply translates the indices of your Fortran-style correct answer: A_v = unmodified A_ir = [0 2 1 0 1 3 1 2 2 4] (in short [1 3 2 1 2 4 2 3 3 4] - 1) A_jc = [0 2 3 6 8 10] (in short [1 3 4 7 9 11] - 1) II) what if I want to represent a matri with some columns which are zeroes, e.g., M2 = [0 1 0 0 4 0 0; 0 0 3 0 5 2 0; 0 2 0 0 0 4 6; 0 0 0 0 7 0 8] wouldn't the representation of M2 in CCS be identical to the one of M? I you have an empty column, simply add a new entry in the offset table A_jc. As this column contains no element this new entry value is simply the value of the previous entry. For instance for M2 (with index starting at 0) you have: A_v = unmodified A_ir = unmodified A_jc = [0 0 2 3 6 8 10] (to be compared to [0 2 3 6 8 10]) Hence the two representations are differents. If you just start learning about sparse matrices there is an excelllent free book here: http://www-users.cs.umn.edu/~saad/IterMethBook_2ndEd.pdf
Efficiently construct a square matrix with unique numbers in each row
A matrix of size nxn needs to be constructed with the desired properties. n is even. (given as input to the algorithm) Matrix should contain integers from 0 to n-1 Main diagonal should contain only zeroes and matrix should be symmetric. All numbers in each row should be different. For various n , any one of the possible output is required. input 2 output 0 1 1 0 input 4 output 0 1 3 2 1 0 2 3 3 2 0 1 2 3 1 0 Now the only idea that comes to my mind is to brute-force build combinations recursively and prune. How can this be done in a iterative way perhaps efficiently?
IMO, You can handle your answer by an algorithm to handle this: If 8x8 result is: 0 1 2 3 4 5 6 7 1 0 3 2 5 4 7 6 2 3 0 1 6 7 4 5 3 2 1 0 7 6 5 4 4 5 6 7 0 1 2 3 5 4 7 6 1 0 3 2 6 7 4 5 2 3 0 1 7 6 5 4 3 2 1 0 You have actually a matrix of two 4x4 matrices in below pattern: m0 => 0 1 2 3 m1 => 4 5 6 7 pattern => m0 m1 1 0 3 2 5 4 7 6 m1 m0 2 3 0 1 6 7 4 5 3 2 1 0 7 6 5 4 And also each 4x4 is a matrix of two 2x2 matrices with a relation to a power of 2: m0 => 0 1 m1 => 2 3 pattern => m0 m1 1 0 3 2 m1 m0 In other explanation I should say you have a 2x2 matrix of 0 and 1 then you expand it to a 4x4 matrix by replacing each cell with a new 2x2 matrix: 0 => 0+2*0 1+2*0 1=> 0+2*1 1+2*1 1+2*0 0+2*0 1+2*1 0+2*1 result => 0 1 2 3 1 0 3 2 2 3 0 1 3 2 1 0 Now expand it again: 0,1=> as above 2=> 0+2*2 1+2*2 3=> 0+2*3 1+2*3 1+2*2 0+2*2 1+2*3 0+2*3 I can calculate value of each cell by this C# sample code: // i: row, j: column, n: matrix dimension var v = 0; var m = 2; do { var p = m/2; v = v*2 + (i%(n/p) < n/m == j%(n/p) < n/m ? 0 : 1); m *= 2; } while (m <= n);
We know each row must contain each number. Likewise, each row contains each number. Let us take CS convention of indices starting from 0. First, consider how to place the 1's in the matrix. Choose a random number k0, from 1 to n-1. Place the 1 in row 0 at position (0,k0). In row 1, if k0 = 1 in which case there is already a one placed. Otherwise, there are n-2 free positions and place the 1 at position (1,k1). Continue in this way until all the 1 are placed. In the final row there is exactly one free position. Next, repeat with the 2 which have to fit in the remaining places. Now the problem is that we might not be able to actually complete the square. We may find there are some constraints which make it impossible to fill in the last digits. The problem is that checking a partially filled latin square is NP-complete.(wikipedia) This basically means pretty compute intensive and there no know short-cut algorithm. So I think the best you can do is generate squares and test if they work or not. If you only want one particular square for each n then there might be simpler ways of generating them. The link Ted Hopp gave in his comment Latin Squares. Simple Construction does provide a method for generating a square starting with the addition of integers mod n.
I might be wrong, but if you just look for printing a symmetric table - a special case of latin squares isomorphic to the symmetric difference operation table over a powerset({0,1,..,n}) mapped to a ring {0,1,2,..,2^n-1}. One can also produce such a table, using XOR(i,j) where i and j are n*n table indexes. For example: def latin_powerset(n): for i in range(n): for j in range(n): yield (i, j, i^j) Printing tuples coming from previously defined special-case generator of symmetric latin squares declared above: def print_latin_square(sq, n=None): cells = [c for c in sq] if n is None: # find the length of the square side n = 1; n2 = len(cells) while n2 != n*n: n += 1 rows = list() for i in range(n): rows.append(" ".join("{0}".format(cells[i*n + j][2]) for j in range(n))) print("\n".join(rows)) square = latin_powerset(8) print(print_latin_square(square)) outputs: 0 1 2 3 4 5 6 7 1 0 3 2 5 4 7 6 2 3 0 1 6 7 4 5 3 2 1 0 7 6 5 4 4 5 6 7 0 1 2 3 5 4 7 6 1 0 3 2 6 7 4 5 2 3 0 1 7 6 5 4 3 2 1 0 See also This covers more generic cases of latin squares, rather than that super symmetrical case with the trivial code above: https://www.cut-the-knot.org/arithmetic/latin2.shtml (also pointed in the comments above for symmetric latin square construction) https://doc.sagemath.org/html/en/reference/combinat/sage/combinat/matrices/latin.html
Permute all unique enumerations of a vector in R
I'm trying to find a function that will permute all the unique permutations of a vector, while not counting juxtapositions within subsets of the same element type. For example: dat <- c(1,0,3,4,1,0,0,3,0,4) has factorial(10) > 3628800 possible permutations, but only 10!/(2!*2!*4!*2!) factorial(10)/(factorial(2)*factorial(2)*factorial(2)*factorial(4)) > 18900 unique permutations when ignoring juxtapositions within subsets of the same element type. I can get this by using unique() and the permn() function from the package combinat unique( permn(dat) ) but this is computationally very expensive, since it involves enumerating n!, which can be an order of magnitude more permutations than I need. Is there a way to do this without first computing n!?
EDIT: Here's a faster answer; again based on the ideas of Louisa Grey and Bryce Wagner, but with faster R code thanks to better use of matrix indexing. It's quite a bit faster than my original: > ddd <- c(1,0,3,4,1,0,0,3,0,4) > system.time(up1 <- uniqueperm(d)) user system elapsed 0.183 0.000 0.186 > system.time(up2 <- uniqueperm2(d)) user system elapsed 0.037 0.000 0.038 And the code: uniqueperm2 <- function(d) { dat <- factor(d) N <- length(dat) n <- tabulate(dat) ng <- length(n) if(ng==1) return(d) a <- N-c(0,cumsum(n))[-(ng+1)] foo <- lapply(1:ng, function(i) matrix(combn(a[i],n[i]),nrow=n[i])) out <- matrix(NA, nrow=N, ncol=prod(sapply(foo, ncol))) xxx <- c(0,cumsum(sapply(foo, nrow))) xxx <- cbind(xxx[-length(xxx)]+1, xxx[-1]) miss <- matrix(1:N,ncol=1) for(i in seq_len(length(foo)-1)) { l1 <- foo[[i]] nn <- ncol(miss) miss <- matrix(rep(miss, ncol(l1)), nrow=nrow(miss)) k <- (rep(0:(ncol(miss)-1), each=nrow(l1)))*nrow(miss) + l1[,rep(1:ncol(l1), each=nn)] out[xxx[i,1]:xxx[i,2],] <- matrix(miss[k], ncol=ncol(miss)) miss <- matrix(miss[-k], ncol=ncol(miss)) } k <- length(foo) out[xxx[k,1]:xxx[k,2],] <- miss out <- out[rank(as.numeric(dat), ties="first"),] foo <- cbind(as.vector(out), as.vector(col(out))) out[foo] <- d t(out) } It doesn't return the same order, but after sorting, the results are identical. up1a <- up1[do.call(order, as.data.frame(up1)),] up2a <- up2[do.call(order, as.data.frame(up2)),] identical(up1a, up2a) For my first attempt, see the edit history.
The following function (which implements the classic formula for repeated permutations just like you did manually in your question) seems quite fast to me: upermn <- function(x) { n <- length(x) duplicates <- as.numeric(table(x)) factorial(n) / prod(factorial(duplicates)) } It does compute n! but not like permn function which generates all permutations first. See it in action: > dat <- c(1,0,3,4,1,0,0,3,0,4) > upermn(dat) [1] 18900 > system.time(uperm(dat)) user system elapsed 0.000 0.000 0.001 UPDATE: I have just realized that the question was about generating all unique permutations not just specifying the number of them - sorry for that! You could improve the unique(perm(...)) part with specifying unique permutations for one less element and later adding the uniqe elements in front of them. Well, my explanation may fail, so let the source speak: uperm <- function(x) { u <- unique(x) # unique values of the vector result <- x # let's start the result matrix with the vector for (i in 1:length(u)) { v <- x[-which(x==u[i])[1]] # leave the first occurance of duplicated values result <- rbind(result, cbind(u[i], do.call(rbind, unique(permn(v))))) } return(result) } This way you could gain some speed. I was lazy to run the code on the vector you provided (took so much time), here is a small comparison on a smaller vector: > dat <- c(1,0,3,4,1,0,0) > system.time(unique(permn(dat))) user system elapsed 0.264 0.000 0.268 > system.time(uperm(dat)) user system elapsed 0.147 0.000 0.150 I think you could gain a lot more by rewriting this function to be recursive! UPDATE (again): I have tried to make up a recursive function with my limited knowledge: uperm <- function(x) { u <- sort(unique(x)) l <- length(u) if (l == length(x)) { return(do.call(rbind,permn(x))) } if (l == 1) return(x) result <- matrix(NA, upermn(x), length(x)) index <- 1 for (i in 1:l) { v <- x[-which(x==u[i])[1]] newindex <- upermn(v) if (table(x)[i] == 1) { result[index:(index+newindex-1),] <- cbind(u[i], do.call(rbind, unique(permn(v)))) } else { result[index:(index+newindex-1),] <- cbind(u[i], uperm(v)) } index <- index+newindex } return(result) } Which has a great gain: > system.time(unique(permn(c(1,0,3,4,1,0,0,3,0)))) user system elapsed 22.808 0.103 23.241 > system.time(uperm(c(1,0,3,4,1,0,0,3,0))) user system elapsed 4.613 0.003 4.645 Please report back if this would work for you!
One option that hasn't been mentioned here is the allPerm function from the multicool package. It can be used pretty easily to get all the unique permutations: library(multicool) perms <- allPerm(initMC(dat)) dim(perms) # [1] 18900 10 head(perms) # [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] # [1,] 4 4 3 3 1 1 0 0 0 0 # [2,] 0 4 4 3 3 1 1 0 0 0 # [3,] 4 0 4 3 3 1 1 0 0 0 # [4,] 4 4 0 3 3 1 1 0 0 0 # [5,] 3 4 4 0 3 1 1 0 0 0 # [6,] 4 3 4 0 3 1 1 0 0 0 In benchmarking I found it to be faster on dat than the solutions from the OP and daroczig but slower than the solution from Aaron.
I don't actually know R, but here's how I'd approach the problem: Find how many of each element type, i.e. 4 X 0 2 X 1 2 X 3 2 X 4 Sort by frequency (which the above already is). Start with the most frequent value, which takes up 4 of the 10 spots. Determine the unique combinations of 4 values within the 10 available spots. (0,1,2,3),(0,1,2,4),(0,1,2,5),(0,1,2,6) ... (0,1,2,9),(0,1,3,4),(0,1,3,5) ... (6,7,8,9) Go to the second most frequent value, it takes up 2 of 6 available spots, and determine it's unique combinations of 2 of 6. (0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(1,3) ... (4,6),(5,6) Then 2 of 4: (0,1),(0,2),(0,3),(1,2),(1,3),(2,3) And the remaining values, 2 of 2: (0,1) Then you need to combine them into each possible combination. Here's some pseudocode (I'm convinced there's a more efficient algorithm for this, but this shouldn't be too bad): lookup = (0,1,3,4) For each of the above sets of combinations, example: input = ((0,2,4,6),(0,2),(2,3),(0,1)) newPermutation = (-1,-1,-1,-1,-1,-1,-1,-1,-1,-1) for i = 0 to 3 index = 0 for j = 0 to 9 if newPermutation(j) = -1 if index = input(i)(j) newPermutation(j) = lookup(i) break else index = index + 1
Another option is the iterpc package, I believe it is the fastest of the existing method. More importantly, the result is in dictionary order (which may be somehow preferable). dat <- c(1, 0, 3, 4, 1, 0, 0, 3, 0, 4) library(iterpc) getall(iterpc(table(dat), order=TRUE)) The benchmark indicates that iterpc is significant faster than all other methods described here library(multicool) library(microbenchmark) microbenchmark(uniqueperm2(dat), allPerm(initMC(dat)), getall(iterpc(table(dat), order=TRUE)) ) Unit: milliseconds expr min lq mean median uniqueperm2(dat) 23.011864 25.33241 40.141907 27.143952 allPerm(initMC(dat)) 1713.549069 1771.83972 1814.434743 1810.331342 getall(iterpc(table(dat), order = TRUE)) 4.332674 5.18348 7.656063 5.989448 uq max neval 64.147399 74.66312 100 1855.869670 1937.48088 100 6.705741 49.98038 100
As this question is old and continues to attract many views, this post is solely meant to inform R users of the current state of the language with regards to performing the popular task outlined by the OP. As #RandyLai alludes to, there are packages developed with this task in mind. They are: arrangements and RcppAlgos*. Efficiency They are very efficient and quite easy to use for generating permutations of a multiset. dat <- c(1, 0, 3, 4, 1, 0, 0, 3, 0, 4) dim(RcppAlgos::permuteGeneral(sort(unique(dat)), freqs = table(dat))) [1] 18900 10 microbenchmark(algos = RcppAlgos::permuteGeneral(sort(unique(dat)), freqs = table(dat)), arngmnt = arrangements::permutations(sort(unique(dat)), freq = table(dat)), curaccptd = uniqueperm2(dat), unit = "relative") Unit: relative expr min lq mean median uq max neval algos 1.000000 1.000000 1.0000000 1.000000 1.000000 1.0000000 100 arngmnt 1.501262 1.093072 0.8783185 1.089927 1.133112 0.3238829 100 curaccptd 19.847457 12.573657 10.2272080 11.705090 11.872955 3.9007364 100 With RcppAlgos we can utilize parallel processing for even better efficiency on larger examples. hugeDat <- rep(dat, 2)[-(1:5)] RcppAlgos::permuteCount(sort(unique(hugeDat)), freqs = table(hugeDat)) [1] 3603600 microbenchmark(algospar = RcppAlgos::permuteGeneral(sort(unique(hugeDat)), freqs = table(hugeDat), nThreads = 4), arngmnt = arrangements::permutations(sort(unique(hugeDat)), freq = table(hugeDat)), curaccptd = uniqueperm2(hugeDat), unit = "relative", times = 10) Unit: relative expr min lq mean median uq max neval algospar 1.00000 1.000000 1.000000 1.000000 1.00000 1.00000 10 arngmnt 3.23193 3.109092 2.427836 2.598058 2.15965 1.79889 10 curaccptd 49.46989 45.910901 34.533521 39.399481 28.87192 22.95247 10 Lexicographical Order A nice benefit of these packages is that the output is in lexicographical order: head(RcppAlgos::permuteGeneral(sort(unique(dat)), freqs = table(dat))) [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [1,] 0 0 0 0 1 1 3 3 4 4 [2,] 0 0 0 0 1 1 3 4 3 4 [3,] 0 0 0 0 1 1 3 4 4 3 [4,] 0 0 0 0 1 1 4 3 3 4 [5,] 0 0 0 0 1 1 4 3 4 3 [6,] 0 0 0 0 1 1 4 4 3 3 tail(RcppAlgos::permuteGeneral(sort(unique(dat)), freqs = table(dat))) [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [18895,] 4 4 3 3 0 1 1 0 0 0 [18896,] 4 4 3 3 1 0 0 0 0 1 [18897,] 4 4 3 3 1 0 0 0 1 0 [18898,] 4 4 3 3 1 0 0 1 0 0 [18899,] 4 4 3 3 1 0 1 0 0 0 [18900,] 4 4 3 3 1 1 0 0 0 0 identical(RcppAlgos::permuteGeneral(sort(unique(dat)), freqs = table(dat)), arrangements::permutations(sort(unique(dat)), freq = table(dat))) [1] TRUE Iterators Additionally, both packages offer iterators that allow for memory efficient generation of permutation, one by one: algosIter <- RcppAlgos::permuteIter(sort(unique(dat)), freqs = table(dat)) algosIter$nextIter() [1] 0 0 0 0 1 1 3 3 4 4 algosIter$nextNIter(5) [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [1,] 0 0 0 0 1 1 3 4 3 4 [2,] 0 0 0 0 1 1 3 4 4 3 [3,] 0 0 0 0 1 1 4 3 3 4 [4,] 0 0 0 0 1 1 4 3 4 3 [5,] 0 0 0 0 1 1 4 4 3 3 ## last permutation algosIter$back() [1] 4 4 3 3 1 1 0 0 0 0 ## use reverse iterator methods algosIter$prevNIter(5) [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [1,] 4 4 3 3 1 0 1 0 0 0 [2,] 4 4 3 3 1 0 0 1 0 0 [3,] 4 4 3 3 1 0 0 0 1 0 [4,] 4 4 3 3 1 0 0 0 0 1 [5,] 4 4 3 3 0 1 1 0 0 0 * I am the author of RcppAlgos
Another option is by using the Rcpp package. The difference is that it returns a list. //[[Rcpp::export]] std::vector<std::vector< int > > UniqueP(std::vector<int> v){ std::vector< std::vector<int> > out; std::sort (v.begin(),v.end()); do { out.push_back(v); } while ( std::next_permutation(v.begin(),v.end())); return out; } Unit: milliseconds expr min lq mean median uq max neval cld uniqueperm2(dat) 10.753426 13.5283 15.61438 13.751179 16.16061 34.03334 100 b UniqueP(dat) 9.090222 9.6371 10.30185 9.838324 10.20819 24.50451 100 a