github.com/rmera/gochem@v0.7.1/v3/gonum_purego.go (about)

     1  // +build ignored
     2  
     3  /*
     4   * gonum_go.go, part of gochem.
     5   *
     6   * Copyright 2012 Raul Mera <rmera{at}chemDOThelsinkiDOTfi>
     7   *
     8   * This program is free software; you can redistribute it and/or modify
     9   * it under the terms of the GNU Lesser General Public License as
    10   * published by the Free Software Foundation; either version 2.1 of the
    11   * License, or (at your option) any later version.
    12   *
    13   * This program is distributed in the hope that it will be useful,
    14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16   * GNU General Public License for more details.
    17   *
    18   * You should have received a copy of the GNU Lesser General
    19   * Public License along with this program.  If not, see
    20   * <http://www.gnu.org/licenses/>.
    21   *
    22   * Gochem is developed at the laboratory for instruction in Swedish, Department of Chemistry,
    23   * University of Helsinki, Finland.
    24   *
    25   */
    26  
    27  //Package chem provides atom and molecule structures, facilities for reading and writing some
    28  //files used in computational chemistry and some functions for geometric manipulations and shape
    29  //indicators.
    30  
    31  //All the *Vec functions will operate/produce column or row vectors depending on whether the matrix underlying Dense
    32  //is row or column major.
    33  
    34  package chem
    35  
    36  import (
    37  	"fmt"
    38  	"math"
    39  	"sort"
    40  
    41  	matrix "github.com/skelterjohn/go.matrix"
    42  )
    43  
    44  /*Here I make a -very incomplete- implementation of the gonum api backed by go.matrix, which will enable me to port gochem to gonum.
    45   * Since the agreement in the gonum community was NOT to build a temporary implementation, I just build the functions that
    46   * gochem uses, on my own type (which should implement all the relevant gonum interfaces).
    47   * all the gonum-owned names will start with gn (i.e. RandomFunc becomes gnRandomFunc) so its latter easy to use search and replace to set the
    48   * correct import path when gonum is implemented (such as gonum.RandomFunc)
    49   */
    50  
    51  //INTERFACES  This part is from GONUM, copyright, the gonum authors.
    52  
    53  //This part of the package is deprecated. Gonum is the only implemantation used in goChem now.
    54  
    55  type Normer interface {
    56  	Norm(o float64) float64
    57  }
    58  
    59  type NormerMatrix interface {
    60  	Normer
    61  	Matrix
    62  }
    63  
    64  // BlasMatrix represents a cblas native representation of a matrix.
    65  type BlasMatrix struct {
    66  	Rows, Cols int
    67  	Stride     int
    68  	Data       []float64
    69  }
    70  
    71  //VecMatrix is a set of vectors in 3D space. The underlying implementation varies.
    72  type VecMatrix struct {
    73  	*Dense
    74  }
    75  
    76  //For the pure-go implementation I must implement Dense on top of go.matrix
    77  type chemDense struct {
    78  	*Dense
    79  }
    80  
    81  //For the pure-go implementation I must implement Dense on top of go.matrix
    82  type Dense struct {
    83  	*matrix.DenseMatrix
    84  }
    85  
    86  //Generate and returns a CoorMatrix with arbitrary shape from data.
    87  func newDense(data []float64, rows, cols int) *Dense {
    88  	if len(data) < cols*rows {
    89  		panic(notEnoughElements)
    90  	}
    91  	return &Dense{matrix.MakeDenseMatrix(data, rows, cols)}
    92  
    93  }
    94  
    95  func det(A *VecMatrix) float64 {
    96  	return A.Det()
    97  
    98  }
    99  
   100  //Generate and returns a CoorMatrix with arbitrary shape from data.
   101  func newchemDense(data []float64, rows, cols int) (*chemDense, error) {
   102  	if len(data) < cols*rows {
   103  		return nil, fmt.Errorf(string(notEnoughElements))
   104  	}
   105  	return &chemDense{newDense(data, rows, cols)}, nil
   106  
   107  }
   108  
   109  //NewVecs enerates and returns a VecMatrix with 3 columns from data.
   110  func NewVecs(data []float64) (*VecMatrix, error) {
   111  	///fmt.Println("JAJAJA BIENVENIDO AL INFIERNO!!!!") //Surely a debugging msg I had forgotten about. It would have rather surprised any Spanish-speaking user :-)
   112  	const cols int = 3
   113  	l := len(data)
   114  	rows := l / cols
   115  	if l%cols != 0 {
   116  		return nil, fmt.Errorf("Input slice lenght %d not divisible by %d: %d", rows, cols, rows%cols)
   117  	}
   118  	r := newDense(data, rows, cols)
   119  	return &VecMatrix{r}, nil
   120  }
   121  
   122  //Returns and empty, but not nil, Dense. It barely allocates memory
   123  func EmptyDense() *Dense {
   124  	var a *matrix.DenseMatrix
   125  	return &Dense{a}
   126  
   127  }
   128  
   129  //Returns an zero-filled Dense with the given dimensions
   130  //It is to be substituted by the Gonum function.
   131  func gnZeros(rows, cols int) *chemDense {
   132  	return &chemDense{&Dense{matrix.Zeros(rows, cols)}}
   133  }
   134  
   135  //Returns an identity matrix spanning span cols and rows
   136  func gnEye(span int) *chemDense {
   137  	A := gnZeros(span, span)
   138  	for i := 0; i < span; i++ {
   139  		A.Set(i, i, 1.0)
   140  	}
   141  	return A
   142  }
   143  
   144  func Eye(span int) *chemDense {
   145  	return gnEye(span)
   146  }
   147  
   148  //Some temporary support function.
   149  //func Eigen(in *Dense, epsilon float64) (*Dense, []float64, error) {
   150  //	i, j, k := gnEigen(in, epsilon)
   151  //	return i, j, k
   152  //}
   153  
   154  //This is a facility to sort Eigenvectors/Eigenvalues pairs
   155  //It satisfies the sort.Interface interface.
   156  type eigenpair struct {
   157  	//evecs must have as many rows as evals has elements.
   158  	evecs *VecMatrix
   159  	evals sort.Float64Slice
   160  }
   161  
   162  func (E eigenpair) Less(i, j int) bool {
   163  	return E.evals[i] < E.evals[j]
   164  }
   165  func (E eigenpair) Swap(i, j int) {
   166  	E.evals.Swap(i, j)
   167  	//	E.evecs[i],E.evecs[j]=E.evecs[j],E.evecs[i]
   168  	E.evecs.SwapRows(i, j)
   169  }
   170  func (E eigenpair) Len() int {
   171  	return len(E.evals)
   172  }
   173  
   174  //EigenWrap wraps the matrix.DenseMatrix.Eigen() function in order to guarantee
   175  //That the eigenvectors and eigenvalues are sorted according to the eigenvalues
   176  //It also guarantees orthonormality and handness. I don't know how many of
   177  //these are already guaranteed by Eig(). Will delete the unneeded parts
   178  //And even this whole function when sure.
   179  func EigenWrap(in *VecMatrix, epsilon float64) (*VecMatrix, []float64, error) {
   180  	var err error
   181  	if epsilon < 0 {
   182  		epsilon = appzero
   183  	}
   184  	evecsDM, vals, _ := in.Eigen()
   185  	evecs := &VecMatrix{&Dense{evecsDM}}
   186  	//	fmt.Println("evecs fresh", evecs) ///////
   187  	evals := [3]float64{vals.Get(0, 0), vals.Get(1, 1), vals.Get(2, 2)} //go.matrix specific code here.
   188  	f := func() { evecs.TCopy(evecs) }
   189  	if err = gnMaybe(gnPanicker(f)); err != nil {
   190  		return nil, nil, err
   191  	}
   192  	eig := eigenpair{evecs, evals[:]}
   193  
   194  	//	fmt.Println("evecs presort", eig.evecs) /////////
   195  	sort.Sort(eig)
   196  
   197  	//Here I should orthonormalize vectors if needed instead of just complaining.
   198  	//I think orthonormality is guaranteed by  DenseMatrix.Eig() If it is, Ill delete all this
   199  	//If not I'll add ortonormalization routines.
   200  	eigrows, _ := eig.evecs.Dims()
   201  	//	fmt.Println("evecs", eig.evecs)  ////////////////
   202  	for i := 0; i < eigrows; i++ {
   203  		vectori := eig.evecs.RowView(i)
   204  		for j := i + 1; j < eigrows; j++ {
   205  			vectorj := eig.evecs.RowView(j)
   206  			if math.Abs(vectori.Dot(vectorj)) > epsilon && i != j {
   207  				return eig.evecs, evals[:], notOrthogonal
   208  			}
   209  		}
   210  		//	fmt.Println("VECTORS", eig.evecs) //////////////////////////
   211  		if math.Abs(vectori.Norm(2)-1) > epsilon {
   212  			//Of course I could just normalize the vectors instead of complaining.
   213  			//err= fmt.Errorf("Vectors not normalized %s",err.Error())
   214  
   215  		}
   216  	}
   217  	//Checking and fixing the handness of the matrix.This if-else is Jannes idea,
   218  	//I don't really know whether it works.
   219  	eig.evecs.TCopy(eig.evecs)
   220  	if eig.evecs.Det() < 0 {
   221  		eig.evecs.Scale(-1, eig.evecs) //SSC
   222  	} else {
   223  		/*
   224  			eig.evecs.TransposeInPlace()
   225  			eig.evecs.ScaleRow(0,-1)
   226  			eig.evecs.ScaleRow(2,-1)
   227  			eig.evecs.TransposeInPlace()
   228  		*/
   229  		//	fmt.Println("all good, I guess")
   230  	}
   231  	eig.evecs.TCopy(eig.evecs)
   232  	return eig.evecs, eig.evals, err //Returns a slice of evals
   233  }
   234  
   235  //Returns the singular value decomposition of matrix A
   236  func gnSVD(A *chemDense) (*chemDense, *chemDense, *chemDense) {
   237  	U, s, V, err := A.SVD()
   238  	if err != nil {
   239  		panic(err.Error())
   240  	}
   241  	theU := chemDense{&Dense{U}}
   242  	sigma := chemDense{&Dense{s}}
   243  	theV := chemDense{&Dense{V}}
   244  	return &theU, &sigma, &theV
   245  
   246  }
   247  
   248  //returns a rows,cols matrix filled with gnOnes.
   249  func gnOnes(rows, cols int) *chemDense {
   250  	gnOnes := gnZeros(rows, cols)
   251  	for i := 0; i < rows; i++ {
   252  		for j := 0; j < cols; j++ {
   253  			gnOnes.Set(i, j, 1)
   254  		}
   255  	}
   256  	return gnOnes
   257  }
   258  
   259  func gnMul(A, B Matrix) *chemDense {
   260  	ar, _ := A.Dims()
   261  	_, bc := B.Dims()
   262  	C := gnZeros(ar, bc)
   263  	C.Mul(A, B)
   264  	return C
   265  }
   266  
   267  func gnCopy(A Matrix) *chemDense {
   268  	r, c := A.Dims()
   269  	B := gnZeros(r, c)
   270  	B.Copy(A)
   271  	return B
   272  }
   273  
   274  func gnT(A Matrix) *chemDense {
   275  	r, c := A.Dims()
   276  	B := gnZeros(c, r)
   277  	B.TCopy(A)
   278  	return B
   279  }
   280  
   281  //Methods
   282  /* When gonum is ready, all this functions will take a num.Matrix interface as an argument, instead of a
   283   * Dense*/
   284  
   285  func (F *Dense) Add(A, B Matrix) {
   286  	ar, ac := A.Dims()
   287  	br, bc := B.Dims()
   288  	fr, fc := F.Dims()
   289  	if ac != bc || br != ar || ac != fc || ar != fr {
   290  		panic(gnErrShape)
   291  	}
   292  	for i := 0; i < fr; i++ {
   293  		for j := 0; j < fc; j++ {
   294  			F.Set(i, j, A.At(i, j)+B.At(i, j))
   295  		}
   296  	}
   297  
   298  }
   299  
   300  func (F *Dense) BlasMatrix() BlasMatrix {
   301  	b := new(BlasMatrix)
   302  	r, c := F.Dims()
   303  	b.Rows = r
   304  	b.Cols = c
   305  	b.Stride = 0 //not really
   306  	b.Data = F.Array()
   307  	return *b
   308  }
   309  
   310  func (F *Dense) At(A, B int) float64 {
   311  	return F.Get(A, B)
   312  }
   313  
   314  func (F *Dense) Copy(A Matrix) {
   315  	ar, ac := A.Dims()
   316  	fr, fc := F.Dims()
   317  	if ac > fc || ar > fr {
   318  		//	fmt.Println(ar, ac, fr, fc)
   319  		panic(gnErrShape)
   320  	}
   321  
   322  	for i := 0; i < ar; i++ {
   323  		for j := 0; j < ac; j++ {
   324  			F.Set(i, j, A.At(i, j))
   325  		}
   326  
   327  	}
   328  
   329  }
   330  
   331  //Returns an array with the data in the ith row of F
   332  func (F *Dense) Col(a []float64, i int) []float64 {
   333  	r, c := F.Dims()
   334  	if i >= c {
   335  		panic("Matrix: Requested column out of bounds")
   336  	}
   337  	if a == nil {
   338  		a = make([]float64, r, r)
   339  	}
   340  	for j := 0; j < r; j++ {
   341  		if j >= len(a) {
   342  			break
   343  		}
   344  		a[j] = F.At(j, i)
   345  	}
   346  	return a
   347  }
   348  
   349  func (F *Dense) Dims() (int, int) {
   350  	return F.Rows(), F.Cols()
   351  }
   352  
   353  //Dot returns the dot product between 2 vectors or matrices
   354  func (F *Dense) Dot(B Matrix) float64 {
   355  	frows, fcols := F.Dims()
   356  	brows, bcols := B.Dims()
   357  	if fcols != bcols || frows != brows {
   358  		panic(gnErrShape)
   359  	}
   360  	a, b := F.Dims()
   361  	A := gnZeros(a, b)
   362  	A.MulElem(F, B)
   363  	return A.Sum()
   364  }
   365  
   366  //puts the inverse of B in F or panics if F is non-singular.
   367  //its just a dirty minor adaptation from the code in go.matrix from John Asmuth
   368  //it will be replaced by the gonum implementation when the library is ready.
   369  //Notice that this doesn't actually check for errors, the error value returned is always nil.
   370  //I just did that crappy fix because this gomatrix-interface should be taken out or deprecated soon.
   371  func gnInverse(B Matrix) (*VecMatrix, error) {
   372  	//fr,fc:=F.Dims()
   373  	ar, ac := B.Dims()
   374  	if ac != ar {
   375  		panic(gnErrSquare)
   376  	}
   377  	F := ZeroVecs(ar)
   378  	var ok bool
   379  	var A *VecMatrix
   380  	A, ok = B.(*VecMatrix)
   381  	if !ok {
   382  		C, ok := B.(*Dense)
   383  		if !ok {
   384  			panic("Few types are allowed so far")
   385  		}
   386  		A = &VecMatrix{C}
   387  
   388  	}
   389  	augt, _ := A.Augment(matrix.Eye(ar))
   390  	aug := &Dense{augt}
   391  	augr, _ := aug.Dims()
   392  	for i := 0; i < augr; i++ {
   393  		j := i
   394  		for k := i; k < augr; k++ {
   395  			if math.Abs(aug.Get(k, i)) > math.Abs(aug.Get(j, i)) {
   396  				j = k
   397  			}
   398  		}
   399  		if j != i {
   400  			aug.SwapRows(i, j)
   401  		}
   402  		if aug.Get(i, i) == 0 {
   403  			panic(gnErrSingular)
   404  		}
   405  		aug.ScaleRow(i, 1.0/aug.Get(i, i))
   406  		for k := 0; k < augr; k++ {
   407  			if k == i {
   408  				continue
   409  			}
   410  			aug.ScaleAddRow(k, i, -aug.Get(k, i))
   411  		}
   412  	}
   413  	F.SubMatrix(aug, 0, ac, ar, ac)
   414  	return F, nil
   415  }
   416  
   417  //A slightly modified version of John Asmuth's ParalellProduct function.
   418  func (F *Dense) Mul(A, B Matrix) {
   419  	Arows, Acols := A.Dims()
   420  	Brows, Bcols := B.Dims()
   421  	if Acols != Brows {
   422  		panic(gnErrShape)
   423  	}
   424  	if F == nil {
   425  		F = gnZeros(Arows, Bcols).Dense //I don't know if the final API will allow this.
   426  	}
   427  
   428  	in := make(chan int)
   429  	quit := make(chan bool)
   430  
   431  	dotRowCol := func() {
   432  		for {
   433  			select {
   434  			case i := <-in:
   435  				sums := make([]float64, Bcols)
   436  				for k := 0; k < Acols; k++ {
   437  					for j := 0; j < Bcols; j++ {
   438  						sums[j] += A.At(i, k) * B.At(k, j)
   439  					}
   440  				}
   441  				for j := 0; j < Bcols; j++ {
   442  					F.Set(i, j, sums[j])
   443  				}
   444  			case <-quit:
   445  				return
   446  			}
   447  		}
   448  	}
   449  
   450  	threads := 2
   451  
   452  	for i := 0; i < threads; i++ {
   453  		go dotRowCol()
   454  	}
   455  
   456  	for i := 0; i < Arows; i++ {
   457  		in <- i
   458  	}
   459  
   460  	for i := 0; i < threads; i++ {
   461  		quit <- true
   462  	}
   463  
   464  	return
   465  }
   466  
   467  func (F *Dense) MulElem(A, B Matrix) {
   468  	arows, acols := A.Dims()
   469  	brows, bcols := B.Dims()
   470  	frows, fcols := F.Dims()
   471  	if arows != brows || acols != bcols || arows != frows || acols != fcols {
   472  		panic(gnErrShape)
   473  	}
   474  	for i := 0; i < arows; i++ {
   475  		for j := 0; j < acols; j++ {
   476  			F.Set(i, j, A.At(i, j)*B.At(i, j))
   477  		}
   478  
   479  	}
   480  }
   481  
   482  func (F *Dense) Norm(i float64) float64 {
   483  	//The parameters is for compatibility
   484  	return F.TwoNorm()
   485  }
   486  
   487  //Returns an array with the data in the ith row of F
   488  func (F *Dense) Row(a []float64, i int) []float64 {
   489  	r, c := F.Dims()
   490  	if i >= r {
   491  		panic("Matrix: Requested row out of bounds")
   492  	}
   493  	if a == nil {
   494  		a = make([]float64, c, c)
   495  	}
   496  	for j := 0; j < c; j++ {
   497  		if j >= len(a) {
   498  			break
   499  		}
   500  		a[j] = F.At(i, j)
   501  	}
   502  	return a
   503  }
   504  
   505  //Scale the matrix A by a number i, putting the result in the received.
   506  func (F *Dense) Scale(i float64, A Matrix) {
   507  	if A == F { //if A and F points to the same object.
   508  		F.scaleAux(i)
   509  	} else {
   510  		F.Copy(A)
   511  		F.scaleAux(i)
   512  	}
   513  }
   514  
   515  //Puts a view of the given col of the matrix on the receiver
   516  func (F *VecMatrix) ColView(i int) *VecMatrix {
   517  	r := new(Dense)
   518  	*r = *F.Dense
   519  	Fr, _ := F.Dims()
   520  	r.View(0, i, Fr, 1)
   521  	return &VecMatrix{r}
   522  }
   523  
   524  //Returns view of the given vector of the matrix in the receiver
   525  func (F *VecMatrix) VecView(i int) *VecMatrix {
   526  	r := new(Dense)
   527  	*r = *F.Dense
   528  	r.View(i, 0, 1, 3)
   529  	return &VecMatrix{r}
   530  }
   531  
   532  //View returns a view of F starting from i,j and spanning r rows and
   533  //c columns. Changes in the view are reflected in F and vice-versa
   534  //This view has the wrong signature for the interface mat64.Viewer,
   535  //But the right signatur was not possible to implement. Notice that very little
   536  //memory allocation happens, only a couple of ints and pointers.
   537  func (F *VecMatrix) View(i, j, r, c int) *VecMatrix {
   538  	ret := new(Dense)
   539  	*ret = *F.Dense
   540  	ret.View(i, j, r, c)
   541  	return &VecMatrix{ret}
   542  }
   543  
   544  func (F *Dense) scaleAux(factor float64) {
   545  	fr, fc := F.Dims()
   546  	for i := 0; i < fr; i++ {
   547  		for j := 0; j < fc; j++ {
   548  			F.Set(i, j, F.At(i, j)*factor)
   549  		}
   550  
   551  	}
   552  }
   553  
   554  //When go.matrix is abandoned it is necesary to implement SetMatrix
   555  //SetMatrix()
   556  //Copies A into F aligning A(0,0) with F(i,j)
   557  func (F *Dense) SetMatrix(i, j int, A Matrix) {
   558  	fr, fc := F.Dims()
   559  	ar, ac := A.Dims()
   560  	if ar+i > fr || ac+j > fc {
   561  		panic(gnErrShape)
   562  	}
   563  	for l := 0; l < ar; l++ {
   564  		for m := 0; m < ac; m++ {
   565  			F.Set(l+i, m+j, A.At(l, m))
   566  		}
   567  	}
   568  }
   569  
   570  //puts in F a matrix consisting in A over B
   571  func (F *Dense) Stack(A, B Matrix) {
   572  	Arows, Acols := A.Dims()
   573  	Brows, Bcols := B.Dims()
   574  	Frows, Fcols := F.Dims()
   575  
   576  	if Acols != Bcols || Acols != Fcols || Arows+Brows != Frows {
   577  		panic(gnErrShape)
   578  	}
   579  
   580  	for i := 0; i < Arows+Brows; i++ {
   581  		for j := 0; j < Acols; j++ {
   582  			if i < Arows {
   583  				F.Set(i, j, A.At(i, j))
   584  			} else {
   585  				F.Set(i, j, B.At(i-Arows, j))
   586  			}
   587  		}
   588  	}
   589  
   590  	return
   591  }
   592  
   593  //Subtracts the matrix B from A putting the result in F
   594  func (F *Dense) Sub(A, B Matrix) {
   595  	ar, ac := A.Dims()
   596  	br, bc := B.Dims()
   597  	fr, fc := F.Dims()
   598  	if ac != bc || br != ar || ac != fc || ar != fr {
   599  		panic(gnErrShape)
   600  	}
   601  	for i := 0; i < fr; i++ {
   602  		for j := 0; j < fc; j++ {
   603  			F.Set(i, j, A.At(i, j)-B.At(i, j))
   604  		}
   605  	}
   606  
   607  }
   608  
   609  //not tested
   610  //returns a copy of the submatrix of A starting by the point i,j and
   611  //spanning rows rows and cols columns.
   612  func (F *Dense) SubMatrix(A *Dense, i, j, rows, cols int) {
   613  	temp := Dense{A.GetMatrix(i, j, rows, cols)}
   614  	F.Copy(&temp)
   615  }
   616  
   617  //Sum returns the sum of all elements in matrix A.
   618  func (F *Dense) Sum() float64 {
   619  	Rows, Cols := F.Dims()
   620  	var sum float64
   621  	for i := 0; i < Cols; i++ {
   622  		for j := 0; j < Rows; j++ {
   623  			sum += F.Get(j, i)
   624  		}
   625  	}
   626  	return sum
   627  }
   628  
   629  //Transpose
   630  func (F *Dense) TCopy(A Matrix) {
   631  	ar, ac := A.Dims()
   632  	fr, fc := F.Dims()
   633  	if ar != fc || ac != fr {
   634  		panic(gnErrShape)
   635  	}
   636  	var B *Dense
   637  	var ok bool
   638  	if B, ok = A.(*Dense); !ok {
   639  		if C, ok := A.(*VecMatrix); ok {
   640  			B = C.Dense
   641  		} else if D, ok := A.(*chemDense); ok {
   642  			B = D.Dense
   643  		} else {
   644  			panic("Only Dense, chemDense and VecMatrix are currently accepted")
   645  		}
   646  	}
   647  	//we do it in a different way if you pass the received as the argument
   648  	//(transpose in place) We could use continue for i==j
   649  	if F == B {
   650  		/*		for i := 0; i < ar; i++ {
   651  				for j := 0; j < i; j++ {
   652  					tmp := A.At(i, j)
   653  					F.Set(i, j, A.At(j, i))
   654  					F.Set(j, i, tmp)
   655  				}
   656  		*/F.TransposeInPlace()
   657  	} else {
   658  		F.DenseMatrix = B.Transpose()
   659  		/*
   660  			for i := 0; i < ar; i++ {
   661  				for j := 0; j < ac; j++ {
   662  					F.Set(j, i, A.At(i, j))
   663  				}
   664  			}
   665  		*/
   666  	}
   667  }
   668  
   669  //Unit takes a vector and divides it by its norm
   670  //thus obtaining an unitary vector pointing in the same direction as
   671  //vector.
   672  func (F *Dense) Unit(A NormerMatrix) {
   673  	norm := 1.0 / A.Norm(2)
   674  	F.Scale(norm, A)
   675  }
   676  
   677  func (F *Dense) View(i, j, rows, cols int) {
   678  	F.DenseMatrix = F.GetMatrix(i, j, rows, cols)
   679  }
   680  
   681  /**These are from the current proposal for gonum, by Dan Kortschak. It will be taken out
   682   * from here when gonum is implemented. The gn prefix is appended to the names to make them
   683   * unimported and to allow easy use of search/replace to add the "num" prefix when I change to
   684   * gonum.**/
   685  
   686  // A Panicker is a function that may panic.
   687  type gnPanicker func()
   688  
   689  // Maybe will recover a panic with a type matrix.Error from fn, and return this error.
   690  // Any other error is re-panicked.
   691  func gnMaybe(fn gnPanicker) (err error) {
   692  	defer func() {
   693  		if r := recover(); r != nil {
   694  			var ok bool
   695  			if err, ok = r.(gnError); ok {
   696  				return
   697  			}
   698  			panic(r)
   699  		}
   700  	}()
   701  	fn()
   702  	return
   703  }
   704  
   705  // Type Error represents matrix package errors. These errors can be recovered by Maybe wrappers.
   706  type gnError string
   707  
   708  func (err gnError) Error() string { return string(err) }
   709  
   710  const (
   711  	//RM
   712  	not3xXMatrix      = gnError("matrix: The other dimmension should be 3")
   713  	notOrthogonal     = gnError("matrix: Vectors nor orthogonal")
   714  	notEnoughElements = gnError("matrix: not enough elements")
   715  	//end RM
   716  	gnErrIndexOutOfRange = gnError("matrix: index out of range")
   717  	gnErrZeroLength      = gnError("matrix: zero length in matrix definition")
   718  	gnErrRowLength       = gnError("matrix: row length mismatch")
   719  	gnErrColLength       = gnError("matrix: col length mismatch")
   720  	gnErrSquare          = gnError("matrix: expect square matrix")
   721  	gnErrNormOrder       = gnError("matrix: invalid norm order for matrix")
   722  	gnErrSingular        = gnError("matrix: matrix is singular")
   723  	gnErrShape           = gnError("matrix: dimension mismatch")
   724  	gnErrIllegalStride   = gnError("matrix: illegal stride")
   725  	gnErrPivot           = gnError("matrix: malformed pivot list")
   726  )