简体   繁体   English

如何停止随机行走

[英]How to stop a random walk

plot(0:70,0:70, type="n", xlab="X", ylab="Y")

x<-40
y<-40

x2<-60
y2<-60

points(x, y, pch=16, col="red", cex=1.5)
points(x2, y2, pch=16, col="green", cex=1.5)

for (i in 1:10000){
    xi<-sample(c(1,0,-1),1)
    yi<-sample(c(1,0,-1),1)
    x2i<-sample(c(1,0,-1),1)
    y2i<-sample(c(1,0,-1),1)
    lines(c(x,x+xi),c(y,y+yi))
    lines(c(x2,x2+x2i),c(y2,y2+y2i), col="red")
    x<-x+xi
    y<-y+yi
    x2<-x2+x2i
    y2<-y2+y2i
    if(x2==x && y==y2) {
        break
    }
}

I have this random walk with two lines and I need it to stop when the two lines meet. 我有两行随机走动,两行相遇时我需要停下来。

First, I drew an empty plot and two start points for the lines. 首先,我画了一个空图和两条线的起点。 Then I have this for loop for the lines to move, to draw them on the plot and to get the new start points for the next iteration. 然后,我有一个for循环,用于直线移动,在绘图上绘制它们并为下一次迭代获取新的起点。

I tried to make it stop when the lines meet using: if(x2==x && y==y2) { break } but the lines only stop if they are on the same point and at the same time (in the same iteration) and I need them to stop if one of them crosses the other. 我试图使行在使用时相遇时停止: if(x2==x && y==y2) { break }但行仅在它们位于相同点且同时(在同一迭代中)停止如果他们中的一个越过另一个,我就需要他们停下来。 If one crosses any point already draw for the other line. 如果一个交叉点已经画出另一条线。 I think the problem is that the points already drawn are not saved anywhere so I cannot compare them with the points of the lines. 我认为问题在于已经绘制的点不会保存在任何地方,因此我无法将它们与直线的点进行比较。 Maybe I need to save the points out of the loop? 也许我需要将积分保存到循环之外? Someone knows how to stop it? 有人知道如何制止它吗?

N      <- 10000
D      <- 1
coef.1 <- matrix(NA,N,2)
coef.2 <- matrix(NA,N,2)
path.1 <- matrix(NA,N,2)
path.2 <- matrix(NA,N,2)
path.1[1,] <- c(40,40)
path.2[1,] <- c(60,60)
d.start    <- sqrt(sum((path.1[1,]-path.2[1,])^2))
ch <- "."
set.seed(1)
system.time({
  for (i in 2:N){
    if (i%%50==0) cat(ch)
    path.1[i,] <- path.1[i-1,] + sample(-D:D,2)
    path.2[i,] <- path.2[i-1,] + sample(-D:D,2)
    coef.1[i,] <- get.line(path.1[(i-1):i,])
    coef.2[i,] <- get.line(path.2[(i-1):i,])
    r.1 <- sqrt(max(rowSums((path.1[1:i,]-path.1[1,])^2)))
    r.2 <- sqrt(max(rowSums((path.2[1:i,]-path.2[1,])^2)))
    if (r.1+r.2 < d.start) next  # paths do not overlap
    ch <- "1"
    d.1 <- sqrt(min(rowSums((path.2[1:i,]-path.1[1,])^2)))
    d.2 <- sqrt(min(rowSums((path.1[1:i,]-path.2[1,])^2)))
    if (d.1>r.1 & d.2>r.2) next
    ch <- "2"
    cross <- sapply(2:i,
               function(k){seg.intersect(path.2[(k-1):k,],path.1[(i-1):i,],k)})
    if (any(cross)) break
    cross <- sapply(2:i,
               function(k){seg.intersect(path.1[(k-1):k,],path.2[(i-1):i,],k)})
    if (any(cross)) break
  }
})
# 11111111112222222222222222222222
#    user  system elapsed 
# 1016.82    0.13 1024.18
print(paste("End at Step: ",i))
# [1] "End at Step:  1624"
plot(0:100,0:100, type="n", xlab="X", ylab="Y")
points(path.1[1,1],path.1[1,2], pch=16, col="red", cex=1.5)
points(path.2[1,1],path.2[1,2], pch=16, col="green", cex=1.5)
lines(path.1[1:i,])
lines(path.2[1:i,],col="red")

As @CarlWitthoft points out, at each step you must check all the previous line segments for crossings. 正如@CarlWitthoft指出的那样,在每个步骤中,您都必须检查所有先前的线段是否存在交叉。 This creates a serious problem, because at each new step, i , there are 2*(i-1) tests for crossings. 这就产生了一个严重的问题,因为在每个新步骤i ,都有2*(i-1)交叉测试。 So, if you get to a crossing at step k , there will have been 2*k*(k+1) tests. 因此,如果您在步骤k到达交叉口,将进行2*k*(k+1)测试。 If k ~O(10000) , then there can be potentially 100MM tests. 如果k ~O(10000) ,则可能存在100MM测试。

To make this more efficient, we store not only the two new points at each step, but also the slope and intercept of the newly created line segments. 为了提高效率,我们不仅在每个步骤中存储了两个新点,而且还存储了新创建的线段的斜率和截距。 This avoids recalculating slope and intercept for all prior line segments at each step. 这样避免了在每个步骤中重新计算所有先前线段的斜率和截距。 In addition, we calculate the path radius, r, for each path at each step. 此外,我们还计算了每个步骤中每个路径的路径半径r。 This is the distance between the starting point and the point on the path farthest from the starting point. 这是起点与路径上距起点最远的点之间的距离。 If the distance between the path starting point and the closest point on the other path is larger than the path radius, there can be no crossings and we can skip the individual segment comparisons for this step. 如果路径起点和另一条路径上最接近点之间的距离大于路径半径,则可能没有交叉,我们可以跳过此步骤的各个线段比较。

Your problem is interesting for other reasons. 由于其他原因,您的问题很有趣。 The normal way to test for crossings is to determine if the intersection between the two lines is on either segment. 测试交叉的正常方法是确定两条线之间的交点是否在任何一条线上。 This is cumbersome but straightforward. 这很麻烦但是很简单。 However there are many special cases: Are the lines parallel? 但是,有许多特殊情况:线是否平行? If so, are they coincident? 如果是这样,它们是巧合吗? If so do the segments overlap? 如果是这样,那么片段重叠吗? What about vertical lines (slope=Inf). 垂直线(slope = Inf)呢? Because you set the increment to a random integer on [-1,1], all of these possibilities are quite likely to happen eventually in a path with 10000 steps. 因为您将增量设置为[-1,1]上的随机整数,所以所有这些可能性很可能最终会在具有10000步的路径中发生。 So the function seg.intersect(...) above has to account for all these possibilities. 因此,上面的函数seg.intersect(...)必须考虑所有这些可能性。 You would think there is a function in R that does that, but I couldn't find one, so here is a (messy) version: 您可能会认为R中有一个函数可以做到这一点,但我找不到一个函数,所以这里是一个(混乱的)版本:

get.line <- function(l) {        # returns slope and intercept 
  if (diff(l)[1]==0) return(c(Inf,NA))
  m <- diff(l)[2]/diff(l)[1]
  b <- l[1,2]-m*l[1,1]
  return(c(m,b))
}
is.between <- function(x,vec) {  # test if x is between values in vec
  return(x>=range(vec)[1] & x<=range(vec)[2])
}
special.cases = function(l1,l2, coeff) {
  # points coincide: not a line segment!
  if (rowSums(diff(l1)^2)==0 | rowSums(diff(l2)^2)==0) return(c(NA,FALSE))
  # both lines vertical
  if (is.infinite(coeff[1,1]) & is.infinite(coeff[2,1])) {
    if (l1[1,1]!=l2[1,1]) return(c(NA,FALSE))
    t1 <- is.between(l1[1,2],l2[,2]) | is.between(l1[2,2],l2[,2])
    t2 <- is.between(l2[1,2],l1[,2]) | is.between(l2[2,2],l1[,2])
    return(c(NA,t1|t2))
  }
  # only l1 is vertical
  if (is.infinite(coeff[1,1]) & is.finite(coeff[2,1])) {
    x <- l1[1,1]
    y <- c(x,1) %*% coeff[2,]
    return(c(x,y))
  }
  # only l2 is vertical
  if (is.finite(coeff[1,1]) & is.infinite(coeff[2,1])) {
    x <- l2[1,1]
    y <- c(x,1) %*% coeff[1,]
    return(c(x,y))
  }
  # parallel, non-coincident lines
  if (diff(coeff[,1])==0 & diff(coeff[,2])!=0) return(c(NA,FALSE))
  # parallel, coincident lines
  if (diff(coeff[,1])==0 & diff(coeff[,2])==0) {
    x <- l1[1,1]
    y <- l1[1,2]
    return(c(x,y))
  }
  # base case: finite slopes, not parallel
  x <- -diff(coeff[,2])/diff(coeff[,1])
  y <- c(x,1) %*% coeff[1,]
  return(c(x,y))   
}
seg.intersect <- function(l1,l2,i){
  pts   <- list(l1,l2)
  coeff <- rbind(coef.1[i,],coef.2[i,])
  z <- special.cases(l1,l2, coeff)
  if (is.na(z[1])) return (z[2])
  #  print(coeff)
  #  print(z)
  found <- do.call("&",
    lapply(pts,function(x){is.between(z[1],x[,1]) & is.between(z[2],x[,2])}))
  return(found)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM