Suppose I have a set of inequalities:
-2x + y <= -3
1.25x + y <= 2.5
y >= -3
And I can summarize the information as follows:
mat <- matrix(c(-2, 1, 1.25, 1, 0, 1), nrow = 3, byrow = TRUE)
dir <- c("<=", "<=", ">=")
rhs <- c(-3, 2.5, -3)
I wrote the following function to plot the inequalities:
plot(0, 0, xlim = c(-1, 5), ylim = c(-4, 1))
plot_ineq <- function(mat, dir, rhs, xlow, xhigh){
line <- list()
for(i in 1:nrow(mat)){
if(mat[i, 2] > 0){
line[[i]] <- sapply(seq(xlow, xhigh, 0.1), function(x) (rhs[i] - mat[i, 1] * x)/mat[i, 2])
}else if(mat[i, 2] < 0){
line[[i]] <- sapply(seq(xlow, xhigh, 0.1), function(x) (rhs[i] - mat[i, 1] * x)/mat[i, 2])
if(dir[i] == ">="){
dir[i] = "<="
}else dir[i] = ">="
}
lines(seq(xlow, xhigh, 0.1), line[[i]])
}
}
plot_ineq(mat = mat, dir = dir, rhs = rhs, xlow = -1, xhigh = 5)
I have two questions: (1) how can I have a blank plot without having the (0, 0) point there? and (2) how can I shade the corresponding region according to dir? Should I try ggplot2?
I'm simply looking to shade the area that is described by the set of inequalities above. Not where (0, 0) lies.
1) Change the last inequality to be the same direction as the others and then use plotPolytope in gMOIP.
library(gMOIP)
mat <- matrix(c(-2, 1, 1.25, 1, 0, -1), nrow = 3, byrow = TRUE)
rhs <- c(-3, 2.5, 3)
argsFaces <- list(argsGeom_polygon = list(fill = "blue"))
plotPolytope(mat, rhs, argsFaces = argsFaces)
giving (continued after image)
2) The above uses ggplot2 graphics but if you prefer classic graphics then using mat and rhs from above:
library(gMOIP)
cp <- cornerPoints(mat, rhs)
cp <- cp[chull(cp), ] # chull gives indices of convex hull in order
plot(cp, type = "n")
polygon(cp, col = "blue")
# not shown but to add lines run this too
for(i in 1:nrow(cp)) {
ix <- if (i < nrow(cp)) i + 0:1 else c(i, 1)
b <- diff(cp[ix, 2]) / (d <- diff(cp[ix, 1]))
if (abs(d) < 1e-5) abline(v = a <- cp[i, 1])
else abline(a = a <- cp[i, 2] - b * cp[i, 1], b = b)
}
giving (continued after image)
3) Note that there is an archived package named intpoint on CRAN and it could be used to draw the boundary of the feasible region and lines. It does have the limitation that it is hard coded to show X and Y axes between -1 and 5 although it might not be hard to generalize it. It is used like this (output not shown) where mat, rhs and cp are from above.
library(intpoint)
intpoint:::show2d(mat, rhs, c = numeric(2))
polygon(cp, col = "blue")
I am developing a (complex) CTMC model in R (as a beginner in R) to simulate the distribution of parasite load (counts) at 8 different body parts of a fish; assuming a parasite can move from one body part to another randomly. To start with a simple block of codes as below, it is able to simulate CTMC but returns errors below when trying to repeat it a number of times (for some runs).
Error in sample.int(x, size, replace, prob) : too few positive
probabilities
Warning message:
In rexp(1, Qt) : NAs produced
I realized, most of the rate values in the Q (matrix) are zero and thus, sampling at such instances, returns such as error. I would like to know if there is anyway to correct this error so as to run the model a number of times without such an error.
To make it simple, I started with these piece of codes:
Fishsim_model <- function(b,d,m,X0,Ti){
#b=birth rate; d=death rate; m=movement rate; Ti=finishing time
#X0=initial distribution; X= states
X <- X0
Ti <- floor(Ti)
ti <- 0 # (initial) time
day <- 1
saved <- matrix(0, Ti+1, 8) #Matrix of zeros to save final results
saved[day,] <- X0
Q <- rep(0, 36) # vector of rates
Qt <- 0 # Qt = sum(Q) is departure rate from current state
while (ti < Ti){
#Calculate rates
Q[1]<-X[1]*b
Q[2]<-X[2]*b
Q[3]<-X[3]*b
Q[4]<-X[4]*b
Q[5]<-X[5]*b
Q[6]<-X[6]*b
Q[7]<-X[7]*b
Q[8]<-X[8]*b
Q[9]<-X[1]*d
Q[10]<-X[2]*d
Q[11]<-X[3]*d
Q[12]<-X[4]*d
Q[13]<-X[5]*d
Q[14]<-X[6]*d
Q[15]<-X[7]*d
Q[16]<-X[8]*d
Q[17]<-X[1]*m
Q[18]<-X[3]*m/3
Q[19]<-X[4]*m/5
Q[20]<-X[6]*m/2
Q[21]<-X[4]*m/5
Q[22]<-X[5]*m/2
Q[23]<-X[2]*m/2
Q[24]<-X[5]*m/2
Q[25]<-X[3]*m/2
Q[26]<-X[2]*m/2
Q[27]<-X[3]*m/3
Q[28]<-X[7]*m/2
Q[29]<-X[8]*m/2
Q[30]<-X[4]*m/5
Q[31]<-X[4]*m/4
Q[32]<-X[7]*m/2
Q[33]<-X[6]*m/2
Q[34]<-X[8]*m/2
Q[35]<-X[3]*m/4
Q[36]<-X[4]*m/5
Qt <- sum(Q)
# time for next jump
ti <- ti + rexp(1, Qt)
# new state
j <- sample(36, 1, prob = Q)
if (j == 1) {
X[1] <- X[1] + 1
} else if (j==2){
X[2]<- X[2]+1
} else if (j==3){
X[3]<-X[3]+1
} else if (j==4){
X[4]<-X[4]+1
} else if (j==5){
X[5]<-X[5]+1
} else if (j==6){
X[6]<-X[6]+1
} else if (j==7){
X[7]<-X[7]+1
} else if (j==8){
X[8]<-X[8]+1
} else if (j==9){
X[1]<-X[1]-1
} else if (j==10){
X[2]<-X[2]-1
} else if (j==11){
X[3]<-X[3]-1
} else if (j==12){
X[4]<-X[4]-1
} else if (j==13){
X[5]<-X[5]-1
} else if (j==14){
X[6]<-X[6]-1
} else if (j==15){
X[7]<-X[7]-1
}else if (j==16){
X[8]=X[8]-1
} else if (j==17){
X[1]=X[1]-1
X[3]=X[3]+1
} else if (j==18){
X[1]=X[1]+1
X[3]=X[3]-1
} else if (j==19){
X[4]=X[4]-1
X[6]=X[6]+1
} else if (j==20){
X[4]=X[4]+1
X[6]=X[6]-1
} else if (j==21){
X[4]=X[4]-1
X[5]=X[5]+1
} else if (j==22){
X[4]=X[4]+1
X[5]=X[5]-1
} else if (j==23){
X[2]=X[2]-1
X[5]=X[5]+1
} else if (j==24){
X[2]=X[2]+1
X[5]=X[5]-1
} else if (j==25){
X[3]=X[3]-1
X[2]=X[2]+1
} else if (j==26){
X[3]=X[3]+1
X[2]=X[2]-1
} else if (j==27){
X[3]=X[3]-1
X[7]=X[7]+1
} else if (j==28){
X[3]=X[3]+1
X[7]=X[7]-1
} else if (j==29){
X[8]=X[8]-1
X[4]=X[4]+1
} else if (j==30){
X[8]=X[8]+1
X[4]=X[4]-1
} else if (j==31){
X[4]=X[4]-1
X[7]=X[7]+1
} else if (j==32){
X[4]=X[4]+1
X[7]=X[7]-1
} else if (j==33){
X[6]=X[6]-1
X[8]=X[8]+1
} else if (j==34){
X[6]=X[6]+1
X[8]=X[8]-1
} else if (j==35){
X[3]=X[3]-1
X[4]=X[4]+1
} else if (j==36){
X[3]=X[3]+1
X[4]=X[4]-1
}
day.old <- day #Keep track of previous days
day=ceiling(ti)
if (day > day.old){
saved[(day.old+1):day,] <-
matrix(saved[day.old,], (day - day.old), 8, byrow=TRUE) # What was this intended to achieve?
saved[day,] <- X
cat("day =", day, X, "\n")
#cat('day:', sprintf('%7.4f',day.old), ' tail:', X[1], ' Anal:', X[2], ' LB:', X[3],' UB:',
# X[4],' Pelvic:', X[5],' Pectoral:', X[6],' dorsal:', X[7],' Head:', X[8], '\n')
}
}
return(saved)
}
#Suppose parasite prefer tail
b <- 0.5 #birth rate per day
d <- 0.14 #death rate
m <- 0.3 #movement rate
X0 <- c(2,0,0,0,0,0,0,0)# initial condition of gyro that prefers the tail
Ti <- 17 #finishing time
#set.seed(12)
Results <- Fishsim_model(b, d, m, X0, Ti)
Results
Both error messages suggest that at some point all values in the Q vector are 0, which causes the first error. Example : sample(3,1, prob = c(0,0,0)).
Consequently, the rate (Qt), which u are passing to the exponential distribution random generator is also 0 and NaN is returned, which causes the second error. Example : rexp(1,0)
Unfortunately, your code was hard for me to read, so I refactored it. You can find an augmented version below, which works with the example input. My guess is that there is an error somewhere causing Q to take the 0 state, you can trace it with some print statements and debug functionalities. You can further refactor this piece of code to make it even more readable and performant.
In general, you can investigate the mathematical conditions for the initial inputs to guarantee that the Q vector never falls in the 0 state. I am not sure if you are looking for pointers on how to do this, as well.
HTH
CHANGE_MATRIX <- matrix(
c(-1, 0, 1, 0, 0, 0, 0, 0
, 1, 0, -1, 0, 0, 0, 0, 0
, 0, 0, 0, -1, 0, 1, 0, 0
, 0, 0, 0, 1, 0, -1, 0, 0
, 0, 0, 0, -1, 1, 0, 0, 0
, 0, 0, 0, 1, -1, 0, 0, 0
, 0, -1, 0, 0, 1, 0, 0, 0
, 0, 1, 0, 0, -1, 0, 0, 0
, 0, 1, -1, 0, 0, 0, 0, 0
, 0, -1, 1, 0, 0, 0, 0, 0
, 0, 0, -1, 0, 0, 0, 1, 0
, 0, 0, 1, 0, 0, 0, -1, 0
, 0, 0, 0, 1, 0, 0, 0, -1
, 0, 0, 0, -1, 0, 0, 0, 1
, 0, 0, 0, -1, 0, 0, 1, 0
, 0, 0, 0, 1, 0, 0, -1, 0
, 0, 0, 0, 0, 0, -1, 0, 1
, 0, 0, 0, 0, 0, 1, 0, -1
, 0, 0, -1, 1, 0, 0, 0, 0
, 0, 0, 1, -1, 0, 0, 0, 0)
, ncol = 8
, byrow = T
)
UPDATE_LOCATION <- c(1, 3, 4, 6, 4, 5
, 2, 5, 3, 2, 3, 7
, 8, 4, 4, 7, 6, 8
, 3, 4)
UPDATE_WEIGHT <- c(1, 3, 5, 2, 5, 2
, 2, 2, 2, 2, 3, 2
, 2, 5, 4, 2, 2, 2
, 4, 5)
UPDATE_INDEX <- seq(17, 36)
BODY_PARTS <- c(' Tail'
,' Anal'
,' LB'
,' UB'
,' Pelvic'
,' Pectoral'
,' dorsal'
,' Head')
Fishsim_model <- function(b,d,m,X0,Ti){
#b=birth rate; d=death rate; m=movement rate; Ti=finishing time
#X0=initial distribution; X= states
X <- X0
Ti <- floor(Ti)
ti <- 0 # (initial) time
day <- 1
saved <- matrix(0, Ti+1, 8) #Matrix of zeros to save final results
saved[day,] <- X0
Q <- vector('numeric', 36)
Qt <- 0 # Qt = sum(Q) is departure rate from current state
while (ti < Ti){
#Calculate rates
Q[1:8] <- X*b
Q[9:16] <- X*d
Q[UPDATE_INDEX]<-X[UPDATE_LOCATION[seq_along(UPDATE_INDEX)]]*
(m*(1/UPDATE_WEIGHT[seq_along(UPDATE_INDEX)]))
Qt <- sum(Q)
# time for next jump
ti <- ti + rexp(1, Qt)
# new state
j <- sample(36, 1, prob = Q)
if (j <= 8) {
X[j] <- X[j] + 1
} else if (j <= 16){
X[j-8] <- X[j-8] - 1
} else{
X <- X + CHANGE_MATRIX[j-16, ]
}
day.old <- day #Keep track of previous days
day <- ceiling(ti)
if (day > day.old){
# What was this intended to achieve?
# saved[(day.old+1):day,] <- matrix(saved[day.old,]
# , (day - day.old)
# , 8
# , byrow=TRUE)
saved[day, ] <- X
cat(
paste('day:', day)
, '\n'
, paste(BODY_PARTS, ':', X)
, '\n'
)
}
}
return(saved)
}
#Suppose parasite prefer tail
b <- 0.5 #birth rate per day
d <- 0.14 #death rate
m <- 0.3 #movement rate
X0 <- c(2,0,0,0,0,0,0,0)# initial condition of gyro that prefers the tail
Ti <- 17 #finishing time
#set.seed(12)
Results <- Fishsim_model(b, d, m, X0, Ti)
Results
I have been able to figure the way out to prevent the errors based previous recommendation received here. This will help me run the model a number of times without any error message. I just needed to break the loop from running when the sum of rates equals 0.
Below is the single code of line I needed to include in my codes;
enter code here
Qt=sum(Q)
if (Qt == 0) break #Just this line code to help break the loop and return to the next
ti <- ti + rexp(1,Qt)
j=sample(152,1,prob=Q)
I want to plot a polyhedron, which is described by the following inequalities:
3*x+5*y+9*z<=500
4*x+5*z<=350
2*y+3*z<=150
x,y,z>=0
It is a linear program. The objective function is:
4*x+3*y+6*z
The polyhedron is the feasible region for this program.
I am able to plot the inequalities as planes, which should describe the polyhedron
(Note that this is my first try with rgl, so the code is kinda messy. if you want to improve it, please feel free to do so):
# setup
x <- seq(0,9,length=20)*seq(0,9,length=20)
y <- x
t <- x
f1 <- function(x,y){y=70-0.8*x}
z1 <- outer(x,y,f1)
f2 <- function(x,y){500/9-x/3-(5*y)/9}
z2 <- outer(x,y,f2)
f3 <- function(x,y){t=50-(2*y)/3}
z3 <- outer(x,y,f3)
# plot planes with rgl
uM = matrix(c(0.72428817, 0.03278469, -0.68134511, 0,
-0.6786808, 0.0555667, -0.7267077, 0,
0.01567543, 0.99948466, 0.05903265, 0,
0, 0, 0, 1),
4, 4)
library(rgl)
open3d(userMatrix = uM, windowRect = c(0, 0, 400, 400))
rgl.pop("lights")
light3d(diffuse='white',theta=0,phi=20)
light3d(diffuse="gray10", specular="gray25")
rgl.light(theta = 0, phi = 0, viewpoint.rel = TRUE, ambient = "#FFFFFF",
diffuse = "#FFFFFF", specular = "#FFFFFF", x=30, y=30, z=40)
rgl.light(theta = 0, phi = 0, viewpoint.rel = TRUE, ambient = "#FFFFFF",
diffuse = "#FFFFFF", specular = "#FFFFFF", x=0, y=0, z=0)
bg3d("white")
material3d(col="white")
persp3d(x,y,z3,
xlim=c(0,100), ylim=c(0,100), zlim=c(0,100),
xlab='x', ylab='y', zlab='z',
col='lightblue',
ltheta=100, shade=0, ticktype = "simple")
surface3d(x, y, z2, col='orange', alpha=1)
surface3d(t, y, z1, col='pink', alpha=1, smooth=TRUE)
Now I want to plot the region that is described by the planes with
x,y,z>=0.
But I don't know how to do it. I tried to do it like this:
x <- seq(0,9,length=20)*seq(0,9,length=20)
y <- x
z <- x
f4 <- function(x,y,t){
cond1 <- 3*x+5*y+9*z<=500
cond2 <- 4*x+5*z<=350
cond3 <- 2*y+3*z<=150
ifelse(cond1, 3*x+5*y+9*z,
ifelse(cond2, 4*x+5*z,
ifelse(cond3, 2*y+3*z,0)))
}
f4(x,y,z)
z4 <- outer(x,y,z,f4) # ERROR
But this is the point where I'm stuck. outer() is defined only for 2 variables, but I have three. How can I move on from here?
You can compute the vertices of the polyhedron by intersecting the planes 3 at a time
(some of the intersections are outside the polyhedron, because of other inequalities:
you have to check those as well).
Once you have the vertices, you can try to connect them.
To identify which are on the boundary, you can take the middle of the segment,
and check if any inequality is satisfied as an equality.
# Write the inequalities as: planes %*% c(x,y,z,1) <= 0
planes <- matrix( c(
3, 5, 9, -500,
4, 0, 5, -350,
0, 2, 3, -150,
-1, 0, 0, 0,
0, -1, 0, 0,
0, 0, -1, 0
), nc = 4, byrow = TRUE )
# Compute the vertices
n <- nrow(planes)
vertices <- NULL
for( i in 1:n )
for( j in 1:n)
for( k in 1:n )
if( i < j && j < k ) try( {
# Intersection of the planes i, j, k
vertex <- solve(planes[c(i,j,k),-4], -planes[c(i,j,k),4] )
# Check that it is indeed in the polyhedron
if( all( planes %*% c(vertex,1) <= 1e-6 ) ) {
print(vertex)
vertices <- rbind( vertices, vertex )
}
} )
# For each pair of points, check if the segment is on the boundary, and draw it
library(rgl)
open3d()
m <- nrow(vertices)
for( i in 1:m )
for( j in 1:m )
if( i < j ) {
# Middle of the segment
p <- .5 * vertices[i,] + .5 * vertices[j,]
# Check if it is at the intersection of two planes
if( sum( abs( planes %*% c(p,1) ) < 1e-6 ) >= 2 )
segments3d(vertices[c(i,j),])
}