// Copyright ©2015 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 mat import "gonum.org/v1/gonum/blas/blas64" // checkOverlap returns false if the receiver does not overlap data elements // referenced by the parameter and panics otherwise. // // checkOverlap methods return a boolean to allow the check call to be added to a // boolean expression, making use of short-circuit operators. func checkOverlap(a, b blas64.General) bool { if cap(a.Data) == 0 || cap(b.Data) == 0 { return false } off := offset(a.Data[:1], b.Data[:1]) if off == 0 { // At least one element overlaps. if a.Cols == b.Cols && a.Rows == b.Rows && a.Stride == b.Stride { panic(regionIdentity) } panic(regionOverlap) } if off > 0 && len(a.Data) <= off { // We know a is completely before b. return false } if off < 0 && len(b.Data) <= -off { // We know a is completely after b. return false } if a.Stride != b.Stride && a.Stride != 1 && b.Stride != 1 { // Too hard, so assume the worst; if either stride // is one it will be caught in rectanglesOverlap. panic(mismatchedStrides) } if off < 0 { off = -off a.Cols, b.Cols = b.Cols, a.Cols } if rectanglesOverlap(off, a.Cols, b.Cols, min(a.Stride, b.Stride)) { panic(regionOverlap) } return false } func (m *Dense) checkOverlap(a blas64.General) bool { return checkOverlap(m.RawMatrix(), a) } func (m *Dense) checkOverlapMatrix(a Matrix) bool { if m == a { return false } var amat blas64.General switch ar := a.(type) { default: return false case RawMatrixer: amat = ar.RawMatrix() case RawSymmetricer: amat = generalFromSymmetric(ar.RawSymmetric()) case RawSymBander: amat = generalFromSymmetricBand(ar.RawSymBand()) case RawTriangular: amat = generalFromTriangular(ar.RawTriangular()) case RawVectorer: r, c := a.Dims() amat = generalFromVector(ar.RawVector(), r, c) } return m.checkOverlap(amat) } func (s *SymDense) checkOverlap(a blas64.General) bool { return checkOverlap(generalFromSymmetric(s.RawSymmetric()), a) } func (s *SymDense) checkOverlapMatrix(a Matrix) bool { if s == a { return false } var amat blas64.General switch ar := a.(type) { default: return false case RawMatrixer: amat = ar.RawMatrix() case RawSymmetricer: amat = generalFromSymmetric(ar.RawSymmetric()) case RawSymBander: amat = generalFromSymmetricBand(ar.RawSymBand()) case RawTriangular: amat = generalFromTriangular(ar.RawTriangular()) case RawVectorer: r, c := a.Dims() amat = generalFromVector(ar.RawVector(), r, c) } return s.checkOverlap(amat) } // generalFromSymmetric returns a blas64.General with the backing // data and dimensions of a. func generalFromSymmetric(a blas64.Symmetric) blas64.General { return blas64.General{ Rows: a.N, Cols: a.N, Stride: a.Stride, Data: a.Data, } } func (t *TriDense) checkOverlap(a blas64.General) bool { return checkOverlap(generalFromTriangular(t.RawTriangular()), a) } func (t *TriDense) checkOverlapMatrix(a Matrix) bool { if t == a { return false } var amat blas64.General switch ar := a.(type) { default: return false case RawMatrixer: amat = ar.RawMatrix() case RawSymmetricer: amat = generalFromSymmetric(ar.RawSymmetric()) case RawSymBander: amat = generalFromSymmetricBand(ar.RawSymBand()) case RawTriangular: amat = generalFromTriangular(ar.RawTriangular()) case RawVectorer: r, c := a.Dims() amat = generalFromVector(ar.RawVector(), r, c) } return t.checkOverlap(amat) } // generalFromTriangular returns a blas64.General with the backing // data and dimensions of a. func generalFromTriangular(a blas64.Triangular) blas64.General { return blas64.General{ Rows: a.N, Cols: a.N, Stride: a.Stride, Data: a.Data, } } func (v *VecDense) checkOverlap(a blas64.Vector) bool { mat := v.mat if cap(mat.Data) == 0 || cap(a.Data) == 0 { return false } off := offset(mat.Data[:1], a.Data[:1]) if off == 0 { // At least one element overlaps. if mat.Inc == a.Inc && len(mat.Data) == len(a.Data) { panic(regionIdentity) } panic(regionOverlap) } if off > 0 && len(mat.Data) <= off { // We know v is completely before a. return false } if off < 0 && len(a.Data) <= -off { // We know v is completely after a. return false } if mat.Inc != a.Inc && mat.Inc != 1 && a.Inc != 1 { // Too hard, so assume the worst; if either // increment is one it will be caught below. panic(mismatchedStrides) } inc := min(mat.Inc, a.Inc) if inc == 1 || off&inc == 0 { panic(regionOverlap) } return false } // generalFromVector returns a blas64.General with the backing // data and dimensions of a. func generalFromVector(a blas64.Vector, r, c int) blas64.General { return blas64.General{ Rows: r, Cols: c, Stride: a.Inc, Data: a.Data, } } func (s *SymBandDense) checkOverlap(a blas64.General) bool { return checkOverlap(generalFromSymmetricBand(s.RawSymBand()), a) } func (s *SymBandDense) checkOverlapMatrix(a Matrix) bool { if s == a { return false } var amat blas64.General switch ar := a.(type) { default: return false case RawMatrixer: amat = ar.RawMatrix() case RawSymmetricer: amat = generalFromSymmetric(ar.RawSymmetric()) case RawSymBander: amat = generalFromSymmetricBand(ar.RawSymBand()) case RawTriangular: amat = generalFromTriangular(ar.RawTriangular()) case RawVectorer: r, c := a.Dims() amat = generalFromVector(ar.RawVector(), r, c) } return s.checkOverlap(amat) } // generalFromSymmetricBand returns a blas64.General with the backing // data and dimensions of a. func generalFromSymmetricBand(a blas64.SymmetricBand) blas64.General { return blas64.General{ Rows: a.N, Cols: a.K + 1, Data: a.Data, Stride: a.Stride, } }