shabbychef / madness

Multivariate Automatic Differentiation R package
GNU Lesser General Public License v3.0
31 stars 0 forks source link

Concatenation #15

Open ZTaylor205 opened 6 years ago

ZTaylor205 commented 6 years ago

Concatenation seems to work properly if you put the madness object first, but not second. Minimum working example:

> x = c(1,2,3)
> xmad = madness(x)
Warning message:
In madness(x) : no dimension given, turning val into a column
> x2 = c(0,xmad)
> x3 = c(xmad,0)

> #this one works
> x3
class: madness 
        d rbind(x,numeric)
 calc: -------------------- 
                d x
  val: 1 ...
 dvdx: 1 0 0 ...
 varx:  ...

> x2
[[1]]
[1] 0

[[2]]
class: madness 
        d x
 calc: ----- 
        d x
  val: 1 ...
 dvdx: 1 0 0 ...
 varx:  ...

Heeding the warning message and forcing x to be a column or a row matrix does not fix the problem.

ZTaylor205 commented 6 years ago

Current workaround:

x2 = madness(c(0,x))
x2@dvdx[1,1] = 0 #reflect the fact that the first value is actually a constant term

This solution only works because concatenation is the first thing I need to do. If this were midway through a function, then I would try something like:

x2 = madness(x)
x2@val = array(c(0,val(x2)),dim = c(1 + length(val(x2)),1))
x2@dvdx = rbind(0,dvdx(x2))
shabbychef commented 6 years ago

Thanks for opening this issue, and the others. I am back from vacation and ready to start in on these. For this one, it seems that madness needs a way to mark a value as a constant, and so 'mixable' with any other madness object. That is, the following also fails:

x <- 1:3
xmad <- madness(x)
ymad <- madness(0,xtag='x')
c(xmad,ymad)

It fails because madness does not recognize that the 0 should be any different than the 1:3 and so could vary with them. If it knew somehow that the 0 should be a constant, then it could force a zero derivative for it with respect to anything. I am not sure yet how to implement this.

ZTaylor205 commented 6 years ago

Thanks for maintaining the package. I was able to get things working using the workarounds that I posted, and the result was well worth the effort.

Why not make c(something,xmad) work as follows?:

shabbychef commented 6 years ago

I think the problem is that c is a method which dispatches on its first argument. Thus c(0,xmad) and c(xmad,0) will call different methods. As you observed above, the first one of these returns a list, and the other a madness object. I am not sure that I can overload all of c to inspect for a single madness object; it may lead to computational slowdowns, since c() is used ubiquitously.

shabbychef commented 6 years ago

Well, I have a unit test for it now, but have no idea how to get around the generic dispatch in c(). I'll have to ask on SO.

shabbychef commented 6 years ago

In the meantime, since the implementation of c merely calls rbind, use rbind instead of concatenation. This is more fitting with the design goal that madness objects track arrays of some kind instead of dimensionless numerics. For array inputs, using rbind or cbind (or abind) makes more sense anyway.

shabbychef commented 6 years ago

I am going to recommend using rbind instead of c for now; this is more consistent with the philosophy that the values in a madness object have dimension associated with them, and one cannot concatenate them without specifying the dimension along which to bind. Moreover, my implementation of c, if I can ever figure out the 'dots generic' form, will merely call rbind anyway.