For a particular time represented by three indistinguishable hands on a clock-face, we are given a cyclic triplet of angles including (but not necessarily in this order) the angle from the 0:00:00 to the first hand arrived at clockwise, the angle to the next hand clockwise from the first, and then the angle from the second to the third hand. 12:30:00 (or 00:30:00) would have a cyclic angle representation of \(15^\circ, 165^\circ, 180^\circ\). Since 06:30:00 also has this same cyclic angle representation (starting with 180, though, and then 15 and 165) it is indistinguishable from 12:30:00.
Now, 03:00:00 has the cyclic representation \(90^\circ, 270^\circ, 0^\circ\), while 09:00:00 has the cyclic representation \(270^\circ, 90^\circ, 0^\circ\), which are different cyclic orientations and therefore, distinguishable.
How many of the 43,200 seconds in a day cannot be deduced?
Let’s construct all of the angles for each of the 43,200 seconds.
## Build the seconds, minutes, and hour vectors, as well as the minute mark
## (or second mark) on the clock.
seconds <- 1:43200
secMM <- seconds %% 60
minutes <- seconds/60
minuteMM <- minutes %% 60
hours <- seconds/3600
hourMM <- hours*5
## Build the angle matrix.
angleMat <- matrix(ncol =3)
for(i in 1:43200){
# Sort so the minute markers are in order from least to greatest.
A <- sort(c(hourMM[i], minuteMM[i], secMM[i]))
## When there is 1 zero, this hand will not be arrived at until the last
## rotation angle. Let's assume it is 60 and place it at the end.
if(sum(A==0)==1){
A <- c(A[2],A[3]-A[2],60-A[3]) * 6
angleMat <- rbind(angleMat, round(A,10)) ## round for fuzzy equality
next
}
else{
## when there are two zeroes, then we spin around to the 0 mark on the
## second rotation and then stay there.
if(sum(A==0)==2){
A <- c(A[3],60-A[3],0)*6
angleMat <- rbind(angleMat, round(A,10))
next
}
A <- c(A[1],A[2]-A[1],A[3]-A[2])*6
angleMat <- rbind(angleMat, round(A,10))
}
}
Now, I need something that determines whether there are duplicates (or triplicates, etc) where if rows are cyclically equivalent than they are duplicates.
## Input a vector, and compute a small matrix of rows that are all cyclically
## equal to the input vector. Output the one that starts with the min value.
canon <- function(v){
rots <- rbind(
v,
v[c(2,3,1)],
v[c(3,1,2)]
)
rots[which.min(rots[,1])[1], ]
}
# apply to the matrix
canonMat <- t(apply(angleMat, 1, canon))
How many of the rows in this matrix are duplicates?
dupIndex <- duplicated(canonMat) | duplicated(canonMat, fromLast = TRUE)
# canonMat[dupIndex, ]
sum(dupIndex)
## [1] 108
Thus, there are 108 times that cannot be deduced because their cyclical angle triplet matches another. An interesting time in this list is 12:06:00, which goes with \(3^\circ, 33^\circ, 324^\circ\) which shares the same cyclical pattern with 10:54:00 (ordered \(324^\circ, 3^\circ, 33^\circ\)).
For the bonus section, I’ll need to check the above for \(1<H\leq M\leq S\) such that \(H*M*S=43200\). First, a function is created to generally build a matrix for a selection of H, M, and S.
## This function avoids row-wise sorting within the Matrix build function
row_sort <- function(A) {
mins <- pmin(A[,1], A[,2], A[,3])
maxs <- pmax(A[,1], A[,2], A[,3])
meds <- A[,1] + A[,2] + A[,3] - mins - maxs
cbind(mins, meds, maxs)
}
## seconds is best in the global environment
SECONDS <- 1:43200
# function to build the matrix with a selected H, M, and S.
MatrixOfAngles <- function(H,M,S, seconds = SECONDS){
secMM <- seconds %% S
minutes <- (seconds/S) %% M
minuteMM <- minutes * S/M
hours <- seconds/S/M
hourMM <- hours*S/H
A <- row_sort(cbind(hourMM, minuteMM, secMM))
zero_count <- rowSums(A == 0)
angleMat <- matrix(0, nrow = nrow(A), ncol = 3)
# exactly one zero
idx1 <- zero_count == 1
angleMat[idx1, ] <- cbind(A[idx1, 2],
A[idx1, 3] - A[idx1, 2],
S - A[idx1, 3]) * 360/S
# exactly two zeros
idx2 <- zero_count == 2
angleMat[idx2, ] <- cbind(A[idx2, 3],
S - A[idx2, 3],
0) * 360/S
# no zeros
idx3 <- zero_count == 0
angleMat[idx3, ] <- cbind(A[idx3, 1],
A[idx3, 2] - A[idx3, 1],
A[idx3, 3] - A[idx3, 2]) * 360/S
# to avoid 1e-14 differences
return(round(angleMat,10))
}
Next, a function that will a vector (or matrix row) of H, M and S values and output the number of duplicates this selection produces.
checkMat <- function(v){
checkM <- MatrixOfAngles(v[1],v[2],v[3])
checkM <- t(apply(checkM, 1, canon))
dupIdx <- duplicated(checkM) | duplicated(checkM, fromLast = TRUE)
return(sum(dupIdx))
}
## See if we get 108
checkMat(c(12,60,60))
## [1] 108
Next, a function to take a number (in this case 43,200) and produce a matrix that exhausts all H, M, S combinations for which \(1<H\leq M\leq S\) and \(H*M*S=43,200\).
three_factorizations <- function(n) {
# must have at least 3 prime factors (with multiplicity)
pf <- primeFactors(n) # from numbers package
if (length(pf) < 3) {
stop("Number must have at least 3 prime factors (with multiplicity).")
}
# using the numbers package, we get divisors of n
divs <- divisors(n)
divs <- divs[divs > 1] # exclude 1
results <- list()
for (i in 1:length(divs)) {
#
a <- divs[i]
for (j in i:length(divs)) {
b <- divs[j]
if (n %% (a * b) != 0) next
c <- n / (a * b)
if (c < b) next # enforce a ≤ b ≤ c
if (c > 1) {
results[[length(results) + 1]] <- c(a, b, c)
}
}
}
do.call(rbind, results)
}
Finally, we build the possible (H,M,S) triplets and cycle through them to find the arrangement with the most duplicates.
PossibleHMS <- three_factorizations(43200)
LargestDupSoFar <- 0
rowWithLargest <- 0
for(r in 1:nrow(PossibleHMS)){
N <- checkMat(PossibleHMS[r,])
rowWithLargest <- ifelse(N>LargestDupSoFar, r, rowWithLargest)
LargestDupSoFar <- ifelse(N>LargestDupSoFar, N, LargestDupSoFar)
}
PossibleHMS[rowWithLargest,]
LargestDupSoFar
When running the code above, it takes a while to produce \(H=30\), \(M=32\), and \(S=45\), where there are 628 duplicate times.