kompose/vendor/github.com/gonum/matrix/mat64/dense.go
Tomas Kral 1f8a0e06c9
Upgrade OpenShift and its dependencies.
OpenShift version 1.4.0-alpha.0
2016-10-18 12:04:00 +02:00

647 lines
15 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright ©2013 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mat64
import (
"bytes"
"encoding/binary"
"github.com/gonum/blas/blas64"
)
var (
matrix *Dense
_ Matrix = matrix
_ Mutable = matrix
_ Vectorer = matrix
_ VectorSetter = matrix
_ Cloner = matrix
_ Viewer = matrix
_ RowViewer = matrix
_ ColViewer = matrix
_ RawRowViewer = matrix
_ Grower = matrix
_ Adder = matrix
_ Suber = matrix
_ Muler = matrix
_ Dotter = matrix
_ ElemMuler = matrix
_ ElemDiver = matrix
_ Exper = matrix
_ Scaler = matrix
_ Applyer = matrix
_ TransposeCopier = matrix
// _ TransposeViewer = matrix
_ Tracer = matrix
_ Normer = matrix
_ Sumer = matrix
_ Uer = matrix
_ Ler = matrix
_ Stacker = matrix
_ Augmenter = matrix
_ Equaler = matrix
_ ApproxEqualer = matrix
_ RawMatrixSetter = matrix
_ RawMatrixer = matrix
_ Reseter = matrix
)
// Dense is a dense matrix representation.
type Dense struct {
mat blas64.General
capRows, capCols int
}
// NewDense creates a new matrix of type Dense with dimensions r and c.
// If the mat argument is nil, a new data slice is allocated.
//
// The data must be arranged in row-major order, i.e. the (i*c + j)-th
// element in mat is the {i, j}-th element in the matrix.
func NewDense(r, c int, mat []float64) *Dense {
if mat != nil && r*c != len(mat) {
panic(ErrShape)
}
if mat == nil {
mat = make([]float64, r*c)
}
return &Dense{
mat: blas64.General{
Rows: r,
Cols: c,
Stride: c,
Data: mat,
},
capRows: r,
capCols: c,
}
}
// reuseAs resizes an empty matrix to a r×c matrix,
// or checks that a non-empty matrix is r×c.
func (m *Dense) reuseAs(r, c int) {
if m.mat.Rows > m.capRows || m.mat.Cols > m.capCols {
// Panic as a string, not a mat64.Error.
panic("mat64: caps not correctly set")
}
if m.isZero() {
m.mat = blas64.General{
Rows: r,
Cols: c,
Stride: c,
Data: use(m.mat.Data, r*c),
}
m.capRows = r
m.capCols = c
return
}
if r != m.mat.Rows || c != m.mat.Cols {
panic(ErrShape)
}
}
func (m *Dense) isZero() bool {
// It must be the case that m.Dims() returns
// zeros in this case. See comment in Reset().
return m.mat.Stride == 0
}
// DenseCopyOf returns a newly allocated copy of the elements of a.
func DenseCopyOf(a Matrix) *Dense {
d := &Dense{}
d.Clone(a)
return d
}
// SetRawMatrix sets the underlying blas64.General used by the receiver.
// Changes to elements in the receiver following the call will be reflected
// in b.
func (m *Dense) SetRawMatrix(b blas64.General) {
m.capRows, m.capCols = b.Rows, b.Cols
m.mat = b
}
// RawMatrix returns the underlying blas64.General used by the receiver.
// Changes to elements in the receiver following the call will be reflected
// in returned blas64.General.
func (m *Dense) RawMatrix() blas64.General { return m.mat }
// Dims returns the number of rows and columns in the matrix.
func (m *Dense) Dims() (r, c int) { return m.mat.Rows, m.mat.Cols }
// Caps returns the number of rows and columns in the backing matrix.
func (m *Dense) Caps() (r, c int) { return m.capRows, m.capCols }
// Col copies the elements in the jth column of the matrix into the slice dst.
// If the provided slice is nil, a new slice is first allocated.
//
// See the Vectorer interface for more information.
func (m *Dense) Col(dst []float64, j int) []float64 {
if j >= m.mat.Cols || j < 0 {
panic(ErrColAccess)
}
if dst == nil {
dst = make([]float64, m.mat.Rows)
}
dst = dst[:min(len(dst), m.mat.Rows)]
blas64.Copy(len(dst),
blas64.Vector{Inc: m.mat.Stride, Data: m.mat.Data[j:]},
blas64.Vector{Inc: 1, Data: dst},
)
return dst
}
// ColView returns a Vector reflecting col j, backed by the matrix data.
//
// See ColViewer for more information.
func (m *Dense) ColView(j int) *Vector {
if j >= m.mat.Cols || j < 0 {
panic(ErrColAccess)
}
return &Vector{
mat: blas64.Vector{
Inc: m.mat.Stride,
Data: m.mat.Data[j : (m.mat.Rows-1)*m.mat.Stride+j+1],
},
n: m.mat.Rows,
}
}
// SetCol sets the elements of the matrix in the specified column to the values
// of src.
//
// See the VectorSetter interface for more information.
func (m *Dense) SetCol(j int, src []float64) int {
if j >= m.mat.Cols || j < 0 {
panic(ErrColAccess)
}
blas64.Copy(min(len(src), m.mat.Rows),
blas64.Vector{Inc: 1, Data: src},
blas64.Vector{Inc: m.mat.Stride, Data: m.mat.Data[j:]},
)
return min(len(src), m.mat.Rows)
}
// Row copies the elements in the ith row of the matrix into the slice dst.
// If the provided slice is nil, a new slice is first allocated.
//
// See the Vectorer interface for more information.
func (m *Dense) Row(dst []float64, i int) []float64 {
if i >= m.mat.Rows || i < 0 {
panic(ErrRowAccess)
}
if dst == nil {
dst = make([]float64, m.mat.Cols)
}
copy(dst, m.rowView(i))
return dst
}
// SetRow sets the elements of the matrix in the specified row to the values of
// src.
//
// See the VectorSetter interface for more information.
func (m *Dense) SetRow(i int, src []float64) int {
if i >= m.mat.Rows || i < 0 {
panic(ErrRowAccess)
}
copy(m.rowView(i), src)
return min(len(src), m.mat.Cols)
}
// RowView returns a Vector reflecting row i, backed by the matrix data.
//
// See RowViewer for more information.
func (m *Dense) RowView(i int) *Vector {
if i >= m.mat.Rows || i < 0 {
panic(ErrRowAccess)
}
return &Vector{
mat: blas64.Vector{
Inc: 1,
Data: m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+m.mat.Cols],
},
n: m.mat.Cols,
}
}
// RawRowView returns a slice backed by the same array as backing the
// receiver.
func (m *Dense) RawRowView(i int) []float64 {
if i >= m.mat.Rows || i < 0 {
panic(ErrRowAccess)
}
return m.rowView(i)
}
func (m *Dense) rowView(r int) []float64 {
return m.mat.Data[r*m.mat.Stride : r*m.mat.Stride+m.mat.Cols]
}
// View returns a new Matrix that shares backing data with the receiver.
// The new matrix is located from row i, column j extending r rows and c
// columns.
func (m *Dense) View(i, j, r, c int) Matrix {
mr, mc := m.Dims()
if i < 0 || i >= mr || j < 0 || j >= mc || r <= 0 || i+r > mr || c <= 0 || j+c > mc {
panic(ErrIndexOutOfRange)
}
t := *m
t.mat.Data = t.mat.Data[i*t.mat.Stride+j : (i+r-1)*t.mat.Stride+(j+c)]
t.mat.Rows = r
t.mat.Cols = c
t.capRows -= i
t.capCols -= j
return &t
}
// Grow returns an expanded copy of the receiver. The copy is expanded
// by r rows and c columns. If the dimensions of the new copy are outside
// the caps of the receiver a new allocation is made, otherwise not.
func (m *Dense) Grow(r, c int) Matrix {
if r < 0 || c < 0 {
panic(ErrIndexOutOfRange)
}
if r == 0 && c == 0 {
return m
}
r += m.mat.Rows
c += m.mat.Cols
var t Dense
switch {
case m.mat.Rows == 0 || m.mat.Cols == 0:
t.mat = blas64.General{
Rows: r,
Cols: c,
Stride: c,
// We zero because we don't know how the matrix will be used.
// In other places, the mat is immediately filled with a result;
// this is not the case here.
Data: useZeroed(m.mat.Data, r*c),
}
case r > m.capRows || c > m.capCols:
cr := max(r, m.capRows)
cc := max(c, m.capCols)
t.mat = blas64.General{
Rows: r,
Cols: c,
Stride: cc,
Data: make([]float64, cr*cc),
}
t.capRows = cr
t.capCols = cc
// Copy the complete matrix over to the new matrix.
// Including elements not currently visible.
r, c, m.mat.Rows, m.mat.Cols = m.mat.Rows, m.mat.Cols, m.capRows, m.capCols
t.Copy(m)
m.mat.Rows, m.mat.Cols = r, c
return &t
default:
t.mat = blas64.General{
Data: m.mat.Data[:(r-1)*m.mat.Stride+c],
Rows: r,
Cols: c,
Stride: m.mat.Stride,
}
}
t.capRows = r
t.capCols = c
return &t
}
// Reset zeros the dimensions of the matrix so that it can be reused as the
// receiver of a dimensionally restricted operation.
//
// See the Reseter interface for more information.
func (m *Dense) Reset() {
// No change of Stride, Rows and Cols to 0
// may be made unless all are set to 0.
m.mat.Rows, m.mat.Cols, m.mat.Stride = 0, 0, 0
m.capRows, m.capCols = 0, 0
m.mat.Data = m.mat.Data[:0]
}
// Clone makes a copy of a into the receiver, overwriting the previous value of
// the receiver. The clone operation does not make any restriction on shape.
//
// See the Cloner interface for more information.
func (m *Dense) Clone(a Matrix) {
r, c := a.Dims()
mat := blas64.General{
Rows: r,
Cols: c,
Stride: c,
}
m.capRows, m.capCols = r, c
switch a := a.(type) {
case RawMatrixer:
amat := a.RawMatrix()
mat.Data = make([]float64, r*c)
for i := 0; i < r; i++ {
copy(mat.Data[i*c:(i+1)*c], amat.Data[i*amat.Stride:i*amat.Stride+c])
}
case Vectorer:
mat.Data = use(m.mat.Data, r*c)
for i := 0; i < r; i++ {
a.Row(mat.Data[i*c:(i+1)*c], i)
}
default:
mat.Data = use(m.mat.Data, r*c)
m.mat = mat
for i := 0; i < r; i++ {
for j := 0; j < c; j++ {
m.set(i, j, a.At(i, j))
}
}
return
}
m.mat = mat
}
// Copy makes a copy of elements of a into the receiver. It is similar to the
// built-in copy; it copies as much as the overlap between the two matrices and
// returns the number of rows and columns it copied.
//
// See the Copier interface for more information.
func (m *Dense) Copy(a Matrix) (r, c int) {
r, c = a.Dims()
r = min(r, m.mat.Rows)
c = min(c, m.mat.Cols)
switch a := a.(type) {
case RawMatrixer:
amat := a.RawMatrix()
for i := 0; i < r; i++ {
copy(m.mat.Data[i*m.mat.Stride:i*m.mat.Stride+c], amat.Data[i*amat.Stride:i*amat.Stride+c])
}
case Vectorer:
for i := 0; i < r; i++ {
a.Row(m.mat.Data[i*m.mat.Stride:i*m.mat.Stride+c], i)
}
default:
for i := 0; i < r; i++ {
for j := 0; j < c; j++ {
m.set(r, c, a.At(r, c))
}
}
}
return r, c
}
// U places the upper triangular matrix of a in the receiver.
//
// See the Uer interface for more information.
func (m *Dense) U(a Matrix) {
ar, ac := a.Dims()
if ar != ac {
panic(ErrSquare)
}
if m == a {
m.zeroLower()
return
}
m.reuseAs(ar, ac)
if a, ok := a.(RawMatrixer); ok {
amat := a.RawMatrix()
copy(m.mat.Data[:ac], amat.Data[:ac])
for j, ja, jm := 1, amat.Stride, m.mat.Stride; ja < ar*amat.Stride; j, ja, jm = j+1, ja+amat.Stride, jm+m.mat.Stride {
zero(m.mat.Data[jm : jm+j])
copy(m.mat.Data[jm+j:jm+ac], amat.Data[ja+j:ja+ac])
}
return
}
if a, ok := a.(Vectorer); ok {
row := make([]float64, ac)
copy(m.mat.Data[:m.mat.Cols], a.Row(row, 0))
for r := 1; r < ar; r++ {
zero(m.mat.Data[r*m.mat.Stride : r*(m.mat.Stride+1)])
copy(m.mat.Data[r*(m.mat.Stride+1):r*m.mat.Stride+m.mat.Cols], a.Row(row, r))
}
return
}
m.zeroLower()
for r := 0; r < ar; r++ {
for c := r; c < ac; c++ {
m.set(r, c, a.At(r, c))
}
}
}
func (m *Dense) zeroLower() {
for i := 1; i < m.mat.Rows; i++ {
zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+i])
}
}
// L places the lower triangular matrix of a in the receiver.
//
// See the Ler interface for more information.
func (m *Dense) L(a Matrix) {
ar, ac := a.Dims()
if ar != ac {
panic(ErrSquare)
}
if m == a {
m.zeroUpper()
return
}
m.reuseAs(ar, ac)
if a, ok := a.(RawMatrixer); ok {
amat := a.RawMatrix()
copy(m.mat.Data[:ar], amat.Data[:ar])
for j, ja, jm := 1, amat.Stride, m.mat.Stride; ja < ac*amat.Stride; j, ja, jm = j+1, ja+amat.Stride, jm+m.mat.Stride {
zero(m.mat.Data[jm : jm+j])
copy(m.mat.Data[jm+j:jm+ar], amat.Data[ja+j:ja+ar])
}
return
}
if a, ok := a.(Vectorer); ok {
row := make([]float64, ac)
for r := 0; r < ar; r++ {
a.Row(row[:r+1], r)
m.SetRow(r, row)
}
return
}
m.zeroUpper()
for c := 0; c < ac; c++ {
for r := c; r < ar; r++ {
m.set(r, c, a.At(r, c))
}
}
}
func (m *Dense) zeroUpper() {
for i := 0; i < m.mat.Rows-1; i++ {
zero(m.mat.Data[i*m.mat.Stride+i+1 : (i+1)*m.mat.Stride])
}
}
// TCopy makes a copy of the transpose the matrix represented by a, placing the
// result into the receiver.
//
// See the TransposeCopier interface for more information.
func (m *Dense) TCopy(a Matrix) {
ar, ac := a.Dims()
var w Dense
if m != a {
w = *m
}
w.reuseAs(ac, ar)
switch a := a.(type) {
case *Dense:
for i := 0; i < ac; i++ {
for j := 0; j < ar; j++ {
w.set(i, j, a.at(j, i))
}
}
default:
for i := 0; i < ac; i++ {
for j := 0; j < ar; j++ {
w.set(i, j, a.At(j, i))
}
}
}
*m = w
}
// Stack appends the rows of b onto the rows of a, placing the result into the
// receiver.
//
// See the Stacker interface for more information.
func (m *Dense) Stack(a, b Matrix) {
ar, ac := a.Dims()
br, bc := b.Dims()
if ac != bc || m == a || m == b {
panic(ErrShape)
}
m.reuseAs(ar+br, ac)
m.Copy(a)
w := m.View(ar, 0, br, bc).(*Dense)
w.Copy(b)
}
// Augment creates the augmented matrix of a and b, where b is placed in the
// greater indexed columns.
//
// See the Augmenter interface for more information.
func (m *Dense) Augment(a, b Matrix) {
ar, ac := a.Dims()
br, bc := b.Dims()
if ar != br || m == a || m == b {
panic(ErrShape)
}
m.reuseAs(ar, ac+bc)
m.Copy(a)
w := m.View(0, ac, br, bc).(*Dense)
w.Copy(b)
}
// MarshalBinary encodes the receiver into a binary form and returns the result.
//
// Dense is little-endian encoded as follows:
// 0 - 8 number of rows (int64)
// 8 - 16 number of columns (int64)
// 16 - .. matrix data elements (float64)
// [0,0] [0,1] ... [0,ncols-1]
// [1,0] [1,1] ... [1,ncols-1]
// ...
// [nrows-1,0] ... [nrows-1,ncols-1]
func (m Dense) MarshalBinary() ([]byte, error) {
buf := bytes.NewBuffer(make([]byte, 0, m.mat.Rows*m.mat.Cols*sizeFloat64+2*sizeInt64))
err := binary.Write(buf, defaultEndian, int64(m.mat.Rows))
if err != nil {
return nil, err
}
err = binary.Write(buf, defaultEndian, int64(m.mat.Cols))
if err != nil {
return nil, err
}
for i := 0; i < m.mat.Rows; i++ {
for _, v := range m.rowView(i) {
err = binary.Write(buf, defaultEndian, v)
if err != nil {
return nil, err
}
}
}
return buf.Bytes(), err
}
// UnmarshalBinary decodes the binary form into the receiver.
// It panics if the receiver is a non-zero Dense matrix.
//
// See MarshalBinary for the on-disk layout.
func (m *Dense) UnmarshalBinary(data []byte) error {
if !m.isZero() {
panic("mat64: unmarshal into non-zero matrix")
}
buf := bytes.NewReader(data)
var rows int64
err := binary.Read(buf, defaultEndian, &rows)
if err != nil {
return err
}
var cols int64
err = binary.Read(buf, defaultEndian, &cols)
if err != nil {
return err
}
m.mat.Rows = int(rows)
m.mat.Cols = int(cols)
m.mat.Stride = int(cols)
m.capRows = int(rows)
m.capCols = int(cols)
m.mat.Data = use(m.mat.Data, m.mat.Rows*m.mat.Cols)
for i := range m.mat.Data {
err = binary.Read(buf, defaultEndian, &m.mat.Data[i])
if err != nil {
return err
}
}
return err
}