func Dot(a, b Vector) float64 {
	la := a.Len()
	lb := b.Len()
	if la != lb {
		panic(ErrShape)
	}
	if arv, ok := a.(RawVectorer); ok {
		if brv, ok := b.(RawVectorer); ok {
			return blas64.Dot(arv.RawVector(), brv.RawVector())
		}
	}
	var sum float64
	for i := 0; i < la; i++ {
		sum += a.At(i, 0) * b.At(i, 0)
	}
	return sum
}
Dot returns the sum of the element-wise product of a and b.
Dot panics if the matrix sizes are unequal.
package mat
import (
	"math"
	"gonum.org/v1/gonum/blas"
	"gonum.org/v1/gonum/blas/blas64"
	"gonum.org/v1/gonum/floats"
	"gonum.org/v1/gonum/lapack"
	"gonum.org/v1/gonum/lapack/lapack64"
)
type Matrix interface {
	Dims() (r, c int)
	At(i, j int) float64
	T() Matrix
}
var (
	_ Matrix       = Transpose{}
	_ Untransposer = Transpose{}
)
type Transpose struct {
	Matrix Matrix
}
func (t Transpose) At(i, j int) float64 {
	return t.Matrix.At(j, i)
}
func (t Transpose) Dims() (r, c int) {
	c, r = t.Matrix.Dims()
	return r, c
}
func (t Transpose) T() Matrix {
	return t.Matrix
}
func (t Transpose) Untranspose() Matrix {
	return t.Matrix
}
type Untransposer interface {
	Untranspose() Matrix
}
type UntransposeBander interface {
	UntransposeBand() Banded
}
type UntransposeTrier interface {
	UntransposeTri() Triangular
}
type UntransposeTriBander interface {
	UntransposeTriBand() TriBanded
}
type Mutable interface {
	Set(i, j int, v float64)
	Matrix
}
type RowViewer interface {
	RowView(i int) Vector
}
type RawRowViewer interface {
	RawRowView(i int) []float64
}
type ColViewer interface {
	ColView(j int) Vector
}
type RawColViewer interface {
	RawColView(j int) []float64
}
type Cloner interface {
	Clone(a Matrix)
}
type Reseter interface {
	Reset()
}
type Copier interface {
	Copy(a Matrix) (r, c int)
}
type Grower interface {
	Caps() (r, c int)
	Grow(r, c int) Matrix
}
type BandWidther interface {
	BandWidth() (k1, k2 int)
}
type RawMatrixSetter interface {
	SetRawMatrix(a blas64.General)
}
type RawMatrixer interface {
	RawMatrix() blas64.General
}
type RawVectorer interface {
	RawVector() blas64.Vector
}
type NonZeroDoer interface {
	DoNonZero(func(i, j int, v float64))
}
type RowNonZeroDoer interface {
	DoRowNonZero(i int, fn func(i, j int, v float64))
}
type ColNonZeroDoer interface {
	DoColNonZero(j int, fn func(i, j int, v float64))
}
func untranspose(a Matrix) (Matrix, bool) {
	if ut, ok := a.(Untransposer); ok {
		return ut.Untranspose(), true
	}
	return a, false
}
func untransposeExtract(a Matrix) (Matrix, bool) {
	ut, trans := untranspose(a)
	switch m := ut.(type) {
	case *DiagDense, *SymBandDense, *TriBandDense, *BandDense, *TriDense, *SymDense, *Dense:
		return m, trans
	case RawSymBander:
		rsb := m.RawSymBand()
		if rsb.Uplo != blas.Upper {
			return ut, trans
		}
		var sb SymBandDense
		sb.SetRawSymBand(rsb)
		return &sb, trans
	case RawTriBander:
		rtb := m.RawTriBand()
		if rtb.Diag == blas.Unit {
			return ut, trans
		}
		var tb TriBandDense
		tb.SetRawTriBand(rtb)
		return &tb, trans
	case RawBander:
		var b BandDense
		b.SetRawBand(m.RawBand())
		return &b, trans
	case RawTriangular:
		rt := m.RawTriangular()
		if rt.Diag == blas.Unit {
			return ut, trans
		}
		var t TriDense
		t.SetRawTriangular(rt)
		return &t, trans
	case RawSymmetricer:
		rs := m.RawSymmetric()
		if rs.Uplo != blas.Upper {
			return ut, trans
		}
		var s SymDense
		s.SetRawSymmetric(rs)
		return &s, trans
	case RawMatrixer:
		var d Dense
		d.SetRawMatrix(m.RawMatrix())
		return &d, trans
	default:
		return ut, trans
	}
}
func Col(dst []float64, j int, a Matrix) []float64 {
	r, c := a.Dims()
	if j < 0 || j >= c {
		panic(ErrColAccess)
	}
	if dst == nil {
		dst = make([]float64, r)
	} else {
		if len(dst) != r {
			panic(ErrColLength)
		}
	}
	aU, aTrans := untranspose(a)
	if rm, ok := aU.(RawMatrixer); ok {
		m := rm.RawMatrix()
		if aTrans {
			copy(dst, m.Data[j*m.Stride:j*m.Stride+m.Cols])
			return dst
		}
		blas64.Copy(blas64.Vector{N: r, Inc: m.Stride, Data: m.Data[j:]},
			blas64.Vector{N: r, Inc: 1, Data: dst},
		)
		return dst
	}
	for i := 0; i < r; i++ {
		dst[i] = a.At(i, j)
	}
	return dst
}
func Row(dst []float64, i int, a Matrix) []float64 {
	r, c := a.Dims()
	if i < 0 || i >= r {
		panic(ErrColAccess)
	}
	if dst == nil {
		dst = make([]float64, c)
	} else {
		if len(dst) != c {
			panic(ErrRowLength)
		}
	}
	aU, aTrans := untranspose(a)
	if rm, ok := aU.(RawMatrixer); ok {
		m := rm.RawMatrix()
		if aTrans {
			blas64.Copy(blas64.Vector{N: c, Inc: m.Stride, Data: m.Data[i:]},
				blas64.Vector{N: c, Inc: 1, Data: dst},
			)
			return dst
		}
		copy(dst, m.Data[i*m.Stride:i*m.Stride+m.Cols])
		return dst
	}
	for j := 0; j < c; j++ {
		dst[j] = a.At(i, j)
	}
	return dst
}
func Cond(a Matrix, norm float64) float64 {
	m, n := a.Dims()
	if m == 0 || n == 0 {
		panic(ErrShape)
	}
	var lnorm lapack.MatrixNorm
	switch norm {
	default:
		panic("mat: bad norm value")
	case 1:
		lnorm = lapack.MaxColumnSum
	case 2:
		var svd SVD
		ok := svd.Factorize(a, SVDNone)
		if !ok {
			return math.Inf(1)
		}
		return svd.Cond()
	case math.Inf(1):
		lnorm = lapack.MaxRowSum
	}
	if m == n {
		var lu LU
		lu.factorize(a, lnorm)
		return lu.Cond()
	}
	if m > n {
		var qr QR
		qr.factorize(a, lnorm)
		return qr.Cond()
	}
	var lq LQ
	lq.factorize(a, lnorm)
	return lq.Cond()
}
func Det(a Matrix) float64 {
	det, sign := LogDet(a)
	return math.Exp(det) * sign
}