Search code examples
rfunctionperspective

dim() Error in outer


I have made the following function I would like to make a 3-dimensional image of using the function "persp", therefore I use the function outer, to get the value of the function for each combination of a and b, but this make an Error.

So my code is:

a<- seq(from=0, to=5,by=0.25)
b<- seq(from=0.1, to=2,by=0.1)

Rab <- function(a,b){
  r <- matrix(ncol = 1, nrow = 4)
  for (p in seq(from=0, to=4,by=1)){
  g <- ifelse(a>=0 & a<1-1/p & p >b, a*p,
         ifelse(a>=0 & a<1-1/b & p< b, -1+(a+1/b),
                ifelse(a > 1-1/max(p,b),-1+p,NA)))
  w <- p
  r[w] <- g
  }
  return(r)
} 

q <- outer(a,b,Rab)

And then I get the following Error and warning messages, which I don't understand.

Error in outer(a, b, Rab) : 
  dims [product 420] do not match the length of object [4]
In addition: Warning messages:
1: In r[w] <- g :
  number of items to replace is not a multiple of replacement length
2: In r[w] <- g :
  number of items to replace is not a multiple of replacement length
3: In r[w] <- g :
  number of items to replace is not a multiple of replacement length
4: In r[w] <- g :
  number of items to replace is not a multiple of replacement length

I have tried to read about it, and I think it is because I have constructed the function Rab wrong, but I don't know how to correct it.

Any help is appreciated.


Solution

  • You are right that your Rab function is wrong. The documentation of outer says

    X and Y must be suitable arguments for FUN. Each will be extended by rep to length the products of the lengths of X and Y before FUN is called.

    FUN is called with these two extended vectors as arguments (plus any arguments in ...). It must be a vectorized function (or the name of one) expecting at least two arguments and returning a value with the same length as the first (and the second).

    So in your example a and b are extended to both have length length(a) * length(b), which happens to be 420 in your case. your function Rab should then return a vector of the same length.

    In Rab you compute a vector g that has the correct length and would be suitable as a return value. Instead of returning this vector you try to assign it to an entry in the matrix r. Note that this matrix is defined as

    r <- matrix(ncol = 1, nrow = 4)
    

    and can't hold vectors of length 420 in either its rows or columns (this is what the warning messages are about). You lose all but the first element of your vector g in the process. You then go on to re-compute g with a slightly different set of parameters, which brings us to the next problem. These computations happen in a loop that is defined like this:

    for (p in seq(from=0, to=4,by=1)){
      ## compute g ...
      r[p] <- g
    }
    

    You seem to expect this loop to be executed four times but it is actually run five times for values of p equalling 0, 1, 2, 3 and 4. This means that the first g is assigned to r[0], which R silently ignores. Of course when you then try to return r none of this really matters because it only has length 4 (rather than 420) and this triggers an error.

    I'm not convinced that I really understand what you are trying to do but the following might be a step in the right direction.

    Rab <- function(a, b, p){
      ifelse(a>=0 & a<1-1/p & p >b, a*p,
                     ifelse(a>=0 & a<1-1/b & p< b, -1+(a+1/b),
                            ifelse(a > 1-1/max(p,b),-1+p,NA)))
    }
    

    This will compute the g from your function once for a fixed value of p and return the result. You'd call this like so (for p=0):

    q <- outer(a, b, Rab, 0)
    

    If you want to call it for a number of different p you can do something like

    q <- lapply(0:3, function(x,y,f, p) outer(x, y, f, p), x=a, y=b, f=Rab)
    

    This would call Rab with p = 0, 1, 2 and 3 (I'm guessing that's what you want, adjust as required).