mat: generalise SymDense SymRankOne vector parameters
MODIFY
mat/symmetric.go
mat/symmetric.go
@@ -232,19 +232,33 @@ func (s *SymDense) CopySym(a Symmetric) int {
// SymRankOne performs a symetric rank-one update to the matrix a and stores
// the result in the receiver
// s = a + alpha * x * x'
-func (s *SymDense) SymRankOne(a Symmetric, alpha float64, x *VecDense) {
- n := x.Len()
- if a.Symmetric() != n {
+func (s *SymDense) SymRankOne(a Symmetric, alpha float64, x Vector) {
+ n, c := x.Dims()
+ if a.Symmetric() != n || c != 1 {
panic(ErrShape)
}
s.reuseAs(n)
+
if s != a {
if rs, ok := a.(RawSymmetricer); ok {
s.checkOverlap(generalFromSymmetric(rs.RawSymmetric()))
}
s.CopySym(a)
}
- blas64.Syr(alpha, x.mat, s.mat)
+
+ xU, _ := untranspose(x)
+ if rv, ok := xU.(RawVectorer); ok {
+ xmat := rv.RawVector()
+ s.checkOverlap((&VecDense{mat: xmat, n: n}).asGeneral())
+ blas64.Syr(alpha, xmat, s.mat)
+ return
+ }
+
+ for i := 0; i < n; i++ {
+ for j := i; j < n; j++ {
+ s.set(i, j, s.at(i, j)+alpha*x.AtVec(i)*x.AtVec(j))
+ }
+ }
}
// SymRankK performs a symmetric rank-k update to the matrix a and stores the

MODIFY
mat/symmetric_test.go
mat/symmetric_test.go
@@ -292,10 +292,10 @@ func TestSymRankOne(t *testing.T) {
alpha := 3.0
method := func(receiver, a, b Matrix) {
type SymRankOner interface {
- SymRankOne(a Symmetric, alpha float64, x *VecDense)
+ SymRankOne(a Symmetric, alpha float64, x Vector)
}
rd := receiver.(SymRankOner)
- rd.SymRankOne(a.(Symmetric), alpha, b.(*VecDense))
+ rd.SymRankOne(a.(Symmetric), alpha, b.(Vector))
}
denseComparison := func(receiver, a, b *Dense) {
var tmp Dense
@@ -308,7 +308,7 @@ func TestSymRankOne(t *testing.T) {
if !ok {
return false
}
- _, ok = b.(*VecDense)
+ _, ok = b.(Vector)
return ok
}
legalSize := func(ar, ac, br, bc int) bool {

mat: generalise SymDense SymRankOne vector parameters