1 // Copyright ©2013 The Gonum Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
8 "gonum.org/v1/gonum/blas"
9 "gonum.org/v1/gonum/blas/blas64"
10 "gonum.org/v1/gonum/internal/asm/f64"
21 // Vector is a vector.
22 type Vector interface {
28 // TransposeVec is a type for performing an implicit transpose of a Vector.
29 // It implements the Vector interface, returning values from the transpose
30 // of the vector within.
31 type TransposeVec struct {
35 // At returns the value of the element at row i and column j of the transposed
36 // matrix, that is, row j and column i of the Vector field.
37 func (t TransposeVec) At(i, j int) float64 {
38 return t.Vector.At(j, i)
41 // AtVec returns the element at position i. It panics if i is out of bounds.
42 func (t TransposeVec) AtVec(i int) float64 {
43 return t.Vector.AtVec(i)
46 // Dims returns the dimensions of the transposed vector.
47 func (t TransposeVec) Dims() (r, c int) {
48 c, r = t.Vector.Dims()
52 // T performs an implicit transpose by returning the Vector field.
53 func (t TransposeVec) T() Matrix {
57 // Len returns the number of columns in the vector.
58 func (t TransposeVec) Len() int {
62 // TVec performs an implicit transpose by returning the Vector field.
63 func (t TransposeVec) TVec() Vector {
67 // Untranspose returns the Vector field.
68 func (t TransposeVec) Untranspose() Matrix {
72 func (t TransposeVec) UntransposeVec() Vector {
76 // VecDense represents a column vector.
77 type VecDense struct {
80 // A BLAS vector can have a negative increment, but allowing this
81 // in the mat type complicates a lot of code, and doesn't gain anything.
82 // VecDense must have positive increment in this package.
85 // NewVecDense creates a new VecDense of length n. If data == nil,
86 // a new slice is allocated for the backing slice. If len(data) == n, data is
87 // used as the backing slice, and changes to the elements of the returned VecDense
88 // will be reflected in data. If neither of these is true, NewVecDense will panic.
89 func NewVecDense(n int, data []float64) *VecDense {
90 if len(data) != n && data != nil {
94 data = make([]float64, n)
105 // SliceVec returns a new Vector that shares backing data with the receiver.
106 // The returned matrix starts at i of the receiver and extends k-i elements.
107 // SliceVec panics with ErrIndexOutOfRange if the slice is outside the capacity
109 func (v *VecDense) SliceVec(i, k int) Vector {
110 if i < 0 || k <= i || v.Cap() < k {
111 panic(ErrIndexOutOfRange)
117 Data: v.mat.Data[i*v.mat.Inc : (k-1)*v.mat.Inc+1],
122 // Dims returns the number of rows and columns in the matrix. Columns is always 1
123 // for a non-Reset vector.
124 func (v *VecDense) Dims() (r, c int) {
131 // Caps returns the number of rows and columns in the backing matrix. Columns is always 1
132 // for a non-Reset vector.
133 func (v *VecDense) Caps() (r, c int) {
140 // Len returns the length of the vector.
141 func (v *VecDense) Len() int {
145 // Cap returns the capacity of the vector.
146 func (v *VecDense) Cap() int {
150 return (cap(v.mat.Data)-1)/v.mat.Inc + 1
153 // T performs an implicit transpose by returning the receiver inside a Transpose.
154 func (v *VecDense) T() Matrix {
158 // TVec performs an implicit transpose by returning the receiver inside a TransposeVec.
159 func (v *VecDense) TVec() Vector {
160 return TransposeVec{v}
163 // Reset zeros the length of the vector so that it can be reused as the
164 // receiver of a dimensionally restricted operation.
166 // See the Reseter interface for more information.
167 func (v *VecDense) Reset() {
168 // No change of Inc or n to 0 may be
169 // made unless both are set to 0.
172 v.mat.Data = v.mat.Data[:0]
175 // CloneVec makes a copy of a into the receiver, overwriting the previous value
177 func (v *VecDense) CloneVec(a Vector) {
182 v.mat = blas64.Vector{
184 Data: use(v.mat.Data, v.n),
186 if r, ok := a.(RawVectorer); ok {
187 blas64.Copy(v.n, r.RawVector(), v.mat)
190 for i := 0; i < a.Len(); i++ {
191 v.SetVec(i, a.AtVec(i))
195 // VecDenseCopyOf returns a newly allocated copy of the elements of a.
196 func VecDenseCopyOf(a Vector) *VecDense {
202 func (v *VecDense) RawVector() blas64.Vector {
206 // CopyVec makes a copy of elements of a into the receiver. It is similar to the
207 // built-in copy; it copies as much as the overlap between the two vectors and
208 // returns the number of elements it copied.
209 func (v *VecDense) CopyVec(a Vector) int {
210 n := min(v.Len(), a.Len())
214 if r, ok := a.(RawVectorer); ok {
215 blas64.Copy(n, r.RawVector(), v.mat)
218 for i := 0; i < n; i++ {
219 v.setVec(i, a.AtVec(i))
224 // ScaleVec scales the vector a by alpha, placing the result in the receiver.
225 func (v *VecDense) ScaleVec(alpha float64, a Vector) {
230 f64.ScalUnitary(alpha, v.mat.Data)
233 f64.ScalInc(alpha, v.mat.Data, uintptr(n), uintptr(v.mat.Inc))
239 if rv, ok := a.(RawVectorer); ok {
240 mat := rv.RawVector()
242 if v.mat.Inc == 1 && mat.Inc == 1 {
243 f64.ScalUnitaryTo(v.mat.Data, alpha, mat.Data)
246 f64.ScalIncTo(v.mat.Data, uintptr(v.mat.Inc),
247 alpha, mat.Data, uintptr(n), uintptr(mat.Inc))
251 for i := 0; i < n; i++ {
252 v.setVec(i, alpha*a.AtVec(i))
256 // AddScaledVec adds the vectors a and alpha*b, placing the result in the receiver.
257 func (v *VecDense) AddScaledVec(a Vector, alpha float64, b Vector) {
274 var amat, bmat blas64.Vector
276 aU, _ := untranspose(a)
277 if rv, ok := aU.(RawVectorer); ok {
278 amat = rv.RawVector()
285 bU, _ := untranspose(b)
286 if rv, ok := bU.(RawVectorer); ok {
287 bmat = rv.RawVector()
298 case alpha == 0: // v <- a
303 case v == a && v == b: // v <- v + alpha * v = (alpha + 1) * v
304 blas64.Scal(ar, alpha+1, v.mat)
305 case !fast: // v <- a + alpha * b without blas64 support.
306 for i := 0; i < ar; i++ {
307 v.setVec(i, a.AtVec(i)+alpha*b.AtVec(i))
309 case v == a && v != b: // v <- v + alpha * b
310 if v.mat.Inc == 1 && bmat.Inc == 1 {
311 // Fast path for a common case.
312 f64.AxpyUnitaryTo(v.mat.Data, alpha, bmat.Data, amat.Data)
314 f64.AxpyInc(alpha, bmat.Data, v.mat.Data,
315 uintptr(ar), uintptr(bmat.Inc), uintptr(v.mat.Inc), 0, 0)
317 default: // v <- a + alpha * b or v <- a + alpha * v
318 if v.mat.Inc == 1 && amat.Inc == 1 && bmat.Inc == 1 {
319 // Fast path for a common case.
320 f64.AxpyUnitaryTo(v.mat.Data, alpha, bmat.Data, amat.Data)
322 f64.AxpyIncTo(v.mat.Data, uintptr(v.mat.Inc), 0,
323 alpha, bmat.Data, amat.Data,
324 uintptr(ar), uintptr(bmat.Inc), uintptr(amat.Inc), 0, 0)
329 // AddVec adds the vectors a and b, placing the result in the receiver.
330 func (v *VecDense) AddVec(a, b Vector) {
340 aU, _ := untranspose(a)
341 bU, _ := untranspose(b)
343 if arv, ok := aU.(RawVectorer); ok {
344 if brv, ok := bU.(RawVectorer); ok {
345 amat := arv.RawVector()
346 bmat := brv.RawVector()
355 if v.mat.Inc == 1 && amat.Inc == 1 && bmat.Inc == 1 {
356 // Fast path for a common case.
357 f64.AxpyUnitaryTo(v.mat.Data, 1, bmat.Data, amat.Data)
360 f64.AxpyIncTo(v.mat.Data, uintptr(v.mat.Inc), 0,
361 1, bmat.Data, amat.Data,
362 uintptr(ar), uintptr(bmat.Inc), uintptr(amat.Inc), 0, 0)
367 for i := 0; i < ar; i++ {
368 v.setVec(i, a.AtVec(i)+b.AtVec(i))
372 // SubVec subtracts the vector b from a, placing the result in the receiver.
373 func (v *VecDense) SubVec(a, b Vector) {
383 aU, _ := untranspose(a)
384 bU, _ := untranspose(b)
386 if arv, ok := aU.(RawVectorer); ok {
387 if brv, ok := bU.(RawVectorer); ok {
388 amat := arv.RawVector()
389 bmat := brv.RawVector()
398 if v.mat.Inc == 1 && amat.Inc == 1 && bmat.Inc == 1 {
399 // Fast path for a common case.
400 f64.AxpyUnitaryTo(v.mat.Data, -1, bmat.Data, amat.Data)
403 f64.AxpyIncTo(v.mat.Data, uintptr(v.mat.Inc), 0,
404 -1, bmat.Data, amat.Data,
405 uintptr(ar), uintptr(bmat.Inc), uintptr(amat.Inc), 0, 0)
410 for i := 0; i < ar; i++ {
411 v.setVec(i, a.AtVec(i)-b.AtVec(i))
415 // MulElemVec performs element-wise multiplication of a and b, placing the result
417 func (v *VecDense) MulElemVec(a, b Vector) {
427 aU, _ := untranspose(a)
428 bU, _ := untranspose(b)
430 if arv, ok := aU.(RawVectorer); ok {
431 if brv, ok := bU.(RawVectorer); ok {
432 amat := arv.RawVector()
433 bmat := brv.RawVector()
442 if v.mat.Inc == 1 && amat.Inc == 1 && bmat.Inc == 1 {
443 // Fast path for a common case.
444 for i, a := range amat.Data {
445 v.mat.Data[i] = a * bmat.Data[i]
450 for i := 0; i < ar; i++ {
451 v.setVec(i, amat.Data[ia]*bmat.Data[ib])
459 for i := 0; i < ar; i++ {
460 v.setVec(i, a.AtVec(i)*b.AtVec(i))
464 // DivElemVec performs element-wise division of a by b, placing the result
466 func (v *VecDense) DivElemVec(a, b Vector) {
476 aU, _ := untranspose(a)
477 bU, _ := untranspose(b)
479 if arv, ok := aU.(RawVectorer); ok {
480 if brv, ok := bU.(RawVectorer); ok {
481 amat := arv.RawVector()
482 bmat := brv.RawVector()
491 if v.mat.Inc == 1 && amat.Inc == 1 && bmat.Inc == 1 {
492 // Fast path for a common case.
493 for i, a := range amat.Data {
494 v.setVec(i, a/bmat.Data[i])
499 for i := 0; i < ar; i++ {
500 v.setVec(i, amat.Data[ia]/bmat.Data[ib])
507 for i := 0; i < ar; i++ {
508 v.setVec(i, a.AtVec(i)/b.AtVec(i))
512 // MulVec computes a * b. The result is stored into the receiver.
513 // MulVec panics if the number of columns in a does not equal the number of rows in b
514 // or if the number of columns in b does not equal 1.
515 func (v *VecDense) MulVec(a Matrix, b Vector) {
518 if c != br || bc != 1 {
522 aU, trans := untranspose(a)
523 var bmat blas64.Vector
525 bU, _ := untranspose(b)
526 if rv, ok := bU.(RawVectorer); ok {
527 bmat = rv.RawVector()
538 v, restore = v.isolatedWorkspace(aU.(*VecDense))
541 v, restore = v.isolatedWorkspace(b)
545 // TODO(kortschak): Improve the non-fast paths.
546 switch aU := aU.(type) {
550 v.ScaleVec(b.AtVec(0), aU)
556 if rv, ok := aU.(RawVectorer); ok {
557 amat := rv.RawVector()
562 if amat.Inc == 1 && bmat.Inc == 1 {
563 // Fast path for a common case.
564 v.setVec(0, f64.DotUnitary(amat.Data, bmat.Data))
567 v.setVec(0, f64.DotInc(amat.Data, bmat.Data,
568 uintptr(c), uintptr(amat.Inc), uintptr(bmat.Inc), 0, 0))
573 for i := 0; i < c; i++ {
574 sum += aU.AtVec(i) * b.AtVec(i)
580 amat := aU.RawSymmetric()
581 // We don't know that a is a *SymDense, so make
582 // a temporary SymDense to check overlap.
583 (&SymDense{mat: amat}).checkOverlap(v.asGeneral())
584 blas64.Symv(1, amat, bmat, 0, v.mat)
589 amat := aU.RawTriangular()
590 // We don't know that a is a *TriDense, so make
591 // a temporary TriDense to check overlap.
592 (&TriDense{mat: amat}).checkOverlap(v.asGeneral())
597 blas64.Trmv(ta, amat, v.mat)
600 amat := aU.RawMatrix()
601 // We don't know that a is a *Dense, so make
602 // a temporary Dense to check overlap.
603 (&Dense{mat: amat}).checkOverlap(v.asGeneral())
608 blas64.Gemv(t, 1, amat, bmat, 0, v.mat)
613 for i := 0; i < r; i++ {
615 for j := 0; j < c; j++ {
616 f += a.At(i, j) * bmat.Data[j*bmat.Inc]
624 for i := 0; i < r; i++ {
626 for j := 0; j < c; j++ {
627 f += a.At(i, j) * b.AtVec(j)
633 // reuseAs resizes an empty vector to a r×1 vector,
634 // or checks that a non-empty matrix is r×1.
635 func (v *VecDense) reuseAs(r int) {
637 v.mat = blas64.Vector{
639 Data: use(v.mat.Data, r),
649 // IsZero returns whether the receiver is zero-sized. Zero-sized vectors can be the
650 // receiver for size-restricted operations. VecDenses can be zeroed using Reset.
651 func (v *VecDense) IsZero() bool {
652 // It must be the case that v.Dims() returns
653 // zeros in this case. See comment in Reset().
654 return v.mat.Inc == 0
657 func (v *VecDense) isolatedWorkspace(a Vector) (n *VecDense, restore func()) {
659 n = getWorkspaceVec(l, false)
666 // asDense returns a Dense representation of the receiver with the same
668 func (v *VecDense) asDense() *Dense {
676 // asGeneral returns a blas64.General representation of the receiver with the
677 // same underlying data.
678 func (v *VecDense) asGeneral() blas64.General {
679 return blas64.General{
687 // ColViewOf reflects the column j of the RawMatrixer m, into the receiver
688 // backed by the same underlying data. The length of the receiver must either be
689 // zero or match the number of rows in m.
690 func (v *VecDense) ColViewOf(m RawMatrixer, j int) {
693 if j >= rm.Cols || j < 0 {
696 if !v.IsZero() && v.n != rm.Rows {
700 v.mat.Inc = rm.Stride
701 v.mat.Data = rm.Data[j : (rm.Rows-1)*rm.Stride+j+1]
705 // RowViewOf reflects the row i of the RawMatrixer m, into the receiver
706 // backed by the same underlying data. The length of the receiver must either be
707 // zero or match the number of columns in m.
708 func (v *VecDense) RowViewOf(m RawMatrixer, i int) {
711 if i >= rm.Rows || i < 0 {
714 if !v.IsZero() && v.n != rm.Cols {
719 v.mat.Data = rm.Data[i*rm.Stride : i*rm.Stride+rm.Cols]