Conversation
|
So, one question is - should MulGen use bool to represent transposes, or should it use blas.Transpose types, which can represent conjugate transpose as well? |
mat64/dense_arithmetic.go
Outdated
There was a problem hiding this comment.
Is MulGen the right name, or should it be GenMul?
There was a problem hiding this comment.
We should have some function comment here.
There was a problem hiding this comment.
I think we can come up with something better than at and bt.
There was a problem hiding this comment.
If it wasn't clear, I'm not sure about the name. MulGen might be better, because Mul is the obvious name and MulGen will be next in the list.
There was a problem hiding this comment.
When we talked about it in #54, @kortschak named it, and I think having it in the order MulGen is better because then in godoc it will show up next to Mul and MulElem.
If you mean that the interface could be GenMuler instead of MulGener, that wouldn't be consistent with the typical naming convention for single method interfaces.
There was a problem hiding this comment.
Instead of at and bt I was thinking of switching it to tA and tB, to mirror the inputs to blas.Dgemm, and change the type from bool to blas.Transpose so that if we get complex matrices the interface will still work. Alternatively, we could call it transA and transB to mirror netlib's quick reference at http://www.netlib.org/blas/
Or we could do something else, any suggestions?
There was a problem hiding this comment.
I personally prefer aTrans and bTrans to either tA or transA
There was a problem hiding this comment.
Also, many of the Dense methods don't have docs, apparently in favor of having them with the interfaces defined in matrix.go. I don't know if that's right or wrong, I've seen it both ways. On the one hand, it reduces the number of places we have to check comments for consistency, but on on the other golint gets mad.
|
I'll be making those changes, and I also went ahead with a benchmark of CovarianceMatrix using MulGen to avoid a call to TCopy and it runs ~35% faster on my crappy macbook using Accelerate. |
mat64/dense_arithmetic.go
Outdated
The inputs should have been transposed. Trying to use this in the stats package panic’ed, and the BLAS docs indicate that the dims should be *after* the op.
|
I'll rework them a bit to make it clearer. |
|
I still have to write tests for the Vectorer and Matrix code paths, fix whatever's wrong, and we have to resolve if methods in Dense should all have godoc comments. |
|
Just throwing this out there -- the actual BLAS function is C = beta * C + alpha * A * B. The beta part is easily solved with Scale (though at some performance penalty), but the "+=" part I think is only solvable with a temporary allocation. We should probably figure out if we want a full mat64 wrapper to the BLAS function, rather than the partial wrapper that this is, and if so, what we want to call it. It seems like if we want the full wrapper, GenMul is the wrong name, and so there is no problem here, but I just wanted to mention it. |
|
Then maybe MulTrans would be more appropriate? |
mat64/dense_test.go
Outdated
There was a problem hiding this comment.
Just type denseAt Dense will do this for you - also below (just type convert to get the *Dense method when you want it implemented). I thought we had already fabricated types like this in the tests though - yes: https://github.com/gonum/matrix/blob/master/mat64/mul_test.go#L225
|
I'm good with MulTrans if we are going to add a MulGen later. |
|
Would we call the function MulGen though? It has a "+=" component which would be different that the other Muls, and different than basically all of the other operations where the receiver is overwritten. |
|
It would kind of be a matrix version of a fused multiply add. Maybe call that one FusedMulAdd and name this MulTrans? |
These were already implemented in mul_test.go
|
I've made the changes you've requested. Is there anything else? |
mat64/dense_arithmetic.go
Outdated
There was a problem hiding this comment.
Should we not test that it's not blas.ConjTrans and panic if it is? Also below. If we're using a blas implementation that should catch this, but it won't a or b are the slow case.
There was a problem hiding this comment.
I agree with @kortschak . We should panic if it's just some random number.
Do we want to have our own constants in mat64 (aka mat64.Transpose)? It seems desirable that users never have to interface with blas beyond registering. It would also avoid the problem where blas actually accepts ConjTrans as a valid input for DXxx cases. Instead, we define
const (
NoTrans = blas.NoTrans
Trans = blas.Trans
)
and now it's logical to panic on ConjTrans because ConjTrans doesn't exist in mat64
There was a problem hiding this comment.
I made it perform a transpose when given a ConjTrans because DGEMM's docs have TRANSA = 'C' or 'c', op( A ) = A'.. The conjugate transpose is defined as the element-wise complex conjugate of the transpose, so in the case of real numbers, it is the same as the transpose, so the behavior is implemented as defined. It sounds like panicing would be a special case where none is needed.
I don't have an issue with putting constants into mat64 to make things easier on users.
There was a problem hiding this comment.
but it still should be
if bTrans == mat64.Trans{
br, bc = bc, br
}else if bTrans != mat64.NoTrans{
panic("mat64: invalid Transpose value")
}
In other words, if I pass -1 into the function it shouldn't act as Transpose.
There was a problem hiding this comment.
One of the ways we could get a real matrix from a complex matrix would be to do
m := NewDense(0,0,nil)
m.MulTrans(A, mat.NoTrans, A, mat.TransConj)edit: where A is a possibly complex matrix.
edit2: I don't know why I thought that would always be true, but it isn't. Sorry, it is late.
There was a problem hiding this comment.
The constants are definitely better if we ever plan on using complex matrices. Otherwise the MulGen sig for a ComplexDense (or whatever) would not be able to express one of the transpose operations.
There was a problem hiding this comment.
But A is not a possibly complex matrix. mat64.Matrix has At which returns a float64. A complex matrix by definition would have to return complex128 from At. In mat128, it will probably need constants. One of the penalties with Go's simplicity is that it will be impossible to mesh the packages fully.
There was a problem hiding this comment.
I hadn't considered that - you're right, Matrix can't do complex.
Alright, I'm fine with either bool (which is what I initially implemented, then scared myself into switching to the flags) or using the flags and panicing. I'd lean towards the bools, because that's one fewer panic that can occur, and callers won't have to look up what to put into it.
There was a problem hiding this comment.
We think the constants are better than a boolean even though it can only take two values here?
I completely missed that. It should be bool.
|
LGTM after discussion of above, but also wait for @btracey. |
mat64/dense_arithmetic.go
Outdated
There was a problem hiding this comment.
On all of these, you can have a
dataTmp := w.mat.Data[r_w.mat.Stride: r_w.mat.Stride + bc]
and then have dataTmp[c]. Probably doesn't save that much given the rest of the inefficiencies, but may as well.
There was a problem hiding this comment.
The trouble is that would require a type assert to access the mat field, and we don't currently have a type that implements Vectorer but doesn't implement RawMatrixer.
There was a problem hiding this comment.
You don't need to assert to get the mat field; w is a Dense.
There was a problem hiding this comment.
Ah, yes you're right.
|
I've changed the code to use booleans, but I don't see how I can implement @btracey's suggestion. Is it good to go without it? |
|
LGTM but again wait for @btracey. |
By taking a slice once, we can avoid doing some extra math on each loop.
|
OK, I've implemented that as well. I haven't benchmarked it though. |
|
LGTM. |
as per #54