Assume you are given a vector of degrees which represent points on the unit circle. How could you formally check to see what the minimum number of points you could isolate in one semicircle with a diameter? I understand there may be multiple diameters which satisfy this property for a given set of data points. That is okay. I am solely interested in the minimum number of points which can be isolated, not the diameter in particular. It also needs to be computationally efficient, so it works for a large number of points. I have written the following based on @db suggestion, but the algorithm fails for tst4.
In R,
# Plots the points on a circle and attempts to find the minimum m (algorithm incorrect for tst )
min_dia <- function(degs, plot = T){
library(dplyr)
plot_circle <- function(x, y, r) {
angles <- seq(0, 2*pi,length.out = 360)
lines(r*cos(angles) + x, r*sin(angles) + y)
}
deg <- degs
plot_boo <- plot
# @d.b suggestion method for finding m
temp <- abs((deg - min(deg) + 180) %% 360 - 180)
m <- min(table(cut(temp, breaks = c(-180, 90, 180))))
if(plot_boo == T){
tm_deg <- c(0, 30, 45, 60, 90, 120, 135, 150, 180, 210, 225, 240, 270, 300, 315, 330)
tm_rad <- (tm_deg * pi) / 180
th <- (deg*pi)/180
r <- 1
x <- r*cos(th)
y <- r*sin(th)
windows.options(width = 600, height = 600)
plot(x, y, xlim = c(-1.1, 1.1), ylim = c(-1.1, 1.1), pch = 20, xlab = "", ylab = "", main = "Plot of Given Data Points by Degrees")
plot_circle(0, 0, 1)
points(0, 0)
text(r*cos(tm_rad), r*sin(tm_rad), labels = paste0(tm_deg), cex= 0.5, pos = 3)
}
return(m)
}
# Function to plot diameter by degrees
plot_dia <- function(deg){
deg1 <- deg
deg2 <- deg + 180
th1 <- (deg1*pi)/180
th2 <- (deg2*pi)/180
x1 <- cos(th1)
y1 <- sin(th1)
x2 <- cos(th2)
y2 <- sin(th2)
lines(c(x1, x2), c(y1, y2))
}
# Testing
tst1 <- c(15, 45, 20) # m = 0
tst2 <- c(15, 45, 200) # m = 1
tst3 <- c(15, 46, 114, 137, 165, 187, 195, 215, 271, 328) # m = 3
tst4 <- c(36, 304, 281, 254, 177, 59, 47, 158, 244, 149, 317, 235, 345, 209, 204,
156, 325, 95, 215, 267)
# Implementation
min_dia(tst1)
plot_dia(90) # eyeball and plot to check
min_dia(tst2)
plot_dia(190) # eyeball and plot to check
min_dia(tst3)
plot_dia(110) # eyeball and plot to check
min_dia(tst4)
plot_dia(150) # m is probably 2
For the three points I have provided in the code with degrees 15, 45, and 225, the minimum number of points (say m) I could separate with a line would be 1.
For the points with degrees 15, 20, 25, the answer would obviously be 0.
Any help or guidance on an efficient algorithm to solve this minimization problem would be greatly appreciated.
Update:
Here is the plot if you were to run through the R code along with an example of a line which illustrates the minimum number of points you could separate, being 1.
Update:
I have also updated the code above which allows one to plot the data points, speculate a diameter which minimizes m, and the plot the diameter by degree.
If points are not sorted, then sort them by angle.
Walk through the list using two-pointer approach. Increment right index if angle difference is <180
, increment left index if angle difference is >180
. Minimum from (right-left, length-right+left)
is your desired value.
Note that scanning should be performed in cyclic manner (you may add copy of the list with +360 addition like this 15, 45, 225, 375, 585
)
Here is a brute force method. Just draw a line at all angle ( 0.5:359.5
) and see what angle gives the least value.
bar = function(degs){
CUTS = sapply(0:359 + 0.5, function(D){
temp = ((degs - D + 180) %% 360 - 180)
min(table(cut(temp, breaks = c(-180, 0, 180))))
})
D = (0:359 + 0.5)[which.min(CUTS)]
m = min(CUTS)
plot(0, 0, type = "n",
xlim = c(-1.5, 1.5), ylim = c(-1.5, 1.5),
ann = FALSE, axes = FALSE, asp = 1)
plotrix::draw.circle(0, 0, 1)
degs = degs * pi/180
xs = cos(degs)
ys = sin(degs)
x1 = cos(D * pi/180)
y1 = sin(D * pi/180)
x2 = cos((D * pi/180) + pi)
y2 = sin((D * pi/180) + pi)
lines(c(x1, x2), c(y1, y2))
points(xs, ys, pch = 19)
points(0, 0)
return(c(min_num = m, angle = D))
}
tst4 <- c(36, 304, 281, 254, 177, 59, 47, 158, 244, 149, 317, 235,
345, 209, 204, 156, 325, 95, 215, 267)
bar(degs = tst4)
# min_num angle
# 5.0 145.5
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.