forked from LaconicNetwork/kompose
Upgrade OpenShift and its dependencies.
OpenShift version 1.4.0-alpha.0
This commit is contained in:
+39
@@ -0,0 +1,39 @@
|
||||
sudo: required
|
||||
|
||||
language: go
|
||||
|
||||
# Versions of go that are explicitly supported by gonum.
|
||||
go:
|
||||
- 1.5beta1
|
||||
- 1.3.3
|
||||
- 1.4.2
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BLAS_LIB=OpenBLAS
|
||||
- BLAS_LIB=gonum
|
||||
# at some point, when travis allows builds on darwin
|
||||
#- BLAS_LIB=Accellerate
|
||||
# at some point, when the issue with drotgm is resolved
|
||||
#- BLAS_LIB=ATLAS
|
||||
|
||||
# Required for coverage.
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
|
||||
# Install the appropriate blas library if we are using cgo.
|
||||
install:
|
||||
- source .travis/$TRAVIS_OS_NAME/$BLAS_LIB/install.sh
|
||||
- go get github.com/gonum/floats
|
||||
|
||||
# Get deps, build, test, and ensure the code is gofmt'ed.
|
||||
# Move into the native directory if we aren't using an external blas lib.
|
||||
# If we are building as gonum, then we have access to the coveralls api key, so we can run coverage as well.
|
||||
script:
|
||||
- if [[ "$BLAS_LIB" == "gonum" ]]; then pushd native; fi
|
||||
- go get -d -t -v ./...
|
||||
- go test -a -v ./...
|
||||
- go test -a -tags noasm -v ./...
|
||||
- diff <(gofmt -d .) <("")
|
||||
- if [[ $TRAVIS_SECURE_ENV_VARS = "true" ]]; then bash -c "${TRAVIS_BUILD_DIR}/.travis/test-coverage.sh"; fi
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
# Gonum BLAS [](https://travis-ci.org/gonum/blas) [](https://coveralls.io/r/gonum/blas)
|
||||
|
||||
A collection of packages to provide BLAS functionality for the [Go programming
|
||||
language](http://golang.org)
|
||||
|
||||
## Installation
|
||||
```sh
|
||||
go get github.com/gonum/blas
|
||||
```
|
||||
|
||||
### BLAS C-bindings
|
||||
|
||||
If you want to use OpenBLAS, install it in any directory:
|
||||
```sh
|
||||
git clone https://github.com/xianyi/OpenBLAS
|
||||
cd OpenBLAS
|
||||
make
|
||||
```
|
||||
|
||||
The blas/cgo package provides bindings to C-backed BLAS packages. blas/cgo needs the `CGO_LDFLAGS`
|
||||
environment variable to point to the blas installation. More information can be found in the
|
||||
[cgo command documentation](http://golang.org/cmd/cgo/).
|
||||
|
||||
Then install the blas/cgo package:
|
||||
```sh
|
||||
CGO_LDFLAGS="-L/path/to/OpenBLAS -lopenblas" go install github.com/gonum/blas/cgo
|
||||
```
|
||||
|
||||
For Windows you can download binary packages for OpenBLAS at
|
||||
[SourceForge](http://sourceforge.net/projects/openblas/files/).
|
||||
|
||||
If you want to use a different BLAS package such as the Intel MKL you can
|
||||
adjust the `CGO_LDFLAGS` variable:
|
||||
```sh
|
||||
CGO_LDFLAGS="-lmkl_rt" go install github.com/gonum/blas/cgo
|
||||
```
|
||||
|
||||
On OS X the easiest solution is to use the libraries provided by the system:
|
||||
```sh
|
||||
CGO_LDFLAGS="-framework Accelerate" go install github.com/gonum/blas/cgo
|
||||
```
|
||||
|
||||
## Packages
|
||||
|
||||
### blas
|
||||
|
||||
Defines [BLAS API](http://www.netlib.org/blas/blast-forum/cinterface.pdf) split in several
|
||||
interfaces.
|
||||
|
||||
### blas/native
|
||||
|
||||
Go implementation of the BLAS API (incomplete, implements the `float32` and `float64` API)
|
||||
|
||||
### blas/cgo
|
||||
|
||||
Binding to a C implementation of the cblas interface (e.g. ATLAS, OpenBLAS, Intel MKL)
|
||||
|
||||
The recommended (free) option for good performance on both Linux and Darwin is OpenBLAS.
|
||||
|
||||
### blas/blas64 and blas/blas32
|
||||
|
||||
Wrappers for an implementation of the double (i.e., `float64`) and single (`float32`)
|
||||
precision real parts of the blas API
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gonum/blas/blas64"
|
||||
)
|
||||
|
||||
func main() {
|
||||
v := blas64.Vector{Inc: 1, Data: []float64{1, 1, 1}}
|
||||
fmt.Println("v has length:", blas64.Nrm2(len(v.Data), v))
|
||||
}
|
||||
```
|
||||
|
||||
### blas/cblas128 and blas/cblas64
|
||||
|
||||
Wrappers for an implementation of the double (i.e., `complex128`) and single (`complex64`)
|
||||
precision complex parts of the blas API
|
||||
|
||||
Currently blas/cblas64 and blas/cblas128 require blas/cgo.
|
||||
|
||||
## Issues
|
||||
|
||||
If you find any bugs, feel free to file an issue on the github issue tracker.
|
||||
Discussions on API changes, added features, code review, or similar requests
|
||||
are preferred on the [gonum-dev Google Group](https://groups.google.com/forum/#!forum/gonum-dev).
|
||||
|
||||
## License
|
||||
|
||||
Please see [github.com/gonum/license](https://github.com/gonum/license) for general
|
||||
license information, contributors, authors, etc on the Gonum suite of packages.
|
||||
+388
@@ -0,0 +1,388 @@
|
||||
// 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 blas provides interfaces for the BLAS linear algebra standard.
|
||||
|
||||
All methods must perform appropriate parameter checking and panic if
|
||||
provided parameters that do not conform to the requirements specified
|
||||
by the BLAS standard.
|
||||
|
||||
Quick Reference Guide to the BLAS from http://www.netlib.org/lapack/lug/node145.html
|
||||
|
||||
This version is modified to remove the "order" option. All matrix operations are
|
||||
on row-order matrices.
|
||||
|
||||
Level 1 BLAS
|
||||
|
||||
dim scalar vector vector scalars 5-element prefixes
|
||||
struct
|
||||
|
||||
_rotg ( a, b ) S, D
|
||||
_rotmg( d1, d2, a, b ) S, D
|
||||
_rot ( n, x, incX, y, incY, c, s ) S, D
|
||||
_rotm ( n, x, incX, y, incY, param ) S, D
|
||||
_swap ( n, x, incX, y, incY ) S, D, C, Z
|
||||
_scal ( n, alpha, x, incX ) S, D, C, Z, Cs, Zd
|
||||
_copy ( n, x, incX, y, incY ) S, D, C, Z
|
||||
_axpy ( n, alpha, x, incX, y, incY ) S, D, C, Z
|
||||
_dot ( n, x, incX, y, incY ) S, D, Ds
|
||||
_dotu ( n, x, incX, y, incY ) C, Z
|
||||
_dotc ( n, x, incX, y, incY ) C, Z
|
||||
__dot ( n, alpha, x, incX, y, incY ) Sds
|
||||
_nrm2 ( n, x, incX ) S, D, Sc, Dz
|
||||
_asum ( n, x, incX ) S, D, Sc, Dz
|
||||
I_amax( n, x, incX ) s, d, c, z
|
||||
|
||||
Level 2 BLAS
|
||||
|
||||
options dim b-width scalar matrix vector scalar vector prefixes
|
||||
|
||||
_gemv ( trans, m, n, alpha, a, lda, x, incX, beta, y, incY ) S, D, C, Z
|
||||
_gbmv ( trans, m, n, kL, kU, alpha, a, lda, x, incX, beta, y, incY ) S, D, C, Z
|
||||
_hemv ( uplo, n, alpha, a, lda, x, incX, beta, y, incY ) C, Z
|
||||
_hbmv ( uplo, n, k, alpha, a, lda, x, incX, beta, y, incY ) C, Z
|
||||
_hpmv ( uplo, n, alpha, ap, x, incX, beta, y, incY ) C, Z
|
||||
_symv ( uplo, n, alpha, a, lda, x, incX, beta, y, incY ) S, D
|
||||
_sbmv ( uplo, n, k, alpha, a, lda, x, incX, beta, y, incY ) S, D
|
||||
_spmv ( uplo, n, alpha, ap, x, incX, beta, y, incY ) S, D
|
||||
_trmv ( uplo, trans, diag, n, a, lda, x, incX ) S, D, C, Z
|
||||
_tbmv ( uplo, trans, diag, n, k, a, lda, x, incX ) S, D, C, Z
|
||||
_tpmv ( uplo, trans, diag, n, ap, x, incX ) S, D, C, Z
|
||||
_trsv ( uplo, trans, diag, n, a, lda, x, incX ) S, D, C, Z
|
||||
_tbsv ( uplo, trans, diag, n, k, a, lda, x, incX ) S, D, C, Z
|
||||
_tpsv ( uplo, trans, diag, n, ap, x, incX ) S, D, C, Z
|
||||
|
||||
options dim scalar vector vector matrix prefixes
|
||||
|
||||
_ger ( m, n, alpha, x, incX, y, incY, a, lda ) S, D
|
||||
_geru ( m, n, alpha, x, incX, y, incY, a, lda ) C, Z
|
||||
_gerc ( m, n, alpha, x, incX, y, incY, a, lda ) C, Z
|
||||
_her ( uplo, n, alpha, x, incX, a, lda ) C, Z
|
||||
_hpr ( uplo, n, alpha, x, incX, ap ) C, Z
|
||||
_her2 ( uplo, n, alpha, x, incX, y, incY, a, lda ) C, Z
|
||||
_hpr2 ( uplo, n, alpha, x, incX, y, incY, ap ) C, Z
|
||||
_syr ( uplo, n, alpha, x, incX, a, lda ) S, D
|
||||
_spr ( uplo, n, alpha, x, incX, ap ) S, D
|
||||
_syr2 ( uplo, n, alpha, x, incX, y, incY, a, lda ) S, D
|
||||
_spr2 ( uplo, n, alpha, x, incX, y, incY, ap ) S, D
|
||||
|
||||
Level 3 BLAS
|
||||
|
||||
options dim scalar matrix matrix scalar matrix prefixes
|
||||
|
||||
_gemm ( transA, transB, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc ) S, D, C, Z
|
||||
_symm ( side, uplo, m, n, alpha, a, lda, b, ldb, beta, c, ldc ) S, D, C, Z
|
||||
_hemm ( side, uplo, m, n, alpha, a, lda, b, ldb, beta, c, ldc ) C, Z
|
||||
_syrk ( uplo, trans, n, k, alpha, a, lda, beta, c, ldc ) S, D, C, Z
|
||||
_herk ( uplo, trans, n, k, alpha, a, lda, beta, c, ldc ) C, Z
|
||||
_syr2k( uplo, trans, n, k, alpha, a, lda, b, ldb, beta, c, ldc ) S, D, C, Z
|
||||
_her2k( uplo, trans, n, k, alpha, a, lda, b, ldb, beta, c, ldc ) C, Z
|
||||
_trmm ( side, uplo, transA, diag, m, n, alpha, a, lda, b, ldb ) S, D, C, Z
|
||||
_trsm ( side, uplo, transA, diag, m, n, alpha, a, lda, b, ldb ) S, D, C, Z
|
||||
|
||||
Meaning of prefixes
|
||||
|
||||
S - float32 C - complex64
|
||||
D - float64 Z - complex128
|
||||
|
||||
Matrix types
|
||||
|
||||
GE - GEneral GB - General Band
|
||||
SY - SYmmetric SB - Symmetric Band SP - Symmetric Packed
|
||||
HE - HErmitian HB - Hermitian Band HP - Hermitian Packed
|
||||
TR - TRiangular TB - Triangular Band TP - Triangular Packed
|
||||
|
||||
Options
|
||||
|
||||
trans = NoTrans, Trans, ConjTrans
|
||||
uplo = Upper, Lower
|
||||
diag = Nonunit, Unit
|
||||
side = Left, Right (A or op(A) on the left, or A or op(A) on the right)
|
||||
|
||||
For real matrices, Trans and ConjTrans have the same meaning.
|
||||
For Hermitian matrices, trans = Trans is not allowed.
|
||||
For complex symmetric matrices, trans = ConjTrans is not allowed.
|
||||
*/
|
||||
package blas
|
||||
|
||||
// Flag constants indicate Givens transformation H matrix state.
|
||||
type Flag int
|
||||
|
||||
const (
|
||||
Identity Flag = iota - 2 // H is the identity matrix; no rotation is needed.
|
||||
Rescaling // H specifies rescaling.
|
||||
OffDiagonal // Off-diagonal elements of H are units.
|
||||
Diagonal // Diagonal elements of H are units.
|
||||
)
|
||||
|
||||
// SrotmParams contains Givens transformation parameters returned
|
||||
// by the Float32 Srotm method.
|
||||
type SrotmParams struct {
|
||||
Flag
|
||||
H [4]float32 // Column-major 2 by 2 matrix.
|
||||
}
|
||||
|
||||
// DrotmParams contains Givens transformation parameters returned
|
||||
// by the Float64 Drotm method.
|
||||
type DrotmParams struct {
|
||||
Flag
|
||||
H [4]float64 // Column-major 2 by 2 matrix.
|
||||
}
|
||||
|
||||
// Transpose is used to specify the transposition operation for a
|
||||
// routine.
|
||||
type Transpose int
|
||||
|
||||
const (
|
||||
NoTrans Transpose = 111 + iota
|
||||
Trans
|
||||
ConjTrans
|
||||
)
|
||||
|
||||
// Uplo is used to specify whether the matrix is an upper or lower
|
||||
// triangular matrix.
|
||||
type Uplo int
|
||||
|
||||
const (
|
||||
All Uplo = 120 + iota
|
||||
Upper
|
||||
Lower
|
||||
)
|
||||
|
||||
// Diag is used to specify whether the matrix is a unit or non-unit
|
||||
// triangular matrix.
|
||||
type Diag int
|
||||
|
||||
const (
|
||||
NonUnit Diag = 131 + iota
|
||||
Unit
|
||||
)
|
||||
|
||||
// Side is used to specify from which side a multiplication operation
|
||||
// is performed.
|
||||
type Side int
|
||||
|
||||
const (
|
||||
Left Side = 141 + iota
|
||||
Right
|
||||
)
|
||||
|
||||
// Float32 implements the single precision real BLAS routines.
|
||||
type Float32 interface {
|
||||
Float32Level1
|
||||
Float32Level2
|
||||
Float32Level3
|
||||
}
|
||||
|
||||
// Float32Level1 implements the single precision real BLAS Level 1 routines.
|
||||
type Float32Level1 interface {
|
||||
Sdsdot(n int, alpha float32, x []float32, incX int, y []float32, incY int) float32
|
||||
Dsdot(n int, x []float32, incX int, y []float32, incY int) float64
|
||||
Sdot(n int, x []float32, incX int, y []float32, incY int) float32
|
||||
Snrm2(n int, x []float32, incX int) float32
|
||||
Sasum(n int, x []float32, incX int) float32
|
||||
Isamax(n int, x []float32, incX int) int
|
||||
Sswap(n int, x []float32, incX int, y []float32, incY int)
|
||||
Scopy(n int, x []float32, incX int, y []float32, incY int)
|
||||
Saxpy(n int, alpha float32, x []float32, incX int, y []float32, incY int)
|
||||
Srotg(a, b float32) (c, s, r, z float32)
|
||||
Srotmg(d1, d2, b1, b2 float32) (p SrotmParams, rd1, rd2, rb1 float32)
|
||||
Srot(n int, x []float32, incX int, y []float32, incY int, c, s float32)
|
||||
Srotm(n int, x []float32, incX int, y []float32, incY int, p SrotmParams)
|
||||
Sscal(n int, alpha float32, x []float32, incX int)
|
||||
}
|
||||
|
||||
// Float32Level2 implements the single precision real BLAS Level 2 routines.
|
||||
type Float32Level2 interface {
|
||||
Sgemv(tA Transpose, m, n int, alpha float32, a []float32, lda int, x []float32, incX int, beta float32, y []float32, incY int)
|
||||
Sgbmv(tA Transpose, m, n, kL, kU int, alpha float32, a []float32, lda int, x []float32, incX int, beta float32, y []float32, incY int)
|
||||
Strmv(ul Uplo, tA Transpose, d Diag, n int, a []float32, lda int, x []float32, incX int)
|
||||
Stbmv(ul Uplo, tA Transpose, d Diag, n, k int, a []float32, lda int, x []float32, incX int)
|
||||
Stpmv(ul Uplo, tA Transpose, d Diag, n int, ap []float32, x []float32, incX int)
|
||||
Strsv(ul Uplo, tA Transpose, d Diag, n int, a []float32, lda int, x []float32, incX int)
|
||||
Stbsv(ul Uplo, tA Transpose, d Diag, n, k int, a []float32, lda int, x []float32, incX int)
|
||||
Stpsv(ul Uplo, tA Transpose, d Diag, n int, ap []float32, x []float32, incX int)
|
||||
Ssymv(ul Uplo, n int, alpha float32, a []float32, lda int, x []float32, incX int, beta float32, y []float32, incY int)
|
||||
Ssbmv(ul Uplo, n, k int, alpha float32, a []float32, lda int, x []float32, incX int, beta float32, y []float32, incY int)
|
||||
Sspmv(ul Uplo, n int, alpha float32, ap []float32, x []float32, incX int, beta float32, y []float32, incY int)
|
||||
Sger(m, n int, alpha float32, x []float32, incX int, y []float32, incY int, a []float32, lda int)
|
||||
Ssyr(ul Uplo, n int, alpha float32, x []float32, incX int, a []float32, lda int)
|
||||
Sspr(ul Uplo, n int, alpha float32, x []float32, incX int, ap []float32)
|
||||
Ssyr2(ul Uplo, n int, alpha float32, x []float32, incX int, y []float32, incY int, a []float32, lda int)
|
||||
Sspr2(ul Uplo, n int, alpha float32, x []float32, incX int, y []float32, incY int, a []float32)
|
||||
}
|
||||
|
||||
// Float32Level3 implements the single precision real BLAS Level 3 routines.
|
||||
type Float32Level3 interface {
|
||||
Sgemm(tA, tB Transpose, m, n, k int, alpha float32, a []float32, lda int, b []float32, ldb int, beta float32, c []float32, ldc int)
|
||||
Ssymm(s Side, ul Uplo, m, n int, alpha float32, a []float32, lda int, b []float32, ldb int, beta float32, c []float32, ldc int)
|
||||
Ssyrk(ul Uplo, t Transpose, n, k int, alpha float32, a []float32, lda int, beta float32, c []float32, ldc int)
|
||||
Ssyr2k(ul Uplo, t Transpose, n, k int, alpha float32, a []float32, lda int, b []float32, ldb int, beta float32, c []float32, ldc int)
|
||||
Strmm(s Side, ul Uplo, tA Transpose, d Diag, m, n int, alpha float32, a []float32, lda int, b []float32, ldb int)
|
||||
Strsm(s Side, ul Uplo, tA Transpose, d Diag, m, n int, alpha float32, a []float32, lda int, b []float32, ldb int)
|
||||
}
|
||||
|
||||
// Float64 implements the single precision real BLAS routines.
|
||||
type Float64 interface {
|
||||
Float64Level1
|
||||
Float64Level2
|
||||
Float64Level3
|
||||
}
|
||||
|
||||
// Float64Level1 implements the double precision real BLAS Level 1 routines.
|
||||
type Float64Level1 interface {
|
||||
Ddot(n int, x []float64, incX int, y []float64, incY int) float64
|
||||
Dnrm2(n int, x []float64, incX int) float64
|
||||
Dasum(n int, x []float64, incX int) float64
|
||||
Idamax(n int, x []float64, incX int) int
|
||||
Dswap(n int, x []float64, incX int, y []float64, incY int)
|
||||
Dcopy(n int, x []float64, incX int, y []float64, incY int)
|
||||
Daxpy(n int, alpha float64, x []float64, incX int, y []float64, incY int)
|
||||
Drotg(a, b float64) (c, s, r, z float64)
|
||||
Drotmg(d1, d2, b1, b2 float64) (p DrotmParams, rd1, rd2, rb1 float64)
|
||||
Drot(n int, x []float64, incX int, y []float64, incY int, c float64, s float64)
|
||||
Drotm(n int, x []float64, incX int, y []float64, incY int, p DrotmParams)
|
||||
Dscal(n int, alpha float64, x []float64, incX int)
|
||||
}
|
||||
|
||||
// Float64Level2 implements the double precision real BLAS Level 2 routines.
|
||||
type Float64Level2 interface {
|
||||
Dgemv(tA Transpose, m, n int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int)
|
||||
Dgbmv(tA Transpose, m, n, kL, kU int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int)
|
||||
Dtrmv(ul Uplo, tA Transpose, d Diag, n int, a []float64, lda int, x []float64, incX int)
|
||||
Dtbmv(ul Uplo, tA Transpose, d Diag, n, k int, a []float64, lda int, x []float64, incX int)
|
||||
Dtpmv(ul Uplo, tA Transpose, d Diag, n int, ap []float64, x []float64, incX int)
|
||||
Dtrsv(ul Uplo, tA Transpose, d Diag, n int, a []float64, lda int, x []float64, incX int)
|
||||
Dtbsv(ul Uplo, tA Transpose, d Diag, n, k int, a []float64, lda int, x []float64, incX int)
|
||||
Dtpsv(ul Uplo, tA Transpose, d Diag, n int, ap []float64, x []float64, incX int)
|
||||
Dsymv(ul Uplo, n int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int)
|
||||
Dsbmv(ul Uplo, n, k int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int)
|
||||
Dspmv(ul Uplo, n int, alpha float64, ap []float64, x []float64, incX int, beta float64, y []float64, incY int)
|
||||
Dger(m, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64, lda int)
|
||||
Dsyr(ul Uplo, n int, alpha float64, x []float64, incX int, a []float64, lda int)
|
||||
Dspr(ul Uplo, n int, alpha float64, x []float64, incX int, ap []float64)
|
||||
Dsyr2(ul Uplo, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64, lda int)
|
||||
Dspr2(ul Uplo, n int, alpha float64, x []float64, incX int, y []float64, incY int, a []float64)
|
||||
}
|
||||
|
||||
// Float64Level3 implements the double precision real BLAS Level 3 routines.
|
||||
type Float64Level3 interface {
|
||||
Dgemm(tA, tB Transpose, m, n, k int, alpha float64, a []float64, lda int, b []float64, ldb int, beta float64, c []float64, ldc int)
|
||||
Dsymm(s Side, ul Uplo, m, n int, alpha float64, a []float64, lda int, b []float64, ldb int, beta float64, c []float64, ldc int)
|
||||
Dsyrk(ul Uplo, t Transpose, n, k int, alpha float64, a []float64, lda int, beta float64, c []float64, ldc int)
|
||||
Dsyr2k(ul Uplo, t Transpose, n, k int, alpha float64, a []float64, lda int, b []float64, ldb int, beta float64, c []float64, ldc int)
|
||||
Dtrmm(s Side, ul Uplo, tA Transpose, d Diag, m, n int, alpha float64, a []float64, lda int, b []float64, ldb int)
|
||||
Dtrsm(s Side, ul Uplo, tA Transpose, d Diag, m, n int, alpha float64, a []float64, lda int, b []float64, ldb int)
|
||||
}
|
||||
|
||||
// Complex64 implements the single precision complex BLAS routines.
|
||||
type Complex64 interface {
|
||||
Complex64Level1
|
||||
Complex64Level2
|
||||
Complex64Level3
|
||||
}
|
||||
|
||||
// Complex64Level1 implements the single precision complex BLAS Level 1 routines.
|
||||
type Complex64Level1 interface {
|
||||
Cdotu(n int, x []complex64, incX int, y []complex64, incY int) (dotu complex64)
|
||||
Cdotc(n int, x []complex64, incX int, y []complex64, incY int) (dotc complex64)
|
||||
Scnrm2(n int, x []complex64, incX int) float32
|
||||
Scasum(n int, x []complex64, incX int) float32
|
||||
Icamax(n int, x []complex64, incX int) int
|
||||
Cswap(n int, x []complex64, incX int, y []complex64, incY int)
|
||||
Ccopy(n int, x []complex64, incX int, y []complex64, incY int)
|
||||
Caxpy(n int, alpha complex64, x []complex64, incX int, y []complex64, incY int)
|
||||
Cscal(n int, alpha complex64, x []complex64, incX int)
|
||||
Csscal(n int, alpha float32, x []complex64, incX int)
|
||||
}
|
||||
|
||||
// Complex64Level2 implements the single precision complex BLAS routines Level 2 routines.
|
||||
type Complex64Level2 interface {
|
||||
Cgemv(tA Transpose, m, n int, alpha complex64, a []complex64, lda int, x []complex64, incX int, beta complex64, y []complex64, incY int)
|
||||
Cgbmv(tA Transpose, m, n, kL, kU int, alpha complex64, a []complex64, lda int, x []complex64, incX int, beta complex64, y []complex64, incY int)
|
||||
Ctrmv(ul Uplo, tA Transpose, d Diag, n int, a []complex64, lda int, x []complex64, incX int)
|
||||
Ctbmv(ul Uplo, tA Transpose, d Diag, n, k int, a []complex64, lda int, x []complex64, incX int)
|
||||
Ctpmv(ul Uplo, tA Transpose, d Diag, n int, ap []complex64, x []complex64, incX int)
|
||||
Ctrsv(ul Uplo, tA Transpose, d Diag, n int, a []complex64, lda int, x []complex64, incX int)
|
||||
Ctbsv(ul Uplo, tA Transpose, d Diag, n, k int, a []complex64, lda int, x []complex64, incX int)
|
||||
Ctpsv(ul Uplo, tA Transpose, d Diag, n int, ap []complex64, x []complex64, incX int)
|
||||
Chemv(ul Uplo, n int, alpha complex64, a []complex64, lda int, x []complex64, incX int, beta complex64, y []complex64, incY int)
|
||||
Chbmv(ul Uplo, n, k int, alpha complex64, a []complex64, lda int, x []complex64, incX int, beta complex64, y []complex64, incY int)
|
||||
Chpmv(ul Uplo, n int, alpha complex64, ap []complex64, x []complex64, incX int, beta complex64, y []complex64, incY int)
|
||||
Cgeru(m, n int, alpha complex64, x []complex64, incX int, y []complex64, incY int, a []complex64, lda int)
|
||||
Cgerc(m, n int, alpha complex64, x []complex64, incX int, y []complex64, incY int, a []complex64, lda int)
|
||||
Cher(ul Uplo, n int, alpha float32, x []complex64, incX int, a []complex64, lda int)
|
||||
Chpr(ul Uplo, n int, alpha float32, x []complex64, incX int, a []complex64)
|
||||
Cher2(ul Uplo, n int, alpha complex64, x []complex64, incX int, y []complex64, incY int, a []complex64, lda int)
|
||||
Chpr2(ul Uplo, n int, alpha complex64, x []complex64, incX int, y []complex64, incY int, ap []complex64)
|
||||
}
|
||||
|
||||
// Complex64Level3 implements the single precision complex BLAS Level 3 routines.
|
||||
type Complex64Level3 interface {
|
||||
Cgemm(tA, tB Transpose, m, n, k int, alpha complex64, a []complex64, lda int, b []complex64, ldb int, beta complex64, c []complex64, ldc int)
|
||||
Csymm(s Side, ul Uplo, m, n int, alpha complex64, a []complex64, lda int, b []complex64, ldb int, beta complex64, c []complex64, ldc int)
|
||||
Csyrk(ul Uplo, t Transpose, n, k int, alpha complex64, a []complex64, lda int, beta complex64, c []complex64, ldc int)
|
||||
Csyr2k(ul Uplo, t Transpose, n, k int, alpha complex64, a []complex64, lda int, b []complex64, ldb int, beta complex64, c []complex64, ldc int)
|
||||
Ctrmm(s Side, ul Uplo, tA Transpose, d Diag, m, n int, alpha complex64, a []complex64, lda int, b []complex64, ldb int)
|
||||
Ctrsm(s Side, ul Uplo, tA Transpose, d Diag, m, n int, alpha complex64, a []complex64, lda int, b []complex64, ldb int)
|
||||
Chemm(s Side, ul Uplo, m, n int, alpha complex64, a []complex64, lda int, b []complex64, ldb int, beta complex64, c []complex64, ldc int)
|
||||
Cherk(ul Uplo, t Transpose, n, k int, alpha float32, a []complex64, lda int, beta float32, c []complex64, ldc int)
|
||||
Cher2k(ul Uplo, t Transpose, n, k int, alpha complex64, a []complex64, lda int, b []complex64, ldb int, beta float32, c []complex64, ldc int)
|
||||
}
|
||||
|
||||
// Complex128 implements the double precision complex BLAS routines.
|
||||
type Complex128 interface {
|
||||
Complex128Level1
|
||||
Complex128Level2
|
||||
Complex128Level3
|
||||
}
|
||||
|
||||
// Complex128Level1 implements the double precision complex BLAS Level 1 routines.
|
||||
type Complex128Level1 interface {
|
||||
Zdotu(n int, x []complex128, incX int, y []complex128, incY int) (dotu complex128)
|
||||
Zdotc(n int, x []complex128, incX int, y []complex128, incY int) (dotc complex128)
|
||||
Dznrm2(n int, x []complex128, incX int) float64
|
||||
Dzasum(n int, x []complex128, incX int) float64
|
||||
Izamax(n int, x []complex128, incX int) int
|
||||
Zswap(n int, x []complex128, incX int, y []complex128, incY int)
|
||||
Zcopy(n int, x []complex128, incX int, y []complex128, incY int)
|
||||
Zaxpy(n int, alpha complex128, x []complex128, incX int, y []complex128, incY int)
|
||||
Zscal(n int, alpha complex128, x []complex128, incX int)
|
||||
Zdscal(n int, alpha float64, x []complex128, incX int)
|
||||
}
|
||||
|
||||
// Complex128Level2 implements the double precision complex BLAS Level 2 routines.
|
||||
type Complex128Level2 interface {
|
||||
Zgemv(tA Transpose, m, n int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int)
|
||||
Zgbmv(tA Transpose, m, n int, kL int, kU int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int)
|
||||
Ztrmv(ul Uplo, tA Transpose, d Diag, n int, a []complex128, lda int, x []complex128, incX int)
|
||||
Ztbmv(ul Uplo, tA Transpose, d Diag, n, k int, a []complex128, lda int, x []complex128, incX int)
|
||||
Ztpmv(ul Uplo, tA Transpose, d Diag, n int, ap []complex128, x []complex128, incX int)
|
||||
Ztrsv(ul Uplo, tA Transpose, d Diag, n int, a []complex128, lda int, x []complex128, incX int)
|
||||
Ztbsv(ul Uplo, tA Transpose, d Diag, n, k int, a []complex128, lda int, x []complex128, incX int)
|
||||
Ztpsv(ul Uplo, tA Transpose, d Diag, n int, ap []complex128, x []complex128, incX int)
|
||||
Zhemv(ul Uplo, n int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int)
|
||||
Zhbmv(ul Uplo, n, k int, alpha complex128, a []complex128, lda int, x []complex128, incX int, beta complex128, y []complex128, incY int)
|
||||
Zhpmv(ul Uplo, n int, alpha complex128, ap []complex128, x []complex128, incX int, beta complex128, y []complex128, incY int)
|
||||
Zgeru(m, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int)
|
||||
Zgerc(m, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int)
|
||||
Zher(ul Uplo, n int, alpha float64, x []complex128, incX int, a []complex128, lda int)
|
||||
Zhpr(ul Uplo, n int, alpha float64, x []complex128, incX int, a []complex128)
|
||||
Zher2(ul Uplo, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, a []complex128, lda int)
|
||||
Zhpr2(ul Uplo, n int, alpha complex128, x []complex128, incX int, y []complex128, incY int, ap []complex128)
|
||||
}
|
||||
|
||||
// Complex128Level3 implements the double precision complex BLAS Level 3 routines.
|
||||
type Complex128Level3 interface {
|
||||
Zgemm(tA, tB Transpose, m, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int)
|
||||
Zsymm(s Side, ul Uplo, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int)
|
||||
Zsyrk(ul Uplo, t Transpose, n, k int, alpha complex128, a []complex128, lda int, beta complex128, c []complex128, ldc int)
|
||||
Zsyr2k(ul Uplo, t Transpose, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int)
|
||||
Ztrmm(s Side, ul Uplo, tA Transpose, d Diag, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int)
|
||||
Ztrsm(s Side, ul Uplo, tA Transpose, d Diag, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int)
|
||||
Zhemm(s Side, ul Uplo, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int)
|
||||
Zherk(ul Uplo, t Transpose, n, k int, alpha float64, a []complex128, lda int, beta float64, c []complex128, ldc int)
|
||||
Zher2k(ul Uplo, t Transpose, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta float64, c []complex128, ldc int)
|
||||
}
|
||||
+434
@@ -0,0 +1,434 @@
|
||||
// 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 blas64 provides a simple interface to the float64 BLAS API.
|
||||
package blas64
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/blas/native"
|
||||
)
|
||||
|
||||
var blas64 blas.Float64 = native.Implementation{}
|
||||
|
||||
// Use sets the BLAS float64 implementation to be used by subsequent BLAS calls.
|
||||
// The default implementation is native.Implementation.
|
||||
func Use(b blas.Float64) {
|
||||
blas64 = b
|
||||
}
|
||||
|
||||
// Implementation returns the current BLAS float64 implementation.
|
||||
//
|
||||
// Implementation allows direct calls to the current the BLAS float64 implementation
|
||||
// giving finer control of parameters.
|
||||
func Implementation() blas.Float64 {
|
||||
return blas64
|
||||
}
|
||||
|
||||
// Vector represents a vector with an associated element increment.
|
||||
type Vector struct {
|
||||
Inc int
|
||||
Data []float64
|
||||
}
|
||||
|
||||
// General represents a matrix using the conventional storage scheme.
|
||||
type General struct {
|
||||
Rows, Cols int
|
||||
Stride int
|
||||
Data []float64
|
||||
}
|
||||
|
||||
// Band represents a band matrix using the band storage scheme.
|
||||
type Band struct {
|
||||
Rows, Cols int
|
||||
KL, KU int
|
||||
Stride int
|
||||
Data []float64
|
||||
}
|
||||
|
||||
// Triangular represents a triangular matrix using the conventional storage scheme.
|
||||
type Triangular struct {
|
||||
N int
|
||||
Stride int
|
||||
Data []float64
|
||||
Uplo blas.Uplo
|
||||
Diag blas.Diag
|
||||
}
|
||||
|
||||
// TriangularBand represents a triangular matrix using the band storage scheme.
|
||||
type TriangularBand struct {
|
||||
N, K int
|
||||
Stride int
|
||||
Data []float64
|
||||
Uplo blas.Uplo
|
||||
Diag blas.Diag
|
||||
}
|
||||
|
||||
// TriangularPacked represents a triangular matrix using the packed storage scheme.
|
||||
type TriangularPacked struct {
|
||||
N int
|
||||
Data []float64
|
||||
Uplo blas.Uplo
|
||||
Diag blas.Diag
|
||||
}
|
||||
|
||||
// Symmetric represents a symmetric matrix using the conventional storage scheme.
|
||||
type Symmetric struct {
|
||||
N int
|
||||
Stride int
|
||||
Data []float64
|
||||
Uplo blas.Uplo
|
||||
}
|
||||
|
||||
// SymmetricBand represents a symmetric matrix using the band storage scheme.
|
||||
type SymmetricBand struct {
|
||||
N, K int
|
||||
Stride int
|
||||
Data []float64
|
||||
Uplo blas.Uplo
|
||||
}
|
||||
|
||||
// SymmetricPacked represents a symmetric matrix using the packed storage scheme.
|
||||
type SymmetricPacked struct {
|
||||
N int
|
||||
Data []float64
|
||||
Uplo blas.Uplo
|
||||
}
|
||||
|
||||
// Level 1
|
||||
|
||||
const negInc = "blas64: negative vector increment"
|
||||
|
||||
// Dot computes the dot product of the two vectors
|
||||
// \sum_i x[i]*y[i]
|
||||
func Dot(n int, x, y Vector) float64 {
|
||||
return blas64.Ddot(n, x.Data, x.Inc, y.Data, y.Inc)
|
||||
}
|
||||
|
||||
// Nrm2 computes the Euclidean norm of a vector,
|
||||
// sqrt(\sum_i x[i] * x[i]).
|
||||
//
|
||||
// Nrm2 will panic if the vector increment is negative.
|
||||
func Nrm2(n int, x Vector) float64 {
|
||||
if x.Inc < 0 {
|
||||
panic(negInc)
|
||||
}
|
||||
return blas64.Dnrm2(n, x.Data, x.Inc)
|
||||
}
|
||||
|
||||
// Asum computes the sum of the absolute values of the elements of x.
|
||||
// \sum_i |x[i]|
|
||||
//
|
||||
// Asum will panic if the vector increment is negative.
|
||||
func Asum(n int, x Vector) float64 {
|
||||
if x.Inc < 0 {
|
||||
panic(negInc)
|
||||
}
|
||||
return blas64.Dasum(n, x.Data, x.Inc)
|
||||
}
|
||||
|
||||
// Iamax returns the index of the largest element of x. If there are multiple
|
||||
// such indices the earliest is returned. Iamax returns -1 if n == 0.
|
||||
//
|
||||
// Iamax will panic if the vector increment is negative.
|
||||
func Iamax(n int, x Vector) int {
|
||||
if x.Inc < 0 {
|
||||
panic(negInc)
|
||||
}
|
||||
return blas64.Idamax(n, x.Data, x.Inc)
|
||||
}
|
||||
|
||||
// Swap exchanges the elements of two vectors.
|
||||
// x[i], y[i] = y[i], x[i] for all i
|
||||
func Swap(n int, x, y Vector) {
|
||||
blas64.Dswap(n, x.Data, x.Inc, y.Data, y.Inc)
|
||||
}
|
||||
|
||||
// Copy copies the elements of x into the elements of y.
|
||||
// y[i] = x[i] for all i
|
||||
func Copy(n int, x, y Vector) {
|
||||
blas64.Dcopy(n, x.Data, x.Inc, y.Data, y.Inc)
|
||||
}
|
||||
|
||||
// Axpy adds alpha times x to y
|
||||
// y[i] += alpha * x[i] for all i
|
||||
func Axpy(n int, alpha float64, x, y Vector) {
|
||||
blas64.Daxpy(n, alpha, x.Data, x.Inc, y.Data, y.Inc)
|
||||
}
|
||||
|
||||
// Rotg computes the plane rotation
|
||||
// _ _ _ _ _ _
|
||||
// | c s | | a | | r |
|
||||
// | -s c | * | b | = | 0 |
|
||||
// ‾ ‾ ‾ ‾ ‾ ‾
|
||||
// where
|
||||
// r = ±(a^2 + b^2)
|
||||
// c = a/r, the cosine of the plane rotation
|
||||
// s = b/r, the sine of the plane rotation
|
||||
func Rotg(a, b float64) (c, s, r, z float64) {
|
||||
return blas64.Drotg(a, b)
|
||||
}
|
||||
|
||||
// Rotmg computes the modified Givens rotation. See
|
||||
// http://www.netlib.org/lapack/explore-html/df/deb/drotmg_8f.html
|
||||
// for more details.
|
||||
func Rotmg(d1, d2, b1, b2 float64) (p blas.DrotmParams, rd1, rd2, rb1 float64) {
|
||||
return blas64.Drotmg(d1, d2, b1, b2)
|
||||
}
|
||||
|
||||
// Rot applies a plane transformation.
|
||||
// x[i] = c * x[i] + s * y[i]
|
||||
// y[i] = c * y[i] - s * x[i]
|
||||
func Rot(n int, x, y Vector, c, s float64) {
|
||||
blas64.Drot(n, x.Data, x.Inc, y.Data, y.Inc, c, s)
|
||||
}
|
||||
|
||||
// Rotm applies the modified Givens rotation to the 2×n matrix.
|
||||
func Rotm(n int, x, y Vector, p blas.DrotmParams) {
|
||||
blas64.Drotm(n, x.Data, x.Inc, y.Data, y.Inc, p)
|
||||
}
|
||||
|
||||
// Scal scales x by alpha.
|
||||
// x[i] *= alpha
|
||||
//
|
||||
// Scal will panic if the vector increment is negative
|
||||
func Scal(n int, alpha float64, x Vector) {
|
||||
if x.Inc < 0 {
|
||||
panic(negInc)
|
||||
}
|
||||
blas64.Dscal(n, alpha, x.Data, x.Inc)
|
||||
}
|
||||
|
||||
// Level 2
|
||||
|
||||
// Gemv computes
|
||||
// y = alpha * a * x + beta * y if tA = blas.NoTrans
|
||||
// y = alpha * A^T * x + beta * y if tA = blas.Trans or blas.ConjTrans
|
||||
// where A is an m×n dense matrix, x and y are vectors, and alpha is a scalar.
|
||||
func Gemv(tA blas.Transpose, alpha float64, a General, x Vector, beta float64, y Vector) {
|
||||
blas64.Dgemv(tA, a.Rows, a.Cols, alpha, a.Data, a.Stride, x.Data, x.Inc, beta, y.Data, y.Inc)
|
||||
}
|
||||
|
||||
// Gbmv computes
|
||||
// y = alpha * A * x + beta * y if tA == blas.NoTrans
|
||||
// y = alpha * A^T * x + beta * y if tA == blas.Trans or blas.ConjTrans
|
||||
// where a is an m×n band matrix kL subdiagonals and kU super-diagonals, and
|
||||
// m and n refer to the size of the full dense matrix it represents.
|
||||
// x and y are vectors, and alpha and beta are scalars.
|
||||
func Gbmv(tA blas.Transpose, alpha float64, a Band, x Vector, beta float64, y Vector) {
|
||||
blas64.Dgbmv(tA, a.Rows, a.Cols, a.KL, a.KU, alpha, a.Data, a.Stride, x.Data, x.Inc, beta, y.Data, y.Inc)
|
||||
}
|
||||
|
||||
// Trmv computes
|
||||
// x = A * x if tA == blas.NoTrans
|
||||
// x = A^T * x if tA == blas.Trans or blas.ConjTrans
|
||||
// A is an n×n Triangular matrix and x is a vector.
|
||||
func Trmv(tA blas.Transpose, a Triangular, x Vector) {
|
||||
blas64.Dtrmv(a.Uplo, tA, a.Diag, a.N, a.Data, a.Stride, x.Data, x.Inc)
|
||||
}
|
||||
|
||||
// Tbmv computes
|
||||
// x = A * x if tA == blas.NoTrans
|
||||
// x = A^T * x if tA == blas.Trans or blas.ConjTrans
|
||||
// where A is an n×n triangular banded matrix with k diagonals, and x is a vector.
|
||||
func Tbmv(tA blas.Transpose, a TriangularBand, x Vector) {
|
||||
blas64.Dtbmv(a.Uplo, tA, a.Diag, a.N, a.K, a.Data, a.Stride, x.Data, x.Inc)
|
||||
}
|
||||
|
||||
// Tpmv computes
|
||||
// x = A * x if tA == blas.NoTrans
|
||||
// x = A^T * x if tA == blas.Trans or blas.ConjTrans
|
||||
// where A is an n×n unit triangular matrix in packed format, and x is a vector.
|
||||
func Tpmv(tA blas.Transpose, a TriangularPacked, x Vector) {
|
||||
blas64.Dtpmv(a.Uplo, tA, a.Diag, a.N, a.Data, x.Data, x.Inc)
|
||||
}
|
||||
|
||||
// Trsv solves
|
||||
// A * x = b if tA == blas.NoTrans
|
||||
// A^T * x = b if tA == blas.Trans or blas.ConjTrans
|
||||
// A is an n×n triangular matrix and x is a vector.
|
||||
// At entry to the function, x contains the values of b, and the result is
|
||||
// stored in place into x.
|
||||
//
|
||||
// No test for singularity or near-singularity is included in this
|
||||
// routine. Such tests must be performed before calling this routine.
|
||||
func Trsv(tA blas.Transpose, a Triangular, x Vector) {
|
||||
blas64.Dtrsv(a.Uplo, tA, a.Diag, a.N, a.Data, a.Stride, x.Data, x.Inc)
|
||||
}
|
||||
|
||||
// Tbsv solves
|
||||
// A * x = b
|
||||
// where A is an n×n triangular banded matrix with k diagonals in packed format,
|
||||
// and x is a vector.
|
||||
// At entry to the function, x contains the values of b, and the result is
|
||||
// stored in place into x.
|
||||
//
|
||||
// No test for singularity or near-singularity is included in this
|
||||
// routine. Such tests must be performed before calling this routine.
|
||||
func Tbsv(tA blas.Transpose, a TriangularBand, x Vector) {
|
||||
blas64.Dtbsv(a.Uplo, tA, a.Diag, a.N, a.K, a.Data, a.Stride, x.Data, x.Inc)
|
||||
}
|
||||
|
||||
// Tpsv solves
|
||||
// A * x = b if tA == blas.NoTrans
|
||||
// A^T * x = b if tA == blas.Trans or blas.ConjTrans
|
||||
// where A is an n×n triangular matrix in packed format and x is a vector.
|
||||
// At entry to the function, x contains the values of b, and the result is
|
||||
// stored in place into x.
|
||||
//
|
||||
// No test for singularity or near-singularity is included in this
|
||||
// routine. Such tests must be performed before calling this routine.
|
||||
func Tpsv(tA blas.Transpose, a TriangularPacked, x Vector) {
|
||||
blas64.Dtpsv(a.Uplo, tA, a.Diag, a.N, a.Data, x.Data, x.Inc)
|
||||
}
|
||||
|
||||
// Symv computes
|
||||
// y = alpha * A * x + beta * y,
|
||||
// where a is an n×n symmetric matrix, x and y are vectors, and alpha and
|
||||
// beta are scalars.
|
||||
func Symv(alpha float64, a Symmetric, x Vector, beta float64, y Vector) {
|
||||
blas64.Dsymv(a.Uplo, a.N, alpha, a.Data, a.Stride, x.Data, x.Inc, beta, y.Data, y.Inc)
|
||||
}
|
||||
|
||||
// Sbmv performs
|
||||
// y = alpha * A * x + beta * y
|
||||
// where A is an n×n symmetric banded matrix, x and y are vectors, and alpha
|
||||
// and beta are scalars.
|
||||
func Sbmv(alpha float64, a SymmetricBand, x Vector, beta float64, y Vector) {
|
||||
blas64.Dsbmv(a.Uplo, a.N, a.K, alpha, a.Data, a.Stride, x.Data, x.Inc, beta, y.Data, y.Inc)
|
||||
}
|
||||
|
||||
// Spmv performs
|
||||
// y = alpha * A * x + beta * y,
|
||||
// where A is an n×n symmetric matrix in packed format, x and y are vectors
|
||||
// and alpha and beta are scalars.
|
||||
func Spmv(alpha float64, a SymmetricPacked, x Vector, beta float64, y Vector) {
|
||||
blas64.Dspmv(a.Uplo, a.N, alpha, a.Data, x.Data, x.Inc, beta, y.Data, y.Inc)
|
||||
}
|
||||
|
||||
// Ger performs the rank-one operation
|
||||
// A += alpha * x * y^T
|
||||
// where A is an m×n dense matrix, x and y are vectors, and alpha is a scalar.
|
||||
func Ger(alpha float64, x, y Vector, a General) {
|
||||
blas64.Dger(a.Rows, a.Cols, alpha, x.Data, x.Inc, y.Data, y.Inc, a.Data, a.Stride)
|
||||
}
|
||||
|
||||
// Syr performs the rank-one update
|
||||
// a += alpha * x * x^T
|
||||
// where a is an n×n symmetric matrix, and x is a vector.
|
||||
func Syr(alpha float64, x Vector, a Symmetric) {
|
||||
blas64.Dsyr(a.Uplo, a.N, alpha, x.Data, x.Inc, a.Data, a.Stride)
|
||||
}
|
||||
|
||||
// Spr computes the rank-one operation
|
||||
// a += alpha * x * x^T
|
||||
// where a is an n×n symmetric matrix in packed format, x is a vector, and
|
||||
// alpha is a scalar.
|
||||
func Spr(alpha float64, x Vector, a SymmetricPacked) {
|
||||
blas64.Dspr(a.Uplo, a.N, alpha, x.Data, x.Inc, a.Data)
|
||||
}
|
||||
|
||||
// Syr2 performs the symmetric rank-two update
|
||||
// A += alpha * x * y^T + alpha * y * x^T
|
||||
// where A is a symmetric n×n matrix, x and y are vectors, and alpha is a scalar.
|
||||
func Syr2(alpha float64, x, y Vector, a Symmetric) {
|
||||
blas64.Dsyr2(a.Uplo, a.N, alpha, x.Data, x.Inc, y.Data, y.Inc, a.Data, a.Stride)
|
||||
}
|
||||
|
||||
// Spr2 performs the symmetric rank-2 update
|
||||
// a += alpha * x * y^T + alpha * y * x^T
|
||||
// where a is an n×n symmetric matirx in packed format and x and y are vectors.
|
||||
func Spr2(alpha float64, x, y Vector, a SymmetricPacked) {
|
||||
blas64.Dspr2(a.Uplo, a.N, alpha, x.Data, x.Inc, y.Data, y.Inc, a.Data)
|
||||
}
|
||||
|
||||
// Level 3
|
||||
|
||||
// Gemm computes
|
||||
// C = beta * C + alpha * A * B.
|
||||
// tA and tB specify whether A or B are transposed. A, B, and C are m×n dense
|
||||
// matrices.
|
||||
func Gemm(tA, tB blas.Transpose, alpha float64, a, b General, beta float64, c General) {
|
||||
var m, n, k int
|
||||
if tA == blas.NoTrans {
|
||||
m, k = a.Rows, a.Cols
|
||||
} else {
|
||||
m, k = a.Cols, a.Rows
|
||||
}
|
||||
if tB == blas.NoTrans {
|
||||
n = b.Cols
|
||||
} else {
|
||||
n = b.Rows
|
||||
}
|
||||
blas64.Dgemm(tA, tB, m, n, k, alpha, a.Data, a.Stride, b.Data, b.Stride, beta, c.Data, c.Stride)
|
||||
}
|
||||
|
||||
// Symm performs one of
|
||||
// C = alpha * A * B + beta * C if side == blas.Left
|
||||
// C = alpha * B * A + beta * C if side == blas.Right
|
||||
// where A is an n×n symmetric matrix, B and C are m×n matrices, and alpha
|
||||
// is a scalar.
|
||||
func Symm(s blas.Side, alpha float64, a Symmetric, b General, beta float64, c General) {
|
||||
var m, n int
|
||||
if s == blas.Left {
|
||||
m, n = a.N, b.Cols
|
||||
} else {
|
||||
m, n = b.Rows, a.N
|
||||
}
|
||||
blas64.Dsymm(s, a.Uplo, m, n, alpha, a.Data, a.Stride, b.Data, b.Stride, beta, c.Data, c.Stride)
|
||||
}
|
||||
|
||||
// Syrk performs the symmetric rank-k operation
|
||||
// C = alpha * A * A^T + beta*C
|
||||
// C is an n×n symmetric matrix. A is an n×k matrix if tA == blas.NoTrans, and
|
||||
// a k×n matrix otherwise. alpha and beta are scalars.
|
||||
func Syrk(t blas.Transpose, alpha float64, a General, beta float64, c Symmetric) {
|
||||
var n, k int
|
||||
if t == blas.NoTrans {
|
||||
n, k = a.Rows, a.Cols
|
||||
} else {
|
||||
n, k = a.Cols, a.Rows
|
||||
}
|
||||
blas64.Dsyrk(c.Uplo, t, n, k, alpha, a.Data, a.Stride, beta, c.Data, c.Stride)
|
||||
}
|
||||
|
||||
// Syr2k performs the symmetric rank 2k operation
|
||||
// C = alpha * A * B^T + alpha * B * A^T + beta * C
|
||||
// where C is an n×n symmetric matrix. A and B are n×k matrices if
|
||||
// tA == NoTrans and k×n otherwise. alpha and beta are scalars.
|
||||
func Syr2k(t blas.Transpose, alpha float64, a, b General, beta float64, c Symmetric) {
|
||||
var n, k int
|
||||
if t == blas.NoTrans {
|
||||
n, k = a.Rows, a.Cols
|
||||
} else {
|
||||
n, k = a.Cols, a.Rows
|
||||
}
|
||||
blas64.Dsyr2k(c.Uplo, t, n, k, alpha, a.Data, a.Stride, b.Data, b.Stride, beta, c.Data, c.Stride)
|
||||
}
|
||||
|
||||
// Trmm performs
|
||||
// B = alpha * A * B if tA == blas.NoTrans and side == blas.Left
|
||||
// B = alpha * A^T * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Left
|
||||
// B = alpha * B * A if tA == blas.NoTrans and side == blas.Right
|
||||
// B = alpha * B * A^T if tA == blas.Trans or blas.ConjTrans, and side == blas.Right
|
||||
// where A is an n×n triangular matrix, and B is an m×n matrix.
|
||||
func Trmm(s blas.Side, tA blas.Transpose, alpha float64, a Triangular, b General) {
|
||||
blas64.Dtrmm(s, a.Uplo, tA, a.Diag, b.Rows, b.Cols, alpha, a.Data, a.Stride, b.Data, b.Stride)
|
||||
}
|
||||
|
||||
// Trsm solves
|
||||
// A * X = alpha * B if tA == blas.NoTrans side == blas.Left
|
||||
// A^T * X = alpha * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Left
|
||||
// X * A = alpha * B if tA == blas.NoTrans side == blas.Right
|
||||
// X * A^T = alpha * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Right
|
||||
// where A is an n×n triangular matrix, x is an m×n matrix, and alpha is a
|
||||
// scalar.
|
||||
//
|
||||
// At entry to the function, X contains the values of B, and the result is
|
||||
// stored in place into X.
|
||||
//
|
||||
// No check is made that A is invertible.
|
||||
func Trsm(s blas.Side, tA blas.Transpose, alpha float64, a Triangular, b General) {
|
||||
blas64.Dtrsm(s, a.Uplo, tA, a.Diag, b.Rows, b.Cols, alpha, a.Data, a.Stride, b.Data, b.Stride)
|
||||
}
|
||||
+391
@@ -0,0 +1,391 @@
|
||||
// Copyright ©2014 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 native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/internal/asm"
|
||||
)
|
||||
|
||||
// Dgemm computes
|
||||
// C = beta * C + alpha * A * B.
|
||||
// tA and tB specify whether A or B are transposed. A, B, and C are m×n dense
|
||||
// matrices.
|
||||
func (Implementation) Dgemm(tA, tB blas.Transpose, m, n, k int, alpha float64, a []float64, lda int, b []float64, ldb int, beta float64, c []float64, ldc int) {
|
||||
if tA != blas.NoTrans && tA != blas.Trans && tA != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
if tB != blas.NoTrans && tB != blas.Trans && tB != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
|
||||
var amat, bmat, cmat general64
|
||||
if tA != blas.NoTrans {
|
||||
amat = general64{
|
||||
data: a,
|
||||
rows: k,
|
||||
cols: m,
|
||||
stride: lda,
|
||||
}
|
||||
} else {
|
||||
amat = general64{
|
||||
data: a,
|
||||
rows: m,
|
||||
cols: k,
|
||||
stride: lda,
|
||||
}
|
||||
}
|
||||
err := amat.check('a')
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
if tB != blas.NoTrans {
|
||||
bmat = general64{
|
||||
data: b,
|
||||
rows: n,
|
||||
cols: k,
|
||||
stride: ldb,
|
||||
}
|
||||
} else {
|
||||
bmat = general64{
|
||||
data: b,
|
||||
rows: k,
|
||||
cols: n,
|
||||
stride: ldb,
|
||||
}
|
||||
}
|
||||
|
||||
err = bmat.check('b')
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
cmat = general64{
|
||||
data: c,
|
||||
rows: m,
|
||||
cols: n,
|
||||
stride: ldc,
|
||||
}
|
||||
err = cmat.check('c')
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
// scale c
|
||||
if beta != 1 {
|
||||
if beta == 0 {
|
||||
for i := 0; i < m; i++ {
|
||||
ctmp := cmat.data[i*cmat.stride : i*cmat.stride+cmat.cols]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < m; i++ {
|
||||
ctmp := cmat.data[i*cmat.stride : i*cmat.stride+cmat.cols]
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dgemmParallel(tA, tB, amat, bmat, cmat, alpha)
|
||||
}
|
||||
|
||||
func dgemmParallel(tA, tB blas.Transpose, a, b, c general64, alpha float64) {
|
||||
// dgemmParallel computes a parallel matrix multiplication by partitioning
|
||||
// a and b into sub-blocks, and updating c with the multiplication of the sub-block
|
||||
// In all cases,
|
||||
// A = [ A_11 A_12 ... A_1j
|
||||
// A_21 A_22 ... A_2j
|
||||
// ...
|
||||
// A_i1 A_i2 ... A_ij]
|
||||
//
|
||||
// and same for B. All of the submatrix sizes are blockSize*blockSize except
|
||||
// at the edges.
|
||||
// In all cases, there is one dimension for each matrix along which
|
||||
// C must be updated sequentially.
|
||||
// Cij = \sum_k Aik Bki, (A * B)
|
||||
// Cij = \sum_k Aki Bkj, (A^T * B)
|
||||
// Cij = \sum_k Aik Bjk, (A * B^T)
|
||||
// Cij = \sum_k Aki Bjk, (A^T * B^T)
|
||||
//
|
||||
// This code computes one {i, j} block sequentially along the k dimension,
|
||||
// and computes all of the {i, j} blocks concurrently. This
|
||||
// partitioning allows Cij to be updated in-place without race-conditions.
|
||||
// Instead of launching a goroutine for each possible concurrent computation,
|
||||
// a number of worker goroutines are created and channels are used to pass
|
||||
// available and completed cases.
|
||||
//
|
||||
// http://alexkr.com/docs/matrixmult.pdf is a good reference on matrix-matrix
|
||||
// multiplies, though this code does not copy matrices to attempt to eliminate
|
||||
// cache misses.
|
||||
|
||||
aTrans := tA == blas.Trans || tA == blas.ConjTrans
|
||||
bTrans := tB == blas.Trans || tB == blas.ConjTrans
|
||||
|
||||
maxKLen, parBlocks := computeNumBlocks64(a, b, aTrans, bTrans)
|
||||
if parBlocks < minParBlock {
|
||||
// The matrix multiplication is small in the dimensions where it can be
|
||||
// computed concurrently. Just do it in serial.
|
||||
dgemmSerial(tA, tB, a, b, c, alpha)
|
||||
return
|
||||
}
|
||||
|
||||
nWorkers := runtime.GOMAXPROCS(0)
|
||||
if parBlocks < nWorkers {
|
||||
nWorkers = parBlocks
|
||||
}
|
||||
// There is a tradeoff between the workers having to wait for work
|
||||
// and a large buffer making operations slow.
|
||||
buf := buffMul * nWorkers
|
||||
if buf > parBlocks {
|
||||
buf = parBlocks
|
||||
}
|
||||
|
||||
sendChan := make(chan subMul, buf)
|
||||
|
||||
// Launch workers. A worker receives an {i, j} submatrix of c, and computes
|
||||
// A_ik B_ki (or the transposed version) storing the result in c_ij. When the
|
||||
// channel is finally closed, it signals to the waitgroup that it has finished
|
||||
// computing.
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < nWorkers; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
// Make local copies of otherwise global variables to reduce shared memory.
|
||||
// This has a noticable effect on benchmarks in some cases.
|
||||
alpha := alpha
|
||||
aTrans := aTrans
|
||||
bTrans := bTrans
|
||||
crows := c.rows
|
||||
ccols := c.cols
|
||||
for sub := range sendChan {
|
||||
i := sub.i
|
||||
j := sub.j
|
||||
leni := blockSize
|
||||
if i+leni > crows {
|
||||
leni = crows - i
|
||||
}
|
||||
lenj := blockSize
|
||||
if j+lenj > ccols {
|
||||
lenj = ccols - j
|
||||
}
|
||||
cSub := c.view(i, j, leni, lenj)
|
||||
|
||||
// Compute A_ik B_kj for all k
|
||||
for k := 0; k < maxKLen; k += blockSize {
|
||||
lenk := blockSize
|
||||
if k+lenk > maxKLen {
|
||||
lenk = maxKLen - k
|
||||
}
|
||||
var aSub, bSub general64
|
||||
if aTrans {
|
||||
aSub = a.view(k, i, lenk, leni)
|
||||
} else {
|
||||
aSub = a.view(i, k, leni, lenk)
|
||||
}
|
||||
if bTrans {
|
||||
bSub = b.view(j, k, lenj, lenk)
|
||||
} else {
|
||||
bSub = b.view(k, j, lenk, lenj)
|
||||
}
|
||||
|
||||
dgemmSerial(tA, tB, aSub, bSub, cSub, alpha)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Send out all of the {i, j} subblocks for computation.
|
||||
for i := 0; i < c.rows; i += blockSize {
|
||||
for j := 0; j < c.cols; j += blockSize {
|
||||
sendChan <- subMul{
|
||||
i: i,
|
||||
j: j,
|
||||
}
|
||||
}
|
||||
}
|
||||
close(sendChan)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// computeNumBlocks says how many blocks there are to compute. maxKLen says the length of the
|
||||
// k dimension, parBlocks is the number of blocks that could be computed in parallel
|
||||
// (the submatrices in i and j). expect is the full number of blocks that will be computed.
|
||||
func computeNumBlocks64(a, b general64, aTrans, bTrans bool) (maxKLen, parBlocks int) {
|
||||
aRowBlocks := a.rows / blockSize
|
||||
if a.rows%blockSize != 0 {
|
||||
aRowBlocks++
|
||||
}
|
||||
aColBlocks := a.cols / blockSize
|
||||
if a.cols%blockSize != 0 {
|
||||
aColBlocks++
|
||||
}
|
||||
bRowBlocks := b.rows / blockSize
|
||||
if b.rows%blockSize != 0 {
|
||||
bRowBlocks++
|
||||
}
|
||||
bColBlocks := b.cols / blockSize
|
||||
if b.cols%blockSize != 0 {
|
||||
bColBlocks++
|
||||
}
|
||||
|
||||
switch {
|
||||
case !aTrans && !bTrans:
|
||||
// Cij = \sum_k Aik Bki
|
||||
maxKLen = a.cols
|
||||
parBlocks = aRowBlocks * bColBlocks
|
||||
case aTrans && !bTrans:
|
||||
// Cij = \sum_k Aki Bkj
|
||||
maxKLen = a.rows
|
||||
parBlocks = aColBlocks * bColBlocks
|
||||
case !aTrans && bTrans:
|
||||
// Cij = \sum_k Aik Bjk
|
||||
maxKLen = a.cols
|
||||
parBlocks = aRowBlocks * bRowBlocks
|
||||
case aTrans && bTrans:
|
||||
// Cij = \sum_k Aki Bjk
|
||||
maxKLen = a.rows
|
||||
parBlocks = aColBlocks * bRowBlocks
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// dgemmSerial is serial matrix multiply
|
||||
func dgemmSerial(tA, tB blas.Transpose, a, b, c general64, alpha float64) {
|
||||
switch {
|
||||
case tA == blas.NoTrans && tB == blas.NoTrans:
|
||||
dgemmSerialNotNot(a, b, c, alpha)
|
||||
return
|
||||
case tA != blas.NoTrans && tB == blas.NoTrans:
|
||||
dgemmSerialTransNot(a, b, c, alpha)
|
||||
return
|
||||
case tA == blas.NoTrans && tB != blas.NoTrans:
|
||||
dgemmSerialNotTrans(a, b, c, alpha)
|
||||
return
|
||||
case tA != blas.NoTrans && tB != blas.NoTrans:
|
||||
dgemmSerialTransTrans(a, b, c, alpha)
|
||||
return
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// dgemmSerial where neither a nor b are transposed
|
||||
func dgemmSerialNotNot(a, b, c general64, alpha float64) {
|
||||
if debug {
|
||||
if a.cols != b.rows {
|
||||
panic("inner dimension mismatch")
|
||||
}
|
||||
if a.rows != c.rows {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
if b.cols != c.cols {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
// This style is used instead of the literal [i*stride +j]) is used because
|
||||
// approximately 5 times faster as of go 1.3.
|
||||
for i := 0; i < a.rows; i++ {
|
||||
ctmp := c.data[i*c.stride : i*c.stride+c.cols]
|
||||
for l, v := range a.data[i*a.stride : i*a.stride+a.cols] {
|
||||
tmp := alpha * v
|
||||
if tmp != 0 {
|
||||
asm.DaxpyUnitary(tmp, b.data[l*b.stride:l*b.stride+b.cols], ctmp, ctmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dgemmSerial where neither a is transposed and b is not
|
||||
func dgemmSerialTransNot(a, b, c general64, alpha float64) {
|
||||
if debug {
|
||||
if a.rows != b.rows {
|
||||
fmt.Println(a.rows, b.rows)
|
||||
panic("inner dimension mismatch")
|
||||
}
|
||||
if a.cols != c.rows {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
if b.cols != c.cols {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
// This style is used instead of the literal [i*stride +j]) is used because
|
||||
// approximately 5 times faster as of go 1.3.
|
||||
for l := 0; l < a.rows; l++ {
|
||||
btmp := b.data[l*b.stride : l*b.stride+b.cols]
|
||||
for i, v := range a.data[l*a.stride : l*a.stride+a.cols] {
|
||||
tmp := alpha * v
|
||||
ctmp := c.data[i*c.stride : i*c.stride+c.cols]
|
||||
if tmp != 0 {
|
||||
asm.DaxpyUnitary(tmp, btmp, ctmp, ctmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dgemmSerial where neither a is not transposed and b is
|
||||
func dgemmSerialNotTrans(a, b, c general64, alpha float64) {
|
||||
if debug {
|
||||
if a.cols != b.cols {
|
||||
panic("inner dimension mismatch")
|
||||
}
|
||||
if a.rows != c.rows {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
if b.rows != c.cols {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
// This style is used instead of the literal [i*stride +j]) is used because
|
||||
// approximately 5 times faster as of go 1.3.
|
||||
for i := 0; i < a.rows; i++ {
|
||||
atmp := a.data[i*a.stride : i*a.stride+a.cols]
|
||||
ctmp := c.data[i*c.stride : i*c.stride+c.cols]
|
||||
for j := 0; j < b.rows; j++ {
|
||||
ctmp[j] += alpha * asm.DdotUnitary(atmp, b.data[j*b.stride:j*b.stride+b.cols])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// dgemmSerial where both are transposed
|
||||
func dgemmSerialTransTrans(a, b, c general64, alpha float64) {
|
||||
if debug {
|
||||
if a.rows != b.cols {
|
||||
panic("inner dimension mismatch")
|
||||
}
|
||||
if a.cols != c.rows {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
if b.rows != c.cols {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
// This style is used instead of the literal [i*stride +j]) is used because
|
||||
// approximately 5 times faster as of go 1.3.
|
||||
for l := 0; l < a.rows; l++ {
|
||||
for i, v := range a.data[l*a.stride : l*a.stride+a.cols] {
|
||||
ctmp := c.data[i*c.stride : i*c.stride+c.cols]
|
||||
if v != 0 {
|
||||
tmp := alpha * v
|
||||
if tmp != 0 {
|
||||
asm.DaxpyInc(tmp, b.data[l:], ctmp, uintptr(b.rows), uintptr(b.stride), 1, 0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
// 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.
|
||||
|
||||
// Ensure changes made to blas/native are reflected in blas/cgo where relevant.
|
||||
|
||||
/*
|
||||
Package native is a Go implementation of the BLAS API. This implementation
|
||||
panics when the input arguments are invalid as per the standard, for example
|
||||
if a vector increment is zero. Please note that the treatment of NaN values
|
||||
is not specified, and differs among the BLAS implementations.
|
||||
github.com/gonum/blas/blas64 provides helpful wrapper functions to the BLAS
|
||||
interface. The rest of this text describes the layout of the data for the input types.
|
||||
|
||||
Please note that in the function documentation, x[i] refers to the i^th element
|
||||
of the vector, which will be different from the i^th element of the slice if
|
||||
incX != 1.
|
||||
|
||||
See http://www.netlib.org/lapack/explore-html/d4/de1/_l_i_c_e_n_s_e_source.html
|
||||
for more license information.
|
||||
|
||||
Vector arguments are effectively strided slices. They have two input arguments,
|
||||
a number of elements, n, and an increment, incX. The increment specifies the
|
||||
distance between elements of the vector. The actual Go slice may be longer
|
||||
than necessary.
|
||||
The increment may be positive or negative, except in functions with only
|
||||
a single vector argument where the increment may only be positive. If the increment
|
||||
is negative, s[0] is the last element in the slice. Note that this is not the same
|
||||
as counting backward from the end of the slice, as len(s) may be longer than
|
||||
necessary. So, for example, if n = 5 and incX = 3, the elements of s are
|
||||
[0 * * 1 * * 2 * * 3 * * 4 * * * ...]
|
||||
where ∗ elements are never accessed. If incX = -3, the same elements are
|
||||
accessed, just in reverse order (4, 3, 2, 1, 0).
|
||||
|
||||
Dense matrices are specified by a number of rows, a number of columns, and a stride.
|
||||
The stride specifies the number of entries in the slice between the first element
|
||||
of successive rows. The stride must be at least as large as the number of columns
|
||||
but may be longer.
|
||||
[a00 ... a0n a0* ... a1stride-1 a21 ... amn am* ... amstride-1]
|
||||
Thus, dense[i*ld + j] refers to the {i, j}th element of the matrix.
|
||||
|
||||
Symmetric and triangular matrices (non-packed) are stored identically to Dense,
|
||||
except that only elements in one triangle of the matrix are accessed.
|
||||
|
||||
Packed symmetric and packed triangular matrices are laid out with the entries
|
||||
condensed such that all of the unreferenced elements are removed. So, the upper triangular
|
||||
matrix
|
||||
[
|
||||
1 2 3
|
||||
0 4 5
|
||||
0 0 6
|
||||
]
|
||||
and the lower-triangular matrix
|
||||
[
|
||||
1 0 0
|
||||
2 3 0
|
||||
4 5 6
|
||||
]
|
||||
will both be compacted as [1 2 3 4 5 6]. The (i, j) element of the original
|
||||
dense matrix can be found at element i*n - (i-1)*i/2 + j for upper triangular,
|
||||
and at element i * (i+1) /2 + j for lower triangular.
|
||||
|
||||
Banded matrices are laid out in a compact format, constructed by removing the
|
||||
zeros in the rows and aligning the diagonals. For example, the matrix
|
||||
[
|
||||
1 2 3 0 0 0
|
||||
4 5 6 7 0 0
|
||||
0 8 9 10 11 0
|
||||
0 0 12 13 14 15
|
||||
0 0 0 16 17 18
|
||||
0 0 0 0 19 20
|
||||
]
|
||||
|
||||
implicitly becomes (∗ entries are never accessed)
|
||||
[
|
||||
* 1 2 3
|
||||
4 5 6 7
|
||||
8 9 10 11
|
||||
12 13 14 15
|
||||
16 17 18 *
|
||||
19 20 * *
|
||||
]
|
||||
which is given to the BLAS routine as [∗ 1 2 3 4 ...].
|
||||
|
||||
See http://www.crest.iu.edu/research/mtl/reference/html/banded.html
|
||||
for more information
|
||||
*/
|
||||
package native
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
// Copyright ©2014 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 native
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
func newGeneral64(r, c int) general64 {
|
||||
return general64{
|
||||
data: make([]float64, r*c),
|
||||
rows: r,
|
||||
cols: c,
|
||||
stride: c,
|
||||
}
|
||||
}
|
||||
|
||||
type general64 struct {
|
||||
data []float64
|
||||
rows, cols int
|
||||
stride int
|
||||
}
|
||||
|
||||
// adds element-wise into receiver. rows and columns must match
|
||||
func (g general64) add(h general64) {
|
||||
if debug {
|
||||
if g.rows != h.rows {
|
||||
panic("blas: row size mismatch")
|
||||
}
|
||||
if g.cols != h.cols {
|
||||
panic("blas: col size mismatch")
|
||||
}
|
||||
}
|
||||
for i := 0; i < g.rows; i++ {
|
||||
gtmp := g.data[i*g.stride : i*g.stride+g.cols]
|
||||
for j, v := range h.data[i*h.stride : i*h.stride+h.cols] {
|
||||
gtmp[j] += v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at returns the value at the ith row and jth column. For speed reasons, the
|
||||
// rows and columns are not bounds checked.
|
||||
func (g general64) at(i, j int) float64 {
|
||||
if debug {
|
||||
if i < 0 || i >= g.rows {
|
||||
panic("blas: row out of bounds")
|
||||
}
|
||||
if j < 0 || j >= g.cols {
|
||||
panic("blas: col out of bounds")
|
||||
}
|
||||
}
|
||||
return g.data[i*g.stride+j]
|
||||
}
|
||||
|
||||
func (g general64) check(c byte) error {
|
||||
if g.rows < 0 {
|
||||
return errors.New("blas: rows < 0")
|
||||
}
|
||||
if g.cols < 0 {
|
||||
return errors.New("blas: cols < 0")
|
||||
}
|
||||
if g.stride < 1 {
|
||||
return errors.New("blas: stride < 1")
|
||||
}
|
||||
if g.stride < g.cols {
|
||||
return errors.New("blas: illegal stride")
|
||||
}
|
||||
if (g.rows-1)*g.stride+g.cols > len(g.data) {
|
||||
return fmt.Errorf("blas: index of %c out of range", c)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g general64) clone() general64 {
|
||||
data := make([]float64, len(g.data))
|
||||
copy(data, g.data)
|
||||
return general64{
|
||||
data: data,
|
||||
rows: g.rows,
|
||||
cols: g.cols,
|
||||
stride: g.stride,
|
||||
}
|
||||
}
|
||||
|
||||
// assumes they are the same size
|
||||
func (g general64) copy(h general64) {
|
||||
if debug {
|
||||
if g.rows != h.rows {
|
||||
panic("blas: row mismatch")
|
||||
}
|
||||
if g.cols != h.cols {
|
||||
panic("blas: col mismatch")
|
||||
}
|
||||
}
|
||||
for k := 0; k < g.rows; k++ {
|
||||
copy(g.data[k*g.stride:(k+1)*g.stride], h.data[k*h.stride:(k+1)*h.stride])
|
||||
}
|
||||
}
|
||||
|
||||
func (g general64) equal(a general64) bool {
|
||||
if g.rows != a.rows || g.cols != a.cols || g.stride != a.stride {
|
||||
return false
|
||||
}
|
||||
for i, v := range g.data {
|
||||
if a.data[i] != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
// print is to aid debugging. Commented out to avoid fmt import
|
||||
func (g general64) print() {
|
||||
fmt.Println("r = ", g.rows, "c = ", g.cols, "stride: ", g.stride)
|
||||
for i := 0; i < g.rows; i++ {
|
||||
fmt.Println(g.data[i*g.stride : (i+1)*g.stride])
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
func (g general64) view(i, j, r, c int) general64 {
|
||||
if debug {
|
||||
if i < 0 || i+r > g.rows {
|
||||
panic("blas: row out of bounds")
|
||||
}
|
||||
if j < 0 || j+c > g.cols {
|
||||
panic("blas: col out of bounds")
|
||||
}
|
||||
}
|
||||
return general64{
|
||||
data: g.data[i*g.stride+j : (i+r-1)*g.stride+j+c],
|
||||
rows: r,
|
||||
cols: c,
|
||||
stride: g.stride,
|
||||
}
|
||||
}
|
||||
|
||||
func (g general64) equalWithinAbs(a general64, tol float64) bool {
|
||||
if g.rows != a.rows || g.cols != a.cols || g.stride != a.stride {
|
||||
return false
|
||||
}
|
||||
for i, v := range g.data {
|
||||
if math.Abs(a.data[i]-v) > tol {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// Copyright ©2014 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 native
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
math "github.com/gonum/blas/native/internal/math32"
|
||||
)
|
||||
|
||||
func newGeneral32(r, c int) general32 {
|
||||
return general32{
|
||||
data: make([]float32, r*c),
|
||||
rows: r,
|
||||
cols: c,
|
||||
stride: c,
|
||||
}
|
||||
}
|
||||
|
||||
type general32 struct {
|
||||
data []float32
|
||||
rows, cols int
|
||||
stride int
|
||||
}
|
||||
|
||||
// adds element-wise into receiver. rows and columns must match
|
||||
func (g general32) add(h general32) {
|
||||
if debug {
|
||||
if g.rows != h.rows {
|
||||
panic("blas: row size mismatch")
|
||||
}
|
||||
if g.cols != h.cols {
|
||||
panic("blas: col size mismatch")
|
||||
}
|
||||
}
|
||||
for i := 0; i < g.rows; i++ {
|
||||
gtmp := g.data[i*g.stride : i*g.stride+g.cols]
|
||||
for j, v := range h.data[i*h.stride : i*h.stride+h.cols] {
|
||||
gtmp[j] += v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at returns the value at the ith row and jth column. For speed reasons, the
|
||||
// rows and columns are not bounds checked.
|
||||
func (g general32) at(i, j int) float32 {
|
||||
if debug {
|
||||
if i < 0 || i >= g.rows {
|
||||
panic("blas: row out of bounds")
|
||||
}
|
||||
if j < 0 || j >= g.cols {
|
||||
panic("blas: col out of bounds")
|
||||
}
|
||||
}
|
||||
return g.data[i*g.stride+j]
|
||||
}
|
||||
|
||||
func (g general32) check(c byte) error {
|
||||
if g.rows < 0 {
|
||||
return errors.New("blas: rows < 0")
|
||||
}
|
||||
if g.cols < 0 {
|
||||
return errors.New("blas: cols < 0")
|
||||
}
|
||||
if g.stride < 1 {
|
||||
return errors.New("blas: stride < 1")
|
||||
}
|
||||
if g.stride < g.cols {
|
||||
return errors.New("blas: illegal stride")
|
||||
}
|
||||
if (g.rows-1)*g.stride+g.cols > len(g.data) {
|
||||
return fmt.Errorf("blas: index of %c out of range", c)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g general32) clone() general32 {
|
||||
data := make([]float32, len(g.data))
|
||||
copy(data, g.data)
|
||||
return general32{
|
||||
data: data,
|
||||
rows: g.rows,
|
||||
cols: g.cols,
|
||||
stride: g.stride,
|
||||
}
|
||||
}
|
||||
|
||||
// assumes they are the same size
|
||||
func (g general32) copy(h general32) {
|
||||
if debug {
|
||||
if g.rows != h.rows {
|
||||
panic("blas: row mismatch")
|
||||
}
|
||||
if g.cols != h.cols {
|
||||
panic("blas: col mismatch")
|
||||
}
|
||||
}
|
||||
for k := 0; k < g.rows; k++ {
|
||||
copy(g.data[k*g.stride:(k+1)*g.stride], h.data[k*h.stride:(k+1)*h.stride])
|
||||
}
|
||||
}
|
||||
|
||||
func (g general32) equal(a general32) bool {
|
||||
if g.rows != a.rows || g.cols != a.cols || g.stride != a.stride {
|
||||
return false
|
||||
}
|
||||
for i, v := range g.data {
|
||||
if a.data[i] != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
// print is to aid debugging. Commented out to avoid fmt import
|
||||
func (g general32) print() {
|
||||
fmt.Println("r = ", g.rows, "c = ", g.cols, "stride: ", g.stride)
|
||||
for i := 0; i < g.rows; i++ {
|
||||
fmt.Println(g.data[i*g.stride : (i+1)*g.stride])
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
func (g general32) view(i, j, r, c int) general32 {
|
||||
if debug {
|
||||
if i < 0 || i+r > g.rows {
|
||||
panic("blas: row out of bounds")
|
||||
}
|
||||
if j < 0 || j+c > g.cols {
|
||||
panic("blas: col out of bounds")
|
||||
}
|
||||
}
|
||||
return general32{
|
||||
data: g.data[i*g.stride+j : (i+r-1)*g.stride+j+c],
|
||||
rows: r,
|
||||
cols: c,
|
||||
stride: g.stride,
|
||||
}
|
||||
}
|
||||
|
||||
func (g general32) equalWithinAbs(a general32, tol float32) bool {
|
||||
if g.rows != a.rows || g.cols != a.cols || g.stride != a.stride {
|
||||
return false
|
||||
}
|
||||
for i, v := range g.data {
|
||||
if math.Abs(a.data[i]-v) > tol {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// 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 math32 provides float32 versions of standard library math package
|
||||
// routines used by gonum/blas/native.
|
||||
package math32
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
const (
|
||||
unan = 0x7fc00000
|
||||
uinf = 0x7f800000
|
||||
uneginf = 0xff800000
|
||||
mask = 0x7f8 >> 3
|
||||
shift = 32 - 8 - 1
|
||||
bias = 127
|
||||
)
|
||||
|
||||
// Abs returns the absolute value of x.
|
||||
//
|
||||
// Special cases are:
|
||||
// Abs(±Inf) = +Inf
|
||||
// Abs(NaN) = NaN
|
||||
func Abs(x float32) float32 {
|
||||
switch {
|
||||
case x < 0:
|
||||
return -x
|
||||
case x == 0:
|
||||
return 0 // return correctly abs(-0)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Copysign returns a value with the magnitude
|
||||
// of x and the sign of y.
|
||||
func Copysign(x, y float32) float32 {
|
||||
const sign = 1 << 31
|
||||
return math.Float32frombits(math.Float32bits(x)&^sign | math.Float32bits(y)&sign)
|
||||
}
|
||||
|
||||
// Hypot returns Sqrt(p*p + q*q), taking care to avoid
|
||||
// unnecessary overflow and underflow.
|
||||
//
|
||||
// Special cases are:
|
||||
// Hypot(±Inf, q) = +Inf
|
||||
// Hypot(p, ±Inf) = +Inf
|
||||
// Hypot(NaN, q) = NaN
|
||||
// Hypot(p, NaN) = NaN
|
||||
func Hypot(p, q float32) float32 {
|
||||
// special cases
|
||||
switch {
|
||||
case IsInf(p, 0) || IsInf(q, 0):
|
||||
return Inf(1)
|
||||
case IsNaN(p) || IsNaN(q):
|
||||
return NaN()
|
||||
}
|
||||
if p < 0 {
|
||||
p = -p
|
||||
}
|
||||
if q < 0 {
|
||||
q = -q
|
||||
}
|
||||
if p < q {
|
||||
p, q = q, p
|
||||
}
|
||||
if p == 0 {
|
||||
return 0
|
||||
}
|
||||
q = q / p
|
||||
return p * Sqrt(1+q*q)
|
||||
}
|
||||
|
||||
// Inf returns positive infinity if sign >= 0, negative infinity if sign < 0.
|
||||
func Inf(sign int) float32 {
|
||||
var v uint32
|
||||
if sign >= 0 {
|
||||
v = uinf
|
||||
} else {
|
||||
v = uneginf
|
||||
}
|
||||
return math.Float32frombits(v)
|
||||
}
|
||||
|
||||
// IsInf reports whether f is an infinity, according to sign.
|
||||
// If sign > 0, IsInf reports whether f is positive infinity.
|
||||
// If sign < 0, IsInf reports whether f is negative infinity.
|
||||
// If sign == 0, IsInf reports whether f is either infinity.
|
||||
func IsInf(f float32, sign int) bool {
|
||||
// Test for infinity by comparing against maximum float.
|
||||
// To avoid the floating-point hardware, could use:
|
||||
// x := math.Float32bits(f);
|
||||
// return sign >= 0 && x == uinf || sign <= 0 && x == uneginf;
|
||||
return sign >= 0 && f > math.MaxFloat32 || sign <= 0 && f < -math.MaxFloat32
|
||||
}
|
||||
|
||||
// IsNaN reports whether f is an IEEE 754 ``not-a-number'' value.
|
||||
func IsNaN(f float32) (is bool) {
|
||||
// IEEE 754 says that only NaNs satisfy f != f.
|
||||
// To avoid the floating-point hardware, could use:
|
||||
// x := math.Float32bits(f);
|
||||
// return uint32(x>>shift)&mask == mask && x != uinf && x != uneginf
|
||||
return f != f
|
||||
}
|
||||
|
||||
// NaN returns an IEEE 754 ``not-a-number'' value.
|
||||
func NaN() float32 { return math.Float32frombits(unan) }
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// 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.
|
||||
|
||||
//+build !amd64 noasm
|
||||
|
||||
package math32
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Sqrt returns the square root of x.
|
||||
//
|
||||
// Special cases are:
|
||||
// Sqrt(+Inf) = +Inf
|
||||
// Sqrt(±0) = ±0
|
||||
// Sqrt(x < 0) = NaN
|
||||
// Sqrt(NaN) = NaN
|
||||
func Sqrt(x float32) float32 {
|
||||
// FIXME(kortschak): Direct translation of the math package
|
||||
// asm code for 386 fails to build. No test hardware is available
|
||||
// for arm, so using conversion instead.
|
||||
return float32(math.Sqrt(float64(x)))
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// 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.
|
||||
|
||||
//+build !noasm
|
||||
|
||||
package math32
|
||||
|
||||
// Sqrt returns the square root of x.
|
||||
//
|
||||
// Special cases are:
|
||||
// Sqrt(+Inf) = +Inf
|
||||
// Sqrt(±0) = ±0
|
||||
// Sqrt(x < 0) = NaN
|
||||
// Sqrt(NaN) = NaN
|
||||
func Sqrt(x float32) float32
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// 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.
|
||||
|
||||
//+build !noasm
|
||||
|
||||
// TODO(kortschak): use textflag.h after we drop Go 1.3 support
|
||||
//#include "textflag.h"
|
||||
// Don't insert stack check preamble.
|
||||
#define NOSPLIT 4
|
||||
|
||||
// func Sqrt(x float32) float32
|
||||
TEXT ·Sqrt(SB),NOSPLIT,$0
|
||||
SQRTSS x+0(FP), X0
|
||||
MOVSS X0, ret+8(FP)
|
||||
RET
|
||||
+599
@@ -0,0 +1,599 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/internal/asm"
|
||||
)
|
||||
|
||||
var _ blas.Float64Level1 = Implementation{}
|
||||
|
||||
// Dnrm2 computes the Euclidean norm of a vector,
|
||||
// sqrt(\sum_i x[i] * x[i]).
|
||||
// This function returns 0 if incX is negative.
|
||||
func (Implementation) Dnrm2(n int, x []float64, incX int) float64 {
|
||||
if incX < 1 {
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
if incX > 0 && (n-1)*incX >= len(x) {
|
||||
panic(badX)
|
||||
}
|
||||
if n < 2 {
|
||||
if n == 1 {
|
||||
return math.Abs(x[0])
|
||||
}
|
||||
if n == 0 {
|
||||
return 0
|
||||
}
|
||||
if n < 1 {
|
||||
panic(negativeN)
|
||||
}
|
||||
}
|
||||
var (
|
||||
scale float64 = 0
|
||||
sumSquares float64 = 1
|
||||
)
|
||||
if incX == 1 {
|
||||
x = x[:n]
|
||||
for _, v := range x {
|
||||
absxi := math.Abs(v)
|
||||
if scale < absxi {
|
||||
sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi)
|
||||
scale = absxi
|
||||
} else {
|
||||
sumSquares = sumSquares + (absxi/scale)*(absxi/scale)
|
||||
}
|
||||
}
|
||||
return scale * math.Sqrt(sumSquares)
|
||||
}
|
||||
for ix := 0; ix < n*incX; ix += incX {
|
||||
val := x[ix]
|
||||
if val == 0 {
|
||||
continue
|
||||
}
|
||||
absxi := math.Abs(val)
|
||||
if scale < absxi {
|
||||
sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi)
|
||||
scale = absxi
|
||||
} else {
|
||||
sumSquares = sumSquares + (absxi/scale)*(absxi/scale)
|
||||
}
|
||||
}
|
||||
return scale * math.Sqrt(sumSquares)
|
||||
}
|
||||
|
||||
// Dasum computes the sum of the absolute values of the elements of x.
|
||||
// \sum_i |x[i]|
|
||||
// Dasum returns 0 if incX is negative.
|
||||
func (Implementation) Dasum(n int, x []float64, incX int) float64 {
|
||||
var sum float64
|
||||
if n < 0 {
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX < 1 {
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
if incX > 0 && (n-1)*incX >= len(x) {
|
||||
panic(badX)
|
||||
}
|
||||
if incX == 1 {
|
||||
x = x[:n]
|
||||
for _, v := range x {
|
||||
sum += math.Abs(v)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
sum += math.Abs(x[i*incX])
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// Idamax returns the index of the largest element of x. If there are multiple
|
||||
// such indices the earliest is returned. Idamax returns -1 if incX is negative or if
|
||||
// n == 0.
|
||||
func (Implementation) Idamax(n int, x []float64, incX int) int {
|
||||
if incX < 1 {
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
return -1
|
||||
}
|
||||
if incX > 0 && (n-1)*incX >= len(x) {
|
||||
panic(badX)
|
||||
}
|
||||
if n < 2 {
|
||||
if n == 1 {
|
||||
return 0
|
||||
}
|
||||
if n == 0 {
|
||||
return -1 // Netlib returns invalid index when n == 0
|
||||
}
|
||||
if n < 1 {
|
||||
panic(negativeN)
|
||||
}
|
||||
}
|
||||
idx := 0
|
||||
max := math.Abs(x[0])
|
||||
if incX == 1 {
|
||||
for i, v := range x[:n] {
|
||||
absV := math.Abs(v)
|
||||
if absV > max {
|
||||
max = absV
|
||||
idx = i
|
||||
}
|
||||
}
|
||||
return idx
|
||||
}
|
||||
ix := incX
|
||||
for i := 1; i < n; i++ {
|
||||
v := x[ix]
|
||||
absV := math.Abs(v)
|
||||
if absV > max {
|
||||
max = absV
|
||||
idx = i
|
||||
}
|
||||
ix += incX
|
||||
}
|
||||
return idx
|
||||
}
|
||||
|
||||
// Dswap exchanges the elements of two vectors.
|
||||
// x[i], y[i] = y[i], x[i] for all i
|
||||
func (Implementation) Dswap(n int, x []float64, incX int, y []float64, incY int) {
|
||||
if n < 1 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
|
||||
panic(badX)
|
||||
}
|
||||
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
|
||||
panic(badY)
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
x = x[:n]
|
||||
for i, v := range x {
|
||||
x[i], y[i] = y[i], v
|
||||
}
|
||||
return
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
x[ix], y[iy] = y[iy], x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
}
|
||||
|
||||
// Dcopy copies the elements of x into the elements of y.
|
||||
// y[i] = x[i] for all i
|
||||
func (Implementation) Dcopy(n int, x []float64, incX int, y []float64, incY int) {
|
||||
if n < 1 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
|
||||
panic(badX)
|
||||
}
|
||||
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
|
||||
panic(badY)
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
copy(y[:n], x[:n])
|
||||
return
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
y[iy] = x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
}
|
||||
|
||||
// Daxpy adds alpha times x to y
|
||||
// y[i] += alpha * x[i] for all i
|
||||
func (Implementation) Daxpy(n int, alpha float64, x []float64, incX int, y []float64, incY int) {
|
||||
if n < 1 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
|
||||
panic(badX)
|
||||
}
|
||||
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
|
||||
panic(badY)
|
||||
}
|
||||
if alpha == 0 {
|
||||
return
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
if len(x) < n {
|
||||
panic(badLenX)
|
||||
}
|
||||
if len(y) < n {
|
||||
panic(badLenY)
|
||||
}
|
||||
asm.DaxpyUnitary(alpha, x[:n], y, y)
|
||||
return
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
if ix >= len(x) || ix+(n-1)*incX >= len(x) {
|
||||
panic(badLenX)
|
||||
}
|
||||
if iy >= len(y) || iy+(n-1)*incY >= len(y) {
|
||||
panic(badLenY)
|
||||
}
|
||||
asm.DaxpyInc(alpha, x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
|
||||
}
|
||||
|
||||
// Drotg computes the plane rotation
|
||||
// _ _ _ _ _ _
|
||||
// | c s | | a | | r |
|
||||
// | -s c | * | b | = | 0 |
|
||||
// ‾ ‾ ‾ ‾ ‾ ‾
|
||||
// where
|
||||
// r = ±(a^2 + b^2)
|
||||
// c = a/r, the cosine of the plane rotation
|
||||
// s = b/r, the sine of the plane rotation
|
||||
//
|
||||
// NOTE: There is a discrepancy between the refence implementation and the BLAS
|
||||
// technical manual regarding the sign for r when a or b are zero.
|
||||
// Drotg agrees with the definition in the manual and other
|
||||
// common BLAS implementations.
|
||||
func (Implementation) Drotg(a, b float64) (c, s, r, z float64) {
|
||||
if b == 0 && a == 0 {
|
||||
return 1, 0, a, 0
|
||||
}
|
||||
absA := math.Abs(a)
|
||||
absB := math.Abs(b)
|
||||
aGTb := absA > absB
|
||||
r = math.Hypot(a, b)
|
||||
if aGTb {
|
||||
r = math.Copysign(r, a)
|
||||
} else {
|
||||
r = math.Copysign(r, b)
|
||||
}
|
||||
c = a / r
|
||||
s = b / r
|
||||
if aGTb {
|
||||
z = s
|
||||
} else if c != 0 { // r == 0 case handled above
|
||||
z = 1 / c
|
||||
} else {
|
||||
z = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Drotmg computes the modified Givens rotation. See
|
||||
// http://www.netlib.org/lapack/explore-html/df/deb/drotmg_8f.html
|
||||
// for more details.
|
||||
func (Implementation) Drotmg(d1, d2, x1, y1 float64) (p blas.DrotmParams, rd1, rd2, rx1 float64) {
|
||||
var p1, p2, q1, q2, u float64
|
||||
|
||||
const (
|
||||
gam = 4096.0
|
||||
gamsq = 16777216.0
|
||||
rgamsq = 5.9604645e-8
|
||||
)
|
||||
|
||||
if d1 < 0 {
|
||||
p.Flag = blas.Rescaling
|
||||
return
|
||||
}
|
||||
|
||||
p2 = d2 * y1
|
||||
if p2 == 0 {
|
||||
p.Flag = blas.Identity
|
||||
rd1 = d1
|
||||
rd2 = d2
|
||||
rx1 = x1
|
||||
return
|
||||
}
|
||||
p1 = d1 * x1
|
||||
q2 = p2 * y1
|
||||
q1 = p1 * x1
|
||||
|
||||
absQ1 := math.Abs(q1)
|
||||
absQ2 := math.Abs(q2)
|
||||
|
||||
if absQ1 < absQ2 && q2 < 0 {
|
||||
p.Flag = blas.Rescaling
|
||||
return
|
||||
}
|
||||
|
||||
if d1 == 0 {
|
||||
p.Flag = blas.Diagonal
|
||||
p.H[0] = p1 / p2
|
||||
p.H[3] = x1 / y1
|
||||
u = 1 + p.H[0]*p.H[3]
|
||||
rd1, rd2 = d2/u, d1/u
|
||||
rx1 = y1 / u
|
||||
return
|
||||
}
|
||||
|
||||
// Now we know that d1 != 0, and d2 != 0. If d2 == 0, it would be caught
|
||||
// when p2 == 0, and if d1 == 0, then it is caught above
|
||||
|
||||
if absQ1 > absQ2 {
|
||||
p.H[1] = -y1 / x1
|
||||
p.H[2] = p2 / p1
|
||||
u = 1 - p.H[2]*p.H[1]
|
||||
rd1 = d1
|
||||
rd2 = d2
|
||||
rx1 = x1
|
||||
p.Flag = blas.OffDiagonal
|
||||
// u must be greater than zero because |q1| > |q2|, so check from netlib
|
||||
// is unnecessary
|
||||
// This is left in for ease of comparison with complex routines
|
||||
//if u > 0 {
|
||||
rd1 /= u
|
||||
rd2 /= u
|
||||
rx1 *= u
|
||||
//}
|
||||
} else {
|
||||
p.Flag = blas.Diagonal
|
||||
p.H[0] = p1 / p2
|
||||
p.H[3] = x1 / y1
|
||||
u = 1 + p.H[0]*p.H[3]
|
||||
rd1 = d2 / u
|
||||
rd2 = d1 / u
|
||||
rx1 = y1 * u
|
||||
}
|
||||
|
||||
for rd1 <= rgamsq || rd1 >= gamsq {
|
||||
if p.Flag == blas.OffDiagonal {
|
||||
p.H[0] = 1
|
||||
p.H[3] = 1
|
||||
p.Flag = blas.Rescaling
|
||||
} else if p.Flag == blas.Diagonal {
|
||||
p.H[1] = -1
|
||||
p.H[2] = 1
|
||||
p.Flag = blas.Rescaling
|
||||
}
|
||||
if rd1 <= rgamsq {
|
||||
rd1 *= gam * gam
|
||||
rx1 /= gam
|
||||
p.H[0] /= gam
|
||||
p.H[2] /= gam
|
||||
} else {
|
||||
rd1 /= gam * gam
|
||||
rx1 *= gam
|
||||
p.H[0] *= gam
|
||||
p.H[2] *= gam
|
||||
}
|
||||
}
|
||||
|
||||
for math.Abs(rd2) <= rgamsq || math.Abs(rd2) >= gamsq {
|
||||
if p.Flag == blas.OffDiagonal {
|
||||
p.H[0] = 1
|
||||
p.H[3] = 1
|
||||
p.Flag = blas.Rescaling
|
||||
} else if p.Flag == blas.Diagonal {
|
||||
p.H[1] = -1
|
||||
p.H[2] = 1
|
||||
p.Flag = blas.Rescaling
|
||||
}
|
||||
if math.Abs(rd2) <= rgamsq {
|
||||
rd2 *= gam * gam
|
||||
p.H[1] /= gam
|
||||
p.H[3] /= gam
|
||||
} else {
|
||||
rd2 /= gam * gam
|
||||
p.H[1] *= gam
|
||||
p.H[3] *= gam
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Drot applies a plane transformation.
|
||||
// x[i] = c * x[i] + s * y[i]
|
||||
// y[i] = c * y[i] - s * x[i]
|
||||
func (Implementation) Drot(n int, x []float64, incX int, y []float64, incY int, c float64, s float64) {
|
||||
if n < 1 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
|
||||
panic(badX)
|
||||
}
|
||||
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
|
||||
panic(badY)
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
x = x[:n]
|
||||
for i, vx := range x {
|
||||
vy := y[i]
|
||||
x[i], y[i] = c*vx+s*vy, c*vy-s*vx
|
||||
}
|
||||
return
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
vx := x[ix]
|
||||
vy := y[iy]
|
||||
x[ix], y[iy] = c*vx+s*vy, c*vy-s*vx
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
}
|
||||
|
||||
// Drotm applies the modified Givens rotation to the 2×n matrix.
|
||||
func (Implementation) Drotm(n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) {
|
||||
if n <= 0 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
|
||||
panic(badX)
|
||||
}
|
||||
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
|
||||
panic(badY)
|
||||
}
|
||||
|
||||
var h11, h12, h21, h22 float64
|
||||
var ix, iy int
|
||||
switch p.Flag {
|
||||
case blas.Identity:
|
||||
return
|
||||
case blas.Rescaling:
|
||||
h11 = p.H[0]
|
||||
h12 = p.H[2]
|
||||
h21 = p.H[1]
|
||||
h22 = p.H[3]
|
||||
case blas.OffDiagonal:
|
||||
h11 = 1
|
||||
h12 = p.H[2]
|
||||
h21 = p.H[1]
|
||||
h22 = 1
|
||||
case blas.Diagonal:
|
||||
h11 = p.H[0]
|
||||
h12 = 1
|
||||
h21 = -1
|
||||
h22 = p.H[3]
|
||||
}
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
x = x[:n]
|
||||
for i, vx := range x {
|
||||
vy := y[i]
|
||||
x[i], y[i] = vx*h11+vy*h12, vx*h21+vy*h22
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
vx := x[ix]
|
||||
vy := y[iy]
|
||||
x[ix], y[iy] = vx*h11+vy*h12, vx*h21+vy*h22
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Dscal scales x by alpha.
|
||||
// x[i] *= alpha
|
||||
// Dscal has no effect if incX < 0.
|
||||
func (Implementation) Dscal(n int, alpha float64, x []float64, incX int) {
|
||||
if incX < 1 {
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
return
|
||||
}
|
||||
if incX > 0 && (n-1)*incX >= len(x) {
|
||||
panic(badX)
|
||||
}
|
||||
if n < 1 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
if n < 1 {
|
||||
panic(negativeN)
|
||||
}
|
||||
}
|
||||
if alpha == 0 {
|
||||
if incX == 1 {
|
||||
x = x[:n]
|
||||
for i := range x {
|
||||
x[i] = 0
|
||||
}
|
||||
}
|
||||
for ix := 0; ix < n*incX; ix += incX {
|
||||
x[ix] = 0
|
||||
}
|
||||
}
|
||||
if incX == 1 {
|
||||
x = x[:n]
|
||||
for i := range x {
|
||||
x[i] *= alpha
|
||||
}
|
||||
return
|
||||
}
|
||||
for ix := 0; ix < n*incX; ix += incX {
|
||||
x[ix] *= alpha
|
||||
}
|
||||
return
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/internal/asm"
|
||||
)
|
||||
|
||||
// Ddot computes the dot product of the two vectors
|
||||
// \sum_i x[i]*y[i]
|
||||
func (Implementation) Ddot(n int, x []float64, incX int, y []float64, incY int) float64 {
|
||||
if n < 0 {
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
if len(x) < n {
|
||||
panic(badLenX)
|
||||
}
|
||||
if len(y) < n {
|
||||
panic(badLenY)
|
||||
}
|
||||
return asm.DdotUnitary(x[:n], y)
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
if ix >= len(x) || ix+(n-1)*incX >= len(x) {
|
||||
panic(badLenX)
|
||||
}
|
||||
if iy >= len(y) || iy+(n-1)*incY >= len(y) {
|
||||
panic(badLenY)
|
||||
}
|
||||
return asm.DdotInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
|
||||
}
|
||||
+623
@@ -0,0 +1,623 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
math "github.com/gonum/blas/native/internal/math32"
|
||||
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/internal/asm"
|
||||
)
|
||||
|
||||
var _ blas.Float32Level1 = Implementation{}
|
||||
|
||||
// Snrm2 computes the Euclidean norm of a vector,
|
||||
// sqrt(\sum_i x[i] * x[i]).
|
||||
// This function returns 0 if incX is negative.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Snrm2(n int, x []float32, incX int) float32 {
|
||||
if incX < 1 {
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
if incX > 0 && (n-1)*incX >= len(x) {
|
||||
panic(badX)
|
||||
}
|
||||
if n < 2 {
|
||||
if n == 1 {
|
||||
return math.Abs(x[0])
|
||||
}
|
||||
if n == 0 {
|
||||
return 0
|
||||
}
|
||||
if n < 1 {
|
||||
panic(negativeN)
|
||||
}
|
||||
}
|
||||
var (
|
||||
scale float32 = 0
|
||||
sumSquares float32 = 1
|
||||
)
|
||||
if incX == 1 {
|
||||
x = x[:n]
|
||||
for _, v := range x {
|
||||
absxi := math.Abs(v)
|
||||
if scale < absxi {
|
||||
sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi)
|
||||
scale = absxi
|
||||
} else {
|
||||
sumSquares = sumSquares + (absxi/scale)*(absxi/scale)
|
||||
}
|
||||
}
|
||||
return scale * math.Sqrt(sumSquares)
|
||||
}
|
||||
for ix := 0; ix < n*incX; ix += incX {
|
||||
val := x[ix]
|
||||
if val == 0 {
|
||||
continue
|
||||
}
|
||||
absxi := math.Abs(val)
|
||||
if scale < absxi {
|
||||
sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi)
|
||||
scale = absxi
|
||||
} else {
|
||||
sumSquares = sumSquares + (absxi/scale)*(absxi/scale)
|
||||
}
|
||||
}
|
||||
return scale * math.Sqrt(sumSquares)
|
||||
}
|
||||
|
||||
// Sasum computes the sum of the absolute values of the elements of x.
|
||||
// \sum_i |x[i]|
|
||||
// Sasum returns 0 if incX is negative.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Sasum(n int, x []float32, incX int) float32 {
|
||||
var sum float32
|
||||
if n < 0 {
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX < 1 {
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
if incX > 0 && (n-1)*incX >= len(x) {
|
||||
panic(badX)
|
||||
}
|
||||
if incX == 1 {
|
||||
x = x[:n]
|
||||
for _, v := range x {
|
||||
sum += math.Abs(v)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
sum += math.Abs(x[i*incX])
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
// Isamax returns the index of the largest element of x. If there are multiple
|
||||
// such indices the earliest is returned. Idamax returns -1 if incX is negative or if
|
||||
// n == 0.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Isamax(n int, x []float32, incX int) int {
|
||||
if incX < 1 {
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
return -1
|
||||
}
|
||||
if incX > 0 && (n-1)*incX >= len(x) {
|
||||
panic(badX)
|
||||
}
|
||||
if n < 2 {
|
||||
if n == 1 {
|
||||
return 0
|
||||
}
|
||||
if n == 0 {
|
||||
return -1 // Netlib returns invalid index when n == 0
|
||||
}
|
||||
if n < 1 {
|
||||
panic(negativeN)
|
||||
}
|
||||
}
|
||||
idx := 0
|
||||
max := math.Abs(x[0])
|
||||
if incX == 1 {
|
||||
for i, v := range x[:n] {
|
||||
absV := math.Abs(v)
|
||||
if absV > max {
|
||||
max = absV
|
||||
idx = i
|
||||
}
|
||||
}
|
||||
return idx
|
||||
}
|
||||
ix := incX
|
||||
for i := 1; i < n; i++ {
|
||||
v := x[ix]
|
||||
absV := math.Abs(v)
|
||||
if absV > max {
|
||||
max = absV
|
||||
idx = i
|
||||
}
|
||||
ix += incX
|
||||
}
|
||||
return idx
|
||||
}
|
||||
|
||||
// Sswap exchanges the elements of two vectors.
|
||||
// x[i], y[i] = y[i], x[i] for all i
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Sswap(n int, x []float32, incX int, y []float32, incY int) {
|
||||
if n < 1 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
|
||||
panic(badX)
|
||||
}
|
||||
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
|
||||
panic(badY)
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
x = x[:n]
|
||||
for i, v := range x {
|
||||
x[i], y[i] = y[i], v
|
||||
}
|
||||
return
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
x[ix], y[iy] = y[iy], x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
}
|
||||
|
||||
// Scopy copies the elements of x into the elements of y.
|
||||
// y[i] = x[i] for all i
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Scopy(n int, x []float32, incX int, y []float32, incY int) {
|
||||
if n < 1 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
|
||||
panic(badX)
|
||||
}
|
||||
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
|
||||
panic(badY)
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
copy(y[:n], x[:n])
|
||||
return
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
y[iy] = x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
}
|
||||
|
||||
// Saxpy adds alpha times x to y
|
||||
// y[i] += alpha * x[i] for all i
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Saxpy(n int, alpha float32, x []float32, incX int, y []float32, incY int) {
|
||||
if n < 1 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
|
||||
panic(badX)
|
||||
}
|
||||
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
|
||||
panic(badY)
|
||||
}
|
||||
if alpha == 0 {
|
||||
return
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
if len(x) < n {
|
||||
panic(badLenX)
|
||||
}
|
||||
if len(y) < n {
|
||||
panic(badLenY)
|
||||
}
|
||||
asm.SaxpyUnitary(alpha, x[:n], y, y)
|
||||
return
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
if ix >= len(x) || ix+(n-1)*incX >= len(x) {
|
||||
panic(badLenX)
|
||||
}
|
||||
if iy >= len(y) || iy+(n-1)*incY >= len(y) {
|
||||
panic(badLenY)
|
||||
}
|
||||
asm.SaxpyInc(alpha, x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
|
||||
}
|
||||
|
||||
// Srotg computes the plane rotation
|
||||
// _ _ _ _ _ _
|
||||
// | c s | | a | | r |
|
||||
// | -s c | * | b | = | 0 |
|
||||
// ‾ ‾ ‾ ‾ ‾ ‾
|
||||
// where
|
||||
// r = ±(a^2 + b^2)
|
||||
// c = a/r, the cosine of the plane rotation
|
||||
// s = b/r, the sine of the plane rotation
|
||||
//
|
||||
// NOTE: There is a discrepancy between the refence implementation and the BLAS
|
||||
// technical manual regarding the sign for r when a or b are zero.
|
||||
// Srotg agrees with the definition in the manual and other
|
||||
// common BLAS implementations.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Srotg(a, b float32) (c, s, r, z float32) {
|
||||
if b == 0 && a == 0 {
|
||||
return 1, 0, a, 0
|
||||
}
|
||||
absA := math.Abs(a)
|
||||
absB := math.Abs(b)
|
||||
aGTb := absA > absB
|
||||
r = math.Hypot(a, b)
|
||||
if aGTb {
|
||||
r = math.Copysign(r, a)
|
||||
} else {
|
||||
r = math.Copysign(r, b)
|
||||
}
|
||||
c = a / r
|
||||
s = b / r
|
||||
if aGTb {
|
||||
z = s
|
||||
} else if c != 0 { // r == 0 case handled above
|
||||
z = 1 / c
|
||||
} else {
|
||||
z = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Srotmg computes the modified Givens rotation. See
|
||||
// http://www.netlib.org/lapack/explore-html/df/deb/drotmg_8f.html
|
||||
// for more details.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Srotmg(d1, d2, x1, y1 float32) (p blas.SrotmParams, rd1, rd2, rx1 float32) {
|
||||
var p1, p2, q1, q2, u float32
|
||||
|
||||
const (
|
||||
gam = 4096.0
|
||||
gamsq = 16777216.0
|
||||
rgamsq = 5.9604645e-8
|
||||
)
|
||||
|
||||
if d1 < 0 {
|
||||
p.Flag = blas.Rescaling
|
||||
return
|
||||
}
|
||||
|
||||
p2 = d2 * y1
|
||||
if p2 == 0 {
|
||||
p.Flag = blas.Identity
|
||||
rd1 = d1
|
||||
rd2 = d2
|
||||
rx1 = x1
|
||||
return
|
||||
}
|
||||
p1 = d1 * x1
|
||||
q2 = p2 * y1
|
||||
q1 = p1 * x1
|
||||
|
||||
absQ1 := math.Abs(q1)
|
||||
absQ2 := math.Abs(q2)
|
||||
|
||||
if absQ1 < absQ2 && q2 < 0 {
|
||||
p.Flag = blas.Rescaling
|
||||
return
|
||||
}
|
||||
|
||||
if d1 == 0 {
|
||||
p.Flag = blas.Diagonal
|
||||
p.H[0] = p1 / p2
|
||||
p.H[3] = x1 / y1
|
||||
u = 1 + p.H[0]*p.H[3]
|
||||
rd1, rd2 = d2/u, d1/u
|
||||
rx1 = y1 / u
|
||||
return
|
||||
}
|
||||
|
||||
// Now we know that d1 != 0, and d2 != 0. If d2 == 0, it would be caught
|
||||
// when p2 == 0, and if d1 == 0, then it is caught above
|
||||
|
||||
if absQ1 > absQ2 {
|
||||
p.H[1] = -y1 / x1
|
||||
p.H[2] = p2 / p1
|
||||
u = 1 - p.H[2]*p.H[1]
|
||||
rd1 = d1
|
||||
rd2 = d2
|
||||
rx1 = x1
|
||||
p.Flag = blas.OffDiagonal
|
||||
// u must be greater than zero because |q1| > |q2|, so check from netlib
|
||||
// is unnecessary
|
||||
// This is left in for ease of comparison with complex routines
|
||||
//if u > 0 {
|
||||
rd1 /= u
|
||||
rd2 /= u
|
||||
rx1 *= u
|
||||
//}
|
||||
} else {
|
||||
p.Flag = blas.Diagonal
|
||||
p.H[0] = p1 / p2
|
||||
p.H[3] = x1 / y1
|
||||
u = 1 + p.H[0]*p.H[3]
|
||||
rd1 = d2 / u
|
||||
rd2 = d1 / u
|
||||
rx1 = y1 * u
|
||||
}
|
||||
|
||||
for rd1 <= rgamsq || rd1 >= gamsq {
|
||||
if p.Flag == blas.OffDiagonal {
|
||||
p.H[0] = 1
|
||||
p.H[3] = 1
|
||||
p.Flag = blas.Rescaling
|
||||
} else if p.Flag == blas.Diagonal {
|
||||
p.H[1] = -1
|
||||
p.H[2] = 1
|
||||
p.Flag = blas.Rescaling
|
||||
}
|
||||
if rd1 <= rgamsq {
|
||||
rd1 *= gam * gam
|
||||
rx1 /= gam
|
||||
p.H[0] /= gam
|
||||
p.H[2] /= gam
|
||||
} else {
|
||||
rd1 /= gam * gam
|
||||
rx1 *= gam
|
||||
p.H[0] *= gam
|
||||
p.H[2] *= gam
|
||||
}
|
||||
}
|
||||
|
||||
for math.Abs(rd2) <= rgamsq || math.Abs(rd2) >= gamsq {
|
||||
if p.Flag == blas.OffDiagonal {
|
||||
p.H[0] = 1
|
||||
p.H[3] = 1
|
||||
p.Flag = blas.Rescaling
|
||||
} else if p.Flag == blas.Diagonal {
|
||||
p.H[1] = -1
|
||||
p.H[2] = 1
|
||||
p.Flag = blas.Rescaling
|
||||
}
|
||||
if math.Abs(rd2) <= rgamsq {
|
||||
rd2 *= gam * gam
|
||||
p.H[1] /= gam
|
||||
p.H[3] /= gam
|
||||
} else {
|
||||
rd2 /= gam * gam
|
||||
p.H[1] *= gam
|
||||
p.H[3] *= gam
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Srot applies a plane transformation.
|
||||
// x[i] = c * x[i] + s * y[i]
|
||||
// y[i] = c * y[i] - s * x[i]
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Srot(n int, x []float32, incX int, y []float32, incY int, c float32, s float32) {
|
||||
if n < 1 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
|
||||
panic(badX)
|
||||
}
|
||||
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
|
||||
panic(badY)
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
x = x[:n]
|
||||
for i, vx := range x {
|
||||
vy := y[i]
|
||||
x[i], y[i] = c*vx+s*vy, c*vy-s*vx
|
||||
}
|
||||
return
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
vx := x[ix]
|
||||
vy := y[iy]
|
||||
x[ix], y[iy] = c*vx+s*vy, c*vy-s*vx
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
}
|
||||
|
||||
// Srotm applies the modified Givens rotation to the 2×n matrix.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Srotm(n int, x []float32, incX int, y []float32, incY int, p blas.SrotmParams) {
|
||||
if n <= 0 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
|
||||
panic(badX)
|
||||
}
|
||||
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
|
||||
panic(badY)
|
||||
}
|
||||
|
||||
var h11, h12, h21, h22 float32
|
||||
var ix, iy int
|
||||
switch p.Flag {
|
||||
case blas.Identity:
|
||||
return
|
||||
case blas.Rescaling:
|
||||
h11 = p.H[0]
|
||||
h12 = p.H[2]
|
||||
h21 = p.H[1]
|
||||
h22 = p.H[3]
|
||||
case blas.OffDiagonal:
|
||||
h11 = 1
|
||||
h12 = p.H[2]
|
||||
h21 = p.H[1]
|
||||
h22 = 1
|
||||
case blas.Diagonal:
|
||||
h11 = p.H[0]
|
||||
h12 = 1
|
||||
h21 = -1
|
||||
h22 = p.H[3]
|
||||
}
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
x = x[:n]
|
||||
for i, vx := range x {
|
||||
vy := y[i]
|
||||
x[i], y[i] = vx*h11+vy*h12, vx*h21+vy*h22
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
vx := x[ix]
|
||||
vy := y[iy]
|
||||
x[ix], y[iy] = vx*h11+vy*h12, vx*h21+vy*h22
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Sscal scales x by alpha.
|
||||
// x[i] *= alpha
|
||||
// Sscal has no effect if incX < 0.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Sscal(n int, alpha float32, x []float32, incX int) {
|
||||
if incX < 1 {
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
return
|
||||
}
|
||||
if incX > 0 && (n-1)*incX >= len(x) {
|
||||
panic(badX)
|
||||
}
|
||||
if n < 1 {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
if n < 1 {
|
||||
panic(negativeN)
|
||||
}
|
||||
}
|
||||
if alpha == 0 {
|
||||
if incX == 1 {
|
||||
x = x[:n]
|
||||
for i := range x {
|
||||
x[i] = 0
|
||||
}
|
||||
}
|
||||
for ix := 0; ix < n*incX; ix += incX {
|
||||
x[ix] = 0
|
||||
}
|
||||
}
|
||||
if incX == 1 {
|
||||
x = x[:n]
|
||||
for i := range x {
|
||||
x[i] *= alpha
|
||||
}
|
||||
return
|
||||
}
|
||||
for ix := 0; ix < n*incX; ix += incX {
|
||||
x[ix] *= alpha
|
||||
}
|
||||
return
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/internal/asm"
|
||||
)
|
||||
|
||||
// Dsdot computes the dot product of the two vectors
|
||||
// \sum_i x[i]*y[i]
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Dsdot(n int, x []float32, incX int, y []float32, incY int) float64 {
|
||||
if n < 0 {
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
if len(x) < n {
|
||||
panic(badLenX)
|
||||
}
|
||||
if len(y) < n {
|
||||
panic(badLenY)
|
||||
}
|
||||
return asm.DsdotUnitary(x[:n], y)
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
if ix >= len(x) || ix+(n-1)*incX >= len(x) {
|
||||
panic(badLenX)
|
||||
}
|
||||
if iy >= len(y) || iy+(n-1)*incY >= len(y) {
|
||||
panic(badLenY)
|
||||
}
|
||||
return asm.DsdotInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/internal/asm"
|
||||
)
|
||||
|
||||
// Sdot computes the dot product of the two vectors
|
||||
// \sum_i x[i]*y[i]
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Sdot(n int, x []float32, incX int, y []float32, incY int) float32 {
|
||||
if n < 0 {
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
if len(x) < n {
|
||||
panic(badLenX)
|
||||
}
|
||||
if len(y) < n {
|
||||
panic(badLenY)
|
||||
}
|
||||
return asm.SdotUnitary(x[:n], y)
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
if ix >= len(x) || ix+(n-1)*incX >= len(x) {
|
||||
panic(badLenX)
|
||||
}
|
||||
if iy >= len(y) || iy+(n-1)*incY >= len(y) {
|
||||
panic(badLenY)
|
||||
}
|
||||
return asm.SdotInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/internal/asm"
|
||||
)
|
||||
|
||||
// Sdsdot computes the dot product of the two vectors plus a constant
|
||||
// alpha + \sum_i x[i]*y[i]
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Sdsdot(n int, alpha float32, x []float32, incX int, y []float32, incY int) float32 {
|
||||
if n < 0 {
|
||||
panic(negativeN)
|
||||
}
|
||||
if incX == 0 {
|
||||
panic(zeroIncX)
|
||||
}
|
||||
if incY == 0 {
|
||||
panic(zeroIncY)
|
||||
}
|
||||
if incX == 1 && incY == 1 {
|
||||
if len(x) < n {
|
||||
panic(badLenX)
|
||||
}
|
||||
if len(y) < n {
|
||||
panic(badLenY)
|
||||
}
|
||||
return alpha + float32(asm.DsdotUnitary(x[:n], y))
|
||||
}
|
||||
var ix, iy int
|
||||
if incX < 0 {
|
||||
ix = (-n + 1) * incX
|
||||
}
|
||||
if incY < 0 {
|
||||
iy = (-n + 1) * incY
|
||||
}
|
||||
if ix >= len(x) || ix+(n-1)*incX >= len(x) {
|
||||
panic(badLenX)
|
||||
}
|
||||
if iy >= len(y) || iy+(n-1)*incY >= len(y) {
|
||||
panic(badLenY)
|
||||
}
|
||||
return alpha + float32(asm.DsdotInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy)))
|
||||
}
|
||||
+2258
File diff suppressed because it is too large
Load Diff
+2292
File diff suppressed because it is too large
Load Diff
+831
@@ -0,0 +1,831 @@
|
||||
// Copyright ©2014 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/internal/asm"
|
||||
)
|
||||
|
||||
var _ blas.Float64Level3 = Implementation{}
|
||||
|
||||
// Dtrsm solves
|
||||
// A * X = alpha * B if tA == blas.NoTrans and side == blas.Left
|
||||
// A^T * X = alpha * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Left
|
||||
// X * A = alpha * B if tA == blas.NoTrans and side == blas.Right
|
||||
// X * A^T = alpha * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Right
|
||||
// where A is an n×n triangular matrix, x is an m×n matrix, and alpha is a
|
||||
// scalar.
|
||||
//
|
||||
// At entry to the function, X contains the values of B, and the result is
|
||||
// stored in place into X.
|
||||
//
|
||||
// No check is made that A is invertible.
|
||||
func (Implementation) Dtrsm(s blas.Side, ul blas.Uplo, tA blas.Transpose, d blas.Diag, m, n int, alpha float64, a []float64, lda int, b []float64, ldb int) {
|
||||
if s != blas.Left && s != blas.Right {
|
||||
panic(badSide)
|
||||
}
|
||||
if ul != blas.Lower && ul != blas.Upper {
|
||||
panic(badUplo)
|
||||
}
|
||||
if tA != blas.NoTrans && tA != blas.Trans && tA != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
if d != blas.NonUnit && d != blas.Unit {
|
||||
panic(badDiag)
|
||||
}
|
||||
if m < 0 {
|
||||
panic(mLT0)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
if ldb < n {
|
||||
panic(badLdB)
|
||||
}
|
||||
var k int
|
||||
if s == blas.Left {
|
||||
k = m
|
||||
} else {
|
||||
k = n
|
||||
}
|
||||
if lda*(k-1)+k > len(a) || lda < max(1, k) {
|
||||
panic(badLdA)
|
||||
}
|
||||
if ldb*(m-1)+n > len(b) || ldb < max(1, n) {
|
||||
panic(badLdB)
|
||||
}
|
||||
|
||||
if m == 0 || n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if alpha == 0 {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j := range btmp {
|
||||
btmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
nonUnit := d == blas.NonUnit
|
||||
if s == blas.Left {
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := m - 1; i >= 0; i-- {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
if alpha != 1 {
|
||||
for j := range btmp {
|
||||
btmp[j] *= alpha
|
||||
}
|
||||
}
|
||||
for ka, va := range a[i*lda+i+1 : i*lda+m] {
|
||||
k := ka + i + 1
|
||||
if va != 0 {
|
||||
asm.DaxpyUnitary(-va, b[k*ldb:k*ldb+n], btmp, btmp)
|
||||
}
|
||||
}
|
||||
if nonUnit {
|
||||
tmp := 1 / a[i*lda+i]
|
||||
for j := 0; j < n; j++ {
|
||||
btmp[j] *= tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
if alpha != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmp[j] *= alpha
|
||||
}
|
||||
}
|
||||
for k, va := range a[i*lda : i*lda+i] {
|
||||
if va != 0 {
|
||||
asm.DaxpyUnitary(-va, b[k*ldb:k*ldb+n], btmp, btmp)
|
||||
}
|
||||
}
|
||||
if nonUnit {
|
||||
tmp := 1 / a[i*lda+i]
|
||||
for j := 0; j < n; j++ {
|
||||
btmp[j] *= tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is transposed
|
||||
if ul == blas.Upper {
|
||||
for k := 0; k < m; k++ {
|
||||
btmpk := b[k*ldb : k*ldb+n]
|
||||
if nonUnit {
|
||||
tmp := 1 / a[k*lda+k]
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= tmp
|
||||
}
|
||||
}
|
||||
for ia, va := range a[k*lda+k+1 : k*lda+m] {
|
||||
i := ia + k + 1
|
||||
if va != 0 {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
asm.DaxpyUnitary(-va, btmpk, btmp, btmp)
|
||||
}
|
||||
}
|
||||
if alpha != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= alpha
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for k := m - 1; k >= 0; k-- {
|
||||
btmpk := b[k*ldb : k*ldb+n]
|
||||
if nonUnit {
|
||||
tmp := 1 / a[k*lda+k]
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= tmp
|
||||
}
|
||||
}
|
||||
for i, va := range a[k*lda : k*lda+k] {
|
||||
if va != 0 {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
asm.DaxpyUnitary(-va, btmpk, btmp, btmp)
|
||||
}
|
||||
}
|
||||
if alpha != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= alpha
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is to the right of X.
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
if alpha != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmp[j] *= alpha
|
||||
}
|
||||
}
|
||||
for k, vb := range btmp {
|
||||
if vb != 0 {
|
||||
if btmp[k] != 0 {
|
||||
if nonUnit {
|
||||
btmp[k] /= a[k*lda+k]
|
||||
}
|
||||
btmpk := btmp[k+1 : n]
|
||||
asm.DaxpyUnitary(-btmp[k], a[k*lda+k+1:k*lda+n], btmpk, btmpk)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*lda : i*lda+n]
|
||||
if alpha != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmp[j] *= alpha
|
||||
}
|
||||
}
|
||||
for k := n - 1; k >= 0; k-- {
|
||||
if btmp[k] != 0 {
|
||||
if nonUnit {
|
||||
btmp[k] /= a[k*lda+k]
|
||||
}
|
||||
asm.DaxpyUnitary(-btmp[k], a[k*lda:k*lda+k], btmp, btmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is transposed.
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*lda : i*lda+n]
|
||||
for j := n - 1; j >= 0; j-- {
|
||||
tmp := alpha*btmp[j] - asm.DdotUnitary(a[j*lda+j+1:j*lda+n], btmp[j+1:])
|
||||
if nonUnit {
|
||||
tmp /= a[j*lda+j]
|
||||
}
|
||||
btmp[j] = tmp
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*lda : i*lda+n]
|
||||
for j := 0; j < n; j++ {
|
||||
tmp := alpha*btmp[j] - asm.DdotUnitary(a[j*lda:j*lda+j], btmp)
|
||||
if nonUnit {
|
||||
tmp /= a[j*lda+j]
|
||||
}
|
||||
btmp[j] = tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dsymm performs one of
|
||||
// C = alpha * A * B + beta * C if side == blas.Left
|
||||
// C = alpha * B * A + beta * C if side == blas.Right
|
||||
// where A is an n×n symmetric matrix, B and C are m×n matrices, and alpha
|
||||
// is a scalar.
|
||||
func (Implementation) Dsymm(s blas.Side, ul blas.Uplo, m, n int, alpha float64, a []float64, lda int, b []float64, ldb int, beta float64, c []float64, ldc int) {
|
||||
if s != blas.Right && s != blas.Left {
|
||||
panic("goblas: bad side")
|
||||
}
|
||||
if ul != blas.Lower && ul != blas.Upper {
|
||||
panic(badUplo)
|
||||
}
|
||||
if m < 0 {
|
||||
panic(mLT0)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
var k int
|
||||
if s == blas.Left {
|
||||
k = m
|
||||
} else {
|
||||
k = n
|
||||
}
|
||||
if lda*(k-1)+k > len(a) || lda < max(1, k) {
|
||||
panic(badLdA)
|
||||
}
|
||||
if ldb*(m-1)+n > len(b) || ldb < max(1, n) {
|
||||
panic(badLdB)
|
||||
}
|
||||
if ldc*(m-1)+n > len(c) || ldc < max(1, n) {
|
||||
panic(badLdC)
|
||||
}
|
||||
if m == 0 || n == 0 {
|
||||
return
|
||||
}
|
||||
if alpha == 0 && beta == 1 {
|
||||
return
|
||||
}
|
||||
if alpha == 0 {
|
||||
if beta == 0 {
|
||||
for i := 0; i < m; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
for j := 0; j < n; j++ {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
isUpper := ul == blas.Upper
|
||||
if s == blas.Left {
|
||||
for i := 0; i < m; i++ {
|
||||
atmp := alpha * a[i*lda+i]
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
for j, v := range btmp {
|
||||
ctmp[j] *= beta
|
||||
ctmp[j] += atmp * v
|
||||
}
|
||||
|
||||
for k := 0; k < i; k++ {
|
||||
var atmp float64
|
||||
if isUpper {
|
||||
atmp = a[k*lda+i]
|
||||
} else {
|
||||
atmp = a[i*lda+k]
|
||||
}
|
||||
atmp *= alpha
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
asm.DaxpyUnitary(atmp, b[k*ldb:k*ldb+n], ctmp, ctmp)
|
||||
}
|
||||
for k := i + 1; k < m; k++ {
|
||||
var atmp float64
|
||||
if isUpper {
|
||||
atmp = a[i*lda+k]
|
||||
} else {
|
||||
atmp = a[k*lda+i]
|
||||
}
|
||||
atmp *= alpha
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
asm.DaxpyUnitary(atmp, b[k*ldb:k*ldb+n], ctmp, ctmp)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if isUpper {
|
||||
for i := 0; i < m; i++ {
|
||||
for j := n - 1; j >= 0; j-- {
|
||||
tmp := alpha * b[i*ldb+j]
|
||||
var tmp2 float64
|
||||
atmp := a[j*lda+j+1 : j*lda+n]
|
||||
btmp := b[i*ldb+j+1 : i*ldb+n]
|
||||
ctmp := c[i*ldc+j+1 : i*ldc+n]
|
||||
for k, v := range atmp {
|
||||
ctmp[k] += tmp * v
|
||||
tmp2 += btmp[k] * v
|
||||
}
|
||||
c[i*ldc+j] *= beta
|
||||
c[i*ldc+j] += tmp*a[j*lda+j] + alpha*tmp2
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < n; j++ {
|
||||
tmp := alpha * b[i*ldb+j]
|
||||
var tmp2 float64
|
||||
atmp := a[j*lda : j*lda+j]
|
||||
btmp := b[i*ldb : i*ldb+j]
|
||||
ctmp := c[i*ldc : i*ldc+j]
|
||||
for k, v := range atmp {
|
||||
ctmp[k] += tmp * v
|
||||
tmp2 += btmp[k] * v
|
||||
}
|
||||
c[i*ldc+j] *= beta
|
||||
c[i*ldc+j] += tmp*a[j*lda+j] + alpha*tmp2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dsyrk performs the symmetric rank-k operation
|
||||
// C = alpha * A * A^T + beta*C
|
||||
// C is an n×n symmetric matrix. A is an n×k matrix if tA == blas.NoTrans, and
|
||||
// a k×n matrix otherwise. alpha and beta are scalars.
|
||||
func (Implementation) Dsyrk(ul blas.Uplo, tA blas.Transpose, n, k int, alpha float64, a []float64, lda int, beta float64, c []float64, ldc int) {
|
||||
if ul != blas.Lower && ul != blas.Upper {
|
||||
panic(badUplo)
|
||||
}
|
||||
if tA != blas.Trans && tA != blas.NoTrans && tA != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
if k < 0 {
|
||||
panic(kLT0)
|
||||
}
|
||||
if ldc < n {
|
||||
panic(badLdC)
|
||||
}
|
||||
var row, col int
|
||||
if tA == blas.NoTrans {
|
||||
row, col = n, k
|
||||
} else {
|
||||
row, col = k, n
|
||||
}
|
||||
if lda*(row-1)+col > len(a) || lda < max(1, col) {
|
||||
panic(badLdA)
|
||||
}
|
||||
if ldc*(n-1)+n > len(c) || ldc < max(1, n) {
|
||||
panic(badLdC)
|
||||
}
|
||||
if alpha == 0 {
|
||||
if beta == 0 {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
atmp := a[i*lda : i*lda+k]
|
||||
for jc, vc := range ctmp {
|
||||
j := jc + i
|
||||
ctmp[jc] = vc*beta + alpha*asm.DdotUnitary(atmp, a[j*lda:j*lda+k])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
atmp := a[i*lda : i*lda+k]
|
||||
for j, vc := range c[i*ldc : i*ldc+i+1] {
|
||||
c[i*ldc+j] = vc*beta + alpha*asm.DdotUnitary(a[j*lda:j*lda+k], atmp)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is transposed.
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
if beta != 1 {
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
for l := 0; l < k; l++ {
|
||||
tmp := alpha * a[l*lda+i]
|
||||
if tmp != 0 {
|
||||
asm.DaxpyUnitary(tmp, a[l*lda+i:l*lda+n], ctmp, ctmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
if beta != 0 {
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
for l := 0; l < k; l++ {
|
||||
tmp := alpha * a[l*lda+i]
|
||||
if tmp != 0 {
|
||||
asm.DaxpyUnitary(tmp, a[l*lda:l*lda+i+1], ctmp, ctmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dsyr2k performs the symmetric rank 2k operation
|
||||
// C = alpha * A * B^T + alpha * B * A^T + beta * C
|
||||
// where C is an n×n symmetric matrix. A and B are n×k matrices if
|
||||
// tA == NoTrans and k×n otherwise. alpha and beta are scalars.
|
||||
func (Implementation) Dsyr2k(ul blas.Uplo, tA blas.Transpose, n, k int, alpha float64, a []float64, lda int, b []float64, ldb int, beta float64, c []float64, ldc int) {
|
||||
if ul != blas.Lower && ul != blas.Upper {
|
||||
panic(badUplo)
|
||||
}
|
||||
if tA != blas.Trans && tA != blas.NoTrans && tA != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
if k < 0 {
|
||||
panic(kLT0)
|
||||
}
|
||||
if ldc < n {
|
||||
panic(badLdC)
|
||||
}
|
||||
var row, col int
|
||||
if tA == blas.NoTrans {
|
||||
row, col = n, k
|
||||
} else {
|
||||
row, col = k, n
|
||||
}
|
||||
if lda*(row-1)+col > len(a) || lda < max(1, col) {
|
||||
panic(badLdA)
|
||||
}
|
||||
if ldb*(row-1)+col > len(b) || ldb < max(1, col) {
|
||||
panic(badLdB)
|
||||
}
|
||||
if ldc*(n-1)+n > len(c) || ldc < max(1, n) {
|
||||
panic(badLdC)
|
||||
}
|
||||
if alpha == 0 {
|
||||
if beta == 0 {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
atmp := a[i*lda : i*lda+k]
|
||||
btmp := b[i*lda : i*lda+k]
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
for jc := range ctmp {
|
||||
j := i + jc
|
||||
var tmp1, tmp2 float64
|
||||
binner := b[j*ldb : j*ldb+k]
|
||||
for l, v := range a[j*lda : j*lda+k] {
|
||||
tmp1 += v * btmp[l]
|
||||
tmp2 += atmp[l] * binner[l]
|
||||
}
|
||||
ctmp[jc] *= beta
|
||||
ctmp[jc] += alpha * (tmp1 + tmp2)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
atmp := a[i*lda : i*lda+k]
|
||||
btmp := b[i*lda : i*lda+k]
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
for j := 0; j <= i; j++ {
|
||||
var tmp1, tmp2 float64
|
||||
binner := b[j*ldb : j*ldb+k]
|
||||
for l, v := range a[j*lda : j*lda+k] {
|
||||
tmp1 += v * btmp[l]
|
||||
tmp2 += atmp[l] * binner[l]
|
||||
}
|
||||
ctmp[j] *= beta
|
||||
ctmp[j] += alpha * (tmp1 + tmp2)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
if beta != 1 {
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
for l := 0; l < k; l++ {
|
||||
tmp1 := alpha * b[l*lda+i]
|
||||
tmp2 := alpha * a[l*lda+i]
|
||||
btmp := b[l*ldb+i : l*ldb+n]
|
||||
if tmp1 != 0 || tmp2 != 0 {
|
||||
for j, v := range a[l*lda+i : l*lda+n] {
|
||||
ctmp[j] += v*tmp1 + btmp[j]*tmp2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
if beta != 1 {
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
for l := 0; l < k; l++ {
|
||||
tmp1 := alpha * b[l*lda+i]
|
||||
tmp2 := alpha * a[l*lda+i]
|
||||
btmp := b[l*ldb : l*ldb+i+1]
|
||||
if tmp1 != 0 || tmp2 != 0 {
|
||||
for j, v := range a[l*lda : l*lda+i+1] {
|
||||
ctmp[j] += v*tmp1 + btmp[j]*tmp2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dtrmm performs
|
||||
// B = alpha * A * B if tA == blas.NoTrans and side == blas.Left
|
||||
// B = alpha * A^T * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Left
|
||||
// B = alpha * B * A if tA == blas.NoTrans and side == blas.Right
|
||||
// B = alpha * B * A^T if tA == blas.Trans or blas.ConjTrans, and side == blas.Right
|
||||
// where A is an n×n triangular matrix, and B is an m×n matrix.
|
||||
func (Implementation) Dtrmm(s blas.Side, ul blas.Uplo, tA blas.Transpose, d blas.Diag, m, n int, alpha float64, a []float64, lda int, b []float64, ldb int) {
|
||||
if s != blas.Left && s != blas.Right {
|
||||
panic(badSide)
|
||||
}
|
||||
if ul != blas.Lower && ul != blas.Upper {
|
||||
panic(badUplo)
|
||||
}
|
||||
if tA != blas.NoTrans && tA != blas.Trans && tA != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
if d != blas.NonUnit && d != blas.Unit {
|
||||
panic(badDiag)
|
||||
}
|
||||
if m < 0 {
|
||||
panic(mLT0)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
var k int
|
||||
if s == blas.Left {
|
||||
k = m
|
||||
} else {
|
||||
k = n
|
||||
}
|
||||
if lda*(k-1)+k > len(a) || lda < max(1, k) {
|
||||
panic(badLdA)
|
||||
}
|
||||
if ldb*(m-1)+n > len(b) || ldb < max(1, n) {
|
||||
panic(badLdB)
|
||||
}
|
||||
if alpha == 0 {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j := range btmp {
|
||||
btmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
nonUnit := d == blas.NonUnit
|
||||
if s == blas.Left {
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
tmp := alpha
|
||||
if nonUnit {
|
||||
tmp *= a[i*lda+i]
|
||||
}
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j := range btmp {
|
||||
btmp[j] *= tmp
|
||||
}
|
||||
for ka, va := range a[i*lda+i+1 : i*lda+m] {
|
||||
k := ka + i + 1
|
||||
tmp := alpha * va
|
||||
if tmp != 0 {
|
||||
asm.DaxpyUnitary(tmp, b[k*ldb:k*ldb+n], btmp, btmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := m - 1; i >= 0; i-- {
|
||||
tmp := alpha
|
||||
if nonUnit {
|
||||
tmp *= a[i*lda+i]
|
||||
}
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j := range btmp {
|
||||
btmp[j] *= tmp
|
||||
}
|
||||
for k, va := range a[i*lda : i*lda+i] {
|
||||
tmp := alpha * va
|
||||
if tmp != 0 {
|
||||
asm.DaxpyUnitary(tmp, b[k*ldb:k*ldb+n], btmp, btmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is transposed.
|
||||
if ul == blas.Upper {
|
||||
for k := m - 1; k >= 0; k-- {
|
||||
btmpk := b[k*ldb : k*ldb+n]
|
||||
for ia, va := range a[k*lda+k+1 : k*lda+m] {
|
||||
i := ia + k + 1
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
tmp := alpha * va
|
||||
if tmp != 0 {
|
||||
asm.DaxpyUnitary(tmp, btmpk, btmp, btmp)
|
||||
}
|
||||
}
|
||||
tmp := alpha
|
||||
if nonUnit {
|
||||
tmp *= a[k*lda+k]
|
||||
}
|
||||
if tmp != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for k := 0; k < m; k++ {
|
||||
btmpk := b[k*ldb : k*ldb+n]
|
||||
for i, va := range a[k*lda : k*lda+k] {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
tmp := alpha * va
|
||||
if tmp != 0 {
|
||||
asm.DaxpyUnitary(tmp, btmpk, btmp, btmp)
|
||||
}
|
||||
}
|
||||
tmp := alpha
|
||||
if nonUnit {
|
||||
tmp *= a[k*lda+k]
|
||||
}
|
||||
if tmp != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is on the right
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for k := n - 1; k >= 0; k-- {
|
||||
tmp := alpha * btmp[k]
|
||||
if tmp != 0 {
|
||||
btmp[k] = tmp
|
||||
if nonUnit {
|
||||
btmp[k] *= a[k*lda+k]
|
||||
}
|
||||
for ja, v := range a[k*lda+k+1 : k*lda+n] {
|
||||
j := ja + k + 1
|
||||
btmp[j] += tmp * v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for k := 0; k < n; k++ {
|
||||
tmp := alpha * btmp[k]
|
||||
if tmp != 0 {
|
||||
btmp[k] = tmp
|
||||
if nonUnit {
|
||||
btmp[k] *= a[k*lda+k]
|
||||
}
|
||||
asm.DaxpyUnitary(tmp, a[k*lda:k*lda+k], btmp, btmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is transposed.
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j, vb := range btmp {
|
||||
tmp := vb
|
||||
if nonUnit {
|
||||
tmp *= a[j*lda+j]
|
||||
}
|
||||
tmp += asm.DdotUnitary(a[j*lda+j+1:j*lda+n], btmp[j+1:n])
|
||||
btmp[j] = alpha * tmp
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j := n - 1; j >= 0; j-- {
|
||||
tmp := btmp[j]
|
||||
if nonUnit {
|
||||
tmp *= a[j*lda+j]
|
||||
}
|
||||
tmp += asm.DdotUnitary(a[j*lda:j*lda+j], btmp[:j])
|
||||
btmp[j] = alpha * tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
+843
@@ -0,0 +1,843 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// Copyright ©2014 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/internal/asm"
|
||||
)
|
||||
|
||||
var _ blas.Float32Level3 = Implementation{}
|
||||
|
||||
// Strsm solves
|
||||
// A * X = alpha * B if tA == blas.NoTrans and side == blas.Left
|
||||
// A^T * X = alpha * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Left
|
||||
// X * A = alpha * B if tA == blas.NoTrans and side == blas.Right
|
||||
// X * A^T = alpha * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Right
|
||||
// where A is an n×n triangular matrix, x is an m×n matrix, and alpha is a
|
||||
// scalar.
|
||||
//
|
||||
// At entry to the function, X contains the values of B, and the result is
|
||||
// stored in place into X.
|
||||
//
|
||||
// No check is made that A is invertible.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Strsm(s blas.Side, ul blas.Uplo, tA blas.Transpose, d blas.Diag, m, n int, alpha float32, a []float32, lda int, b []float32, ldb int) {
|
||||
if s != blas.Left && s != blas.Right {
|
||||
panic(badSide)
|
||||
}
|
||||
if ul != blas.Lower && ul != blas.Upper {
|
||||
panic(badUplo)
|
||||
}
|
||||
if tA != blas.NoTrans && tA != blas.Trans && tA != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
if d != blas.NonUnit && d != blas.Unit {
|
||||
panic(badDiag)
|
||||
}
|
||||
if m < 0 {
|
||||
panic(mLT0)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
if ldb < n {
|
||||
panic(badLdB)
|
||||
}
|
||||
var k int
|
||||
if s == blas.Left {
|
||||
k = m
|
||||
} else {
|
||||
k = n
|
||||
}
|
||||
if lda*(k-1)+k > len(a) || lda < max(1, k) {
|
||||
panic(badLdA)
|
||||
}
|
||||
if ldb*(m-1)+n > len(b) || ldb < max(1, n) {
|
||||
panic(badLdB)
|
||||
}
|
||||
|
||||
if m == 0 || n == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if alpha == 0 {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j := range btmp {
|
||||
btmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
nonUnit := d == blas.NonUnit
|
||||
if s == blas.Left {
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := m - 1; i >= 0; i-- {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
if alpha != 1 {
|
||||
for j := range btmp {
|
||||
btmp[j] *= alpha
|
||||
}
|
||||
}
|
||||
for ka, va := range a[i*lda+i+1 : i*lda+m] {
|
||||
k := ka + i + 1
|
||||
if va != 0 {
|
||||
asm.SaxpyUnitary(-va, b[k*ldb:k*ldb+n], btmp, btmp)
|
||||
}
|
||||
}
|
||||
if nonUnit {
|
||||
tmp := 1 / a[i*lda+i]
|
||||
for j := 0; j < n; j++ {
|
||||
btmp[j] *= tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
if alpha != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmp[j] *= alpha
|
||||
}
|
||||
}
|
||||
for k, va := range a[i*lda : i*lda+i] {
|
||||
if va != 0 {
|
||||
asm.SaxpyUnitary(-va, b[k*ldb:k*ldb+n], btmp, btmp)
|
||||
}
|
||||
}
|
||||
if nonUnit {
|
||||
tmp := 1 / a[i*lda+i]
|
||||
for j := 0; j < n; j++ {
|
||||
btmp[j] *= tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is transposed
|
||||
if ul == blas.Upper {
|
||||
for k := 0; k < m; k++ {
|
||||
btmpk := b[k*ldb : k*ldb+n]
|
||||
if nonUnit {
|
||||
tmp := 1 / a[k*lda+k]
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= tmp
|
||||
}
|
||||
}
|
||||
for ia, va := range a[k*lda+k+1 : k*lda+m] {
|
||||
i := ia + k + 1
|
||||
if va != 0 {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
asm.SaxpyUnitary(-va, btmpk, btmp, btmp)
|
||||
}
|
||||
}
|
||||
if alpha != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= alpha
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for k := m - 1; k >= 0; k-- {
|
||||
btmpk := b[k*ldb : k*ldb+n]
|
||||
if nonUnit {
|
||||
tmp := 1 / a[k*lda+k]
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= tmp
|
||||
}
|
||||
}
|
||||
for i, va := range a[k*lda : k*lda+k] {
|
||||
if va != 0 {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
asm.SaxpyUnitary(-va, btmpk, btmp, btmp)
|
||||
}
|
||||
}
|
||||
if alpha != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= alpha
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is to the right of X.
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
if alpha != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmp[j] *= alpha
|
||||
}
|
||||
}
|
||||
for k, vb := range btmp {
|
||||
if vb != 0 {
|
||||
if btmp[k] != 0 {
|
||||
if nonUnit {
|
||||
btmp[k] /= a[k*lda+k]
|
||||
}
|
||||
btmpk := btmp[k+1 : n]
|
||||
asm.SaxpyUnitary(-btmp[k], a[k*lda+k+1:k*lda+n], btmpk, btmpk)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*lda : i*lda+n]
|
||||
if alpha != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmp[j] *= alpha
|
||||
}
|
||||
}
|
||||
for k := n - 1; k >= 0; k-- {
|
||||
if btmp[k] != 0 {
|
||||
if nonUnit {
|
||||
btmp[k] /= a[k*lda+k]
|
||||
}
|
||||
asm.SaxpyUnitary(-btmp[k], a[k*lda:k*lda+k], btmp, btmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is transposed.
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*lda : i*lda+n]
|
||||
for j := n - 1; j >= 0; j-- {
|
||||
tmp := alpha*btmp[j] - asm.SdotUnitary(a[j*lda+j+1:j*lda+n], btmp[j+1:])
|
||||
if nonUnit {
|
||||
tmp /= a[j*lda+j]
|
||||
}
|
||||
btmp[j] = tmp
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*lda : i*lda+n]
|
||||
for j := 0; j < n; j++ {
|
||||
tmp := alpha*btmp[j] - asm.SdotUnitary(a[j*lda:j*lda+j], btmp)
|
||||
if nonUnit {
|
||||
tmp /= a[j*lda+j]
|
||||
}
|
||||
btmp[j] = tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ssymm performs one of
|
||||
// C = alpha * A * B + beta * C if side == blas.Left
|
||||
// C = alpha * B * A + beta * C if side == blas.Right
|
||||
// where A is an n×n symmetric matrix, B and C are m×n matrices, and alpha
|
||||
// is a scalar.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Ssymm(s blas.Side, ul blas.Uplo, m, n int, alpha float32, a []float32, lda int, b []float32, ldb int, beta float32, c []float32, ldc int) {
|
||||
if s != blas.Right && s != blas.Left {
|
||||
panic("goblas: bad side")
|
||||
}
|
||||
if ul != blas.Lower && ul != blas.Upper {
|
||||
panic(badUplo)
|
||||
}
|
||||
if m < 0 {
|
||||
panic(mLT0)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
var k int
|
||||
if s == blas.Left {
|
||||
k = m
|
||||
} else {
|
||||
k = n
|
||||
}
|
||||
if lda*(k-1)+k > len(a) || lda < max(1, k) {
|
||||
panic(badLdA)
|
||||
}
|
||||
if ldb*(m-1)+n > len(b) || ldb < max(1, n) {
|
||||
panic(badLdB)
|
||||
}
|
||||
if ldc*(m-1)+n > len(c) || ldc < max(1, n) {
|
||||
panic(badLdC)
|
||||
}
|
||||
if m == 0 || n == 0 {
|
||||
return
|
||||
}
|
||||
if alpha == 0 && beta == 1 {
|
||||
return
|
||||
}
|
||||
if alpha == 0 {
|
||||
if beta == 0 {
|
||||
for i := 0; i < m; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
for j := 0; j < n; j++ {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
isUpper := ul == blas.Upper
|
||||
if s == blas.Left {
|
||||
for i := 0; i < m; i++ {
|
||||
atmp := alpha * a[i*lda+i]
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
for j, v := range btmp {
|
||||
ctmp[j] *= beta
|
||||
ctmp[j] += atmp * v
|
||||
}
|
||||
|
||||
for k := 0; k < i; k++ {
|
||||
var atmp float32
|
||||
if isUpper {
|
||||
atmp = a[k*lda+i]
|
||||
} else {
|
||||
atmp = a[i*lda+k]
|
||||
}
|
||||
atmp *= alpha
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
asm.SaxpyUnitary(atmp, b[k*ldb:k*ldb+n], ctmp, ctmp)
|
||||
}
|
||||
for k := i + 1; k < m; k++ {
|
||||
var atmp float32
|
||||
if isUpper {
|
||||
atmp = a[i*lda+k]
|
||||
} else {
|
||||
atmp = a[k*lda+i]
|
||||
}
|
||||
atmp *= alpha
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
asm.SaxpyUnitary(atmp, b[k*ldb:k*ldb+n], ctmp, ctmp)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if isUpper {
|
||||
for i := 0; i < m; i++ {
|
||||
for j := n - 1; j >= 0; j-- {
|
||||
tmp := alpha * b[i*ldb+j]
|
||||
var tmp2 float32
|
||||
atmp := a[j*lda+j+1 : j*lda+n]
|
||||
btmp := b[i*ldb+j+1 : i*ldb+n]
|
||||
ctmp := c[i*ldc+j+1 : i*ldc+n]
|
||||
for k, v := range atmp {
|
||||
ctmp[k] += tmp * v
|
||||
tmp2 += btmp[k] * v
|
||||
}
|
||||
c[i*ldc+j] *= beta
|
||||
c[i*ldc+j] += tmp*a[j*lda+j] + alpha*tmp2
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < n; j++ {
|
||||
tmp := alpha * b[i*ldb+j]
|
||||
var tmp2 float32
|
||||
atmp := a[j*lda : j*lda+j]
|
||||
btmp := b[i*ldb : i*ldb+j]
|
||||
ctmp := c[i*ldc : i*ldc+j]
|
||||
for k, v := range atmp {
|
||||
ctmp[k] += tmp * v
|
||||
tmp2 += btmp[k] * v
|
||||
}
|
||||
c[i*ldc+j] *= beta
|
||||
c[i*ldc+j] += tmp*a[j*lda+j] + alpha*tmp2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ssyrk performs the symmetric rank-k operation
|
||||
// C = alpha * A * A^T + beta*C
|
||||
// C is an n×n symmetric matrix. A is an n×k matrix if tA == blas.NoTrans, and
|
||||
// a k×n matrix otherwise. alpha and beta are scalars.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Ssyrk(ul blas.Uplo, tA blas.Transpose, n, k int, alpha float32, a []float32, lda int, beta float32, c []float32, ldc int) {
|
||||
if ul != blas.Lower && ul != blas.Upper {
|
||||
panic(badUplo)
|
||||
}
|
||||
if tA != blas.Trans && tA != blas.NoTrans && tA != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
if k < 0 {
|
||||
panic(kLT0)
|
||||
}
|
||||
if ldc < n {
|
||||
panic(badLdC)
|
||||
}
|
||||
var row, col int
|
||||
if tA == blas.NoTrans {
|
||||
row, col = n, k
|
||||
} else {
|
||||
row, col = k, n
|
||||
}
|
||||
if lda*(row-1)+col > len(a) || lda < max(1, col) {
|
||||
panic(badLdA)
|
||||
}
|
||||
if ldc*(n-1)+n > len(c) || ldc < max(1, n) {
|
||||
panic(badLdC)
|
||||
}
|
||||
if alpha == 0 {
|
||||
if beta == 0 {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
atmp := a[i*lda : i*lda+k]
|
||||
for jc, vc := range ctmp {
|
||||
j := jc + i
|
||||
ctmp[jc] = vc*beta + alpha*asm.SdotUnitary(atmp, a[j*lda:j*lda+k])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
atmp := a[i*lda : i*lda+k]
|
||||
for j, vc := range c[i*ldc : i*ldc+i+1] {
|
||||
c[i*ldc+j] = vc*beta + alpha*asm.SdotUnitary(a[j*lda:j*lda+k], atmp)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is transposed.
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
if beta != 1 {
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
for l := 0; l < k; l++ {
|
||||
tmp := alpha * a[l*lda+i]
|
||||
if tmp != 0 {
|
||||
asm.SaxpyUnitary(tmp, a[l*lda+i:l*lda+n], ctmp, ctmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
if beta != 0 {
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
for l := 0; l < k; l++ {
|
||||
tmp := alpha * a[l*lda+i]
|
||||
if tmp != 0 {
|
||||
asm.SaxpyUnitary(tmp, a[l*lda:l*lda+i+1], ctmp, ctmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ssyr2k performs the symmetric rank 2k operation
|
||||
// C = alpha * A * B^T + alpha * B * A^T + beta * C
|
||||
// where C is an n×n symmetric matrix. A and B are n×k matrices if
|
||||
// tA == NoTrans and k×n otherwise. alpha and beta are scalars.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Ssyr2k(ul blas.Uplo, tA blas.Transpose, n, k int, alpha float32, a []float32, lda int, b []float32, ldb int, beta float32, c []float32, ldc int) {
|
||||
if ul != blas.Lower && ul != blas.Upper {
|
||||
panic(badUplo)
|
||||
}
|
||||
if tA != blas.Trans && tA != blas.NoTrans && tA != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
if k < 0 {
|
||||
panic(kLT0)
|
||||
}
|
||||
if ldc < n {
|
||||
panic(badLdC)
|
||||
}
|
||||
var row, col int
|
||||
if tA == blas.NoTrans {
|
||||
row, col = n, k
|
||||
} else {
|
||||
row, col = k, n
|
||||
}
|
||||
if lda*(row-1)+col > len(a) || lda < max(1, col) {
|
||||
panic(badLdA)
|
||||
}
|
||||
if ldb*(row-1)+col > len(b) || ldb < max(1, col) {
|
||||
panic(badLdB)
|
||||
}
|
||||
if ldc*(n-1)+n > len(c) || ldc < max(1, n) {
|
||||
panic(badLdC)
|
||||
}
|
||||
if alpha == 0 {
|
||||
if beta == 0 {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
atmp := a[i*lda : i*lda+k]
|
||||
btmp := b[i*lda : i*lda+k]
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
for jc := range ctmp {
|
||||
j := i + jc
|
||||
var tmp1, tmp2 float32
|
||||
binner := b[j*ldb : j*ldb+k]
|
||||
for l, v := range a[j*lda : j*lda+k] {
|
||||
tmp1 += v * btmp[l]
|
||||
tmp2 += atmp[l] * binner[l]
|
||||
}
|
||||
ctmp[jc] *= beta
|
||||
ctmp[jc] += alpha * (tmp1 + tmp2)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
atmp := a[i*lda : i*lda+k]
|
||||
btmp := b[i*lda : i*lda+k]
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
for j := 0; j <= i; j++ {
|
||||
var tmp1, tmp2 float32
|
||||
binner := b[j*ldb : j*ldb+k]
|
||||
for l, v := range a[j*lda : j*lda+k] {
|
||||
tmp1 += v * btmp[l]
|
||||
tmp2 += atmp[l] * binner[l]
|
||||
}
|
||||
ctmp[j] *= beta
|
||||
ctmp[j] += alpha * (tmp1 + tmp2)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc+i : i*ldc+n]
|
||||
if beta != 1 {
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
for l := 0; l < k; l++ {
|
||||
tmp1 := alpha * b[l*lda+i]
|
||||
tmp2 := alpha * a[l*lda+i]
|
||||
btmp := b[l*ldb+i : l*ldb+n]
|
||||
if tmp1 != 0 || tmp2 != 0 {
|
||||
for j, v := range a[l*lda+i : l*lda+n] {
|
||||
ctmp[j] += v*tmp1 + btmp[j]*tmp2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+i+1]
|
||||
if beta != 1 {
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
for l := 0; l < k; l++ {
|
||||
tmp1 := alpha * b[l*lda+i]
|
||||
tmp2 := alpha * a[l*lda+i]
|
||||
btmp := b[l*ldb : l*ldb+i+1]
|
||||
if tmp1 != 0 || tmp2 != 0 {
|
||||
for j, v := range a[l*lda : l*lda+i+1] {
|
||||
ctmp[j] += v*tmp1 + btmp[j]*tmp2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strmm performs
|
||||
// B = alpha * A * B if tA == blas.NoTrans and side == blas.Left
|
||||
// B = alpha * A^T * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Left
|
||||
// B = alpha * B * A if tA == blas.NoTrans and side == blas.Right
|
||||
// B = alpha * B * A^T if tA == blas.Trans or blas.ConjTrans, and side == blas.Right
|
||||
// where A is an n×n triangular matrix, and B is an m×n matrix.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Strmm(s blas.Side, ul blas.Uplo, tA blas.Transpose, d blas.Diag, m, n int, alpha float32, a []float32, lda int, b []float32, ldb int) {
|
||||
if s != blas.Left && s != blas.Right {
|
||||
panic(badSide)
|
||||
}
|
||||
if ul != blas.Lower && ul != blas.Upper {
|
||||
panic(badUplo)
|
||||
}
|
||||
if tA != blas.NoTrans && tA != blas.Trans && tA != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
if d != blas.NonUnit && d != blas.Unit {
|
||||
panic(badDiag)
|
||||
}
|
||||
if m < 0 {
|
||||
panic(mLT0)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
var k int
|
||||
if s == blas.Left {
|
||||
k = m
|
||||
} else {
|
||||
k = n
|
||||
}
|
||||
if lda*(k-1)+k > len(a) || lda < max(1, k) {
|
||||
panic(badLdA)
|
||||
}
|
||||
if ldb*(m-1)+n > len(b) || ldb < max(1, n) {
|
||||
panic(badLdB)
|
||||
}
|
||||
if alpha == 0 {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j := range btmp {
|
||||
btmp[j] = 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
nonUnit := d == blas.NonUnit
|
||||
if s == blas.Left {
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
tmp := alpha
|
||||
if nonUnit {
|
||||
tmp *= a[i*lda+i]
|
||||
}
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j := range btmp {
|
||||
btmp[j] *= tmp
|
||||
}
|
||||
for ka, va := range a[i*lda+i+1 : i*lda+m] {
|
||||
k := ka + i + 1
|
||||
tmp := alpha * va
|
||||
if tmp != 0 {
|
||||
asm.SaxpyUnitary(tmp, b[k*ldb:k*ldb+n], btmp, btmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := m - 1; i >= 0; i-- {
|
||||
tmp := alpha
|
||||
if nonUnit {
|
||||
tmp *= a[i*lda+i]
|
||||
}
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j := range btmp {
|
||||
btmp[j] *= tmp
|
||||
}
|
||||
for k, va := range a[i*lda : i*lda+i] {
|
||||
tmp := alpha * va
|
||||
if tmp != 0 {
|
||||
asm.SaxpyUnitary(tmp, b[k*ldb:k*ldb+n], btmp, btmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is transposed.
|
||||
if ul == blas.Upper {
|
||||
for k := m - 1; k >= 0; k-- {
|
||||
btmpk := b[k*ldb : k*ldb+n]
|
||||
for ia, va := range a[k*lda+k+1 : k*lda+m] {
|
||||
i := ia + k + 1
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
tmp := alpha * va
|
||||
if tmp != 0 {
|
||||
asm.SaxpyUnitary(tmp, btmpk, btmp, btmp)
|
||||
}
|
||||
}
|
||||
tmp := alpha
|
||||
if nonUnit {
|
||||
tmp *= a[k*lda+k]
|
||||
}
|
||||
if tmp != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for k := 0; k < m; k++ {
|
||||
btmpk := b[k*ldb : k*ldb+n]
|
||||
for i, va := range a[k*lda : k*lda+k] {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
tmp := alpha * va
|
||||
if tmp != 0 {
|
||||
asm.SaxpyUnitary(tmp, btmpk, btmp, btmp)
|
||||
}
|
||||
}
|
||||
tmp := alpha
|
||||
if nonUnit {
|
||||
tmp *= a[k*lda+k]
|
||||
}
|
||||
if tmp != 1 {
|
||||
for j := 0; j < n; j++ {
|
||||
btmpk[j] *= tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is on the right
|
||||
if tA == blas.NoTrans {
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for k := n - 1; k >= 0; k-- {
|
||||
tmp := alpha * btmp[k]
|
||||
if tmp != 0 {
|
||||
btmp[k] = tmp
|
||||
if nonUnit {
|
||||
btmp[k] *= a[k*lda+k]
|
||||
}
|
||||
for ja, v := range a[k*lda+k+1 : k*lda+n] {
|
||||
j := ja + k + 1
|
||||
btmp[j] += tmp * v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for k := 0; k < n; k++ {
|
||||
tmp := alpha * btmp[k]
|
||||
if tmp != 0 {
|
||||
btmp[k] = tmp
|
||||
if nonUnit {
|
||||
btmp[k] *= a[k*lda+k]
|
||||
}
|
||||
asm.SaxpyUnitary(tmp, a[k*lda:k*lda+k], btmp, btmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Cases where a is transposed.
|
||||
if ul == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j, vb := range btmp {
|
||||
tmp := vb
|
||||
if nonUnit {
|
||||
tmp *= a[j*lda+j]
|
||||
}
|
||||
tmp += asm.SdotUnitary(a[j*lda+j+1:j*lda+n], btmp[j+1:n])
|
||||
btmp[j] = alpha * tmp
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
btmp := b[i*ldb : i*ldb+n]
|
||||
for j := n - 1; j >= 0; j-- {
|
||||
tmp := btmp[j]
|
||||
if nonUnit {
|
||||
tmp *= a[j*lda+j]
|
||||
}
|
||||
tmp += asm.SdotUnitary(a[j*lda:j*lda+j], btmp[:j])
|
||||
btmp[j] = alpha * tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
// 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.
|
||||
|
||||
//go:generate ./single_precision
|
||||
|
||||
package native
|
||||
|
||||
type Implementation struct{}
|
||||
|
||||
// The following are panic strings used during parameter checks.
|
||||
const (
|
||||
negativeN = "blas: n < 0"
|
||||
zeroIncX = "blas: zero x index increment"
|
||||
zeroIncY = "blas: zero y index increment"
|
||||
badLenX = "blas: x index out of range"
|
||||
badLenY = "blas: y index out of range"
|
||||
|
||||
mLT0 = "blas: m < 0"
|
||||
nLT0 = "blas: n < 0"
|
||||
kLT0 = "blas: k < 0"
|
||||
kLLT0 = "blas: kL < 0"
|
||||
kULT0 = "blas: kU < 0"
|
||||
|
||||
badUplo = "blas: illegal triangle"
|
||||
badTranspose = "blas: illegal transpose"
|
||||
badDiag = "blas: illegal diagonal"
|
||||
badSide = "blas: illegal side"
|
||||
|
||||
badLdA = "blas: index of a out of range"
|
||||
badLdB = "blas: index of b out of range"
|
||||
badLdC = "blas: index of c out of range"
|
||||
|
||||
badX = "blas: x index out of range"
|
||||
badY = "blas: y index out of range"
|
||||
)
|
||||
|
||||
// [SD]gemm behavior constants. These are kept here to keep them out of the
|
||||
// way during single precision code genration.
|
||||
const (
|
||||
blockSize = 64 // b x b matrix
|
||||
minParBlock = 4 // minimum number of blocks needed to go parallel
|
||||
buffMul = 4 // how big is the buffer relative to the number of workers
|
||||
)
|
||||
|
||||
// [SD]gemm debugging constant.
|
||||
const debug = false
|
||||
|
||||
// subMul is a common type shared by [SD]gemm.
|
||||
type subMul struct {
|
||||
i, j int // index of block
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a > b {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
+395
@@ -0,0 +1,395 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// Copyright ©2014 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 native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/internal/asm"
|
||||
)
|
||||
|
||||
// Sgemm computes
|
||||
// C = beta * C + alpha * A * B.
|
||||
// tA and tB specify whether A or B are transposed. A, B, and C are m×n dense
|
||||
// matrices.
|
||||
//
|
||||
// Float32 implementations are autogenerated and not directly tested.
|
||||
func (Implementation) Sgemm(tA, tB blas.Transpose, m, n, k int, alpha float32, a []float32, lda int, b []float32, ldb int, beta float32, c []float32, ldc int) {
|
||||
if tA != blas.NoTrans && tA != blas.Trans && tA != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
if tB != blas.NoTrans && tB != blas.Trans && tB != blas.ConjTrans {
|
||||
panic(badTranspose)
|
||||
}
|
||||
|
||||
var amat, bmat, cmat general32
|
||||
if tA != blas.NoTrans {
|
||||
amat = general32{
|
||||
data: a,
|
||||
rows: k,
|
||||
cols: m,
|
||||
stride: lda,
|
||||
}
|
||||
} else {
|
||||
amat = general32{
|
||||
data: a,
|
||||
rows: m,
|
||||
cols: k,
|
||||
stride: lda,
|
||||
}
|
||||
}
|
||||
err := amat.check('a')
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
if tB != blas.NoTrans {
|
||||
bmat = general32{
|
||||
data: b,
|
||||
rows: n,
|
||||
cols: k,
|
||||
stride: ldb,
|
||||
}
|
||||
} else {
|
||||
bmat = general32{
|
||||
data: b,
|
||||
rows: k,
|
||||
cols: n,
|
||||
stride: ldb,
|
||||
}
|
||||
}
|
||||
|
||||
err = bmat.check('b')
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
cmat = general32{
|
||||
data: c,
|
||||
rows: m,
|
||||
cols: n,
|
||||
stride: ldc,
|
||||
}
|
||||
err = cmat.check('c')
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
// scale c
|
||||
if beta != 1 {
|
||||
if beta == 0 {
|
||||
for i := 0; i < m; i++ {
|
||||
ctmp := cmat.data[i*cmat.stride : i*cmat.stride+cmat.cols]
|
||||
for j := range ctmp {
|
||||
ctmp[j] = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < m; i++ {
|
||||
ctmp := cmat.data[i*cmat.stride : i*cmat.stride+cmat.cols]
|
||||
for j := range ctmp {
|
||||
ctmp[j] *= beta
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sgemmParallel(tA, tB, amat, bmat, cmat, alpha)
|
||||
}
|
||||
|
||||
func sgemmParallel(tA, tB blas.Transpose, a, b, c general32, alpha float32) {
|
||||
// dgemmParallel computes a parallel matrix multiplication by partitioning
|
||||
// a and b into sub-blocks, and updating c with the multiplication of the sub-block
|
||||
// In all cases,
|
||||
// A = [ A_11 A_12 ... A_1j
|
||||
// A_21 A_22 ... A_2j
|
||||
// ...
|
||||
// A_i1 A_i2 ... A_ij]
|
||||
//
|
||||
// and same for B. All of the submatrix sizes are blockSize*blockSize except
|
||||
// at the edges.
|
||||
// In all cases, there is one dimension for each matrix along which
|
||||
// C must be updated sequentially.
|
||||
// Cij = \sum_k Aik Bki, (A * B)
|
||||
// Cij = \sum_k Aki Bkj, (A^T * B)
|
||||
// Cij = \sum_k Aik Bjk, (A * B^T)
|
||||
// Cij = \sum_k Aki Bjk, (A^T * B^T)
|
||||
//
|
||||
// This code computes one {i, j} block sequentially along the k dimension,
|
||||
// and computes all of the {i, j} blocks concurrently. This
|
||||
// partitioning allows Cij to be updated in-place without race-conditions.
|
||||
// Instead of launching a goroutine for each possible concurrent computation,
|
||||
// a number of worker goroutines are created and channels are used to pass
|
||||
// available and completed cases.
|
||||
//
|
||||
// http://alexkr.com/docs/matrixmult.pdf is a good reference on matrix-matrix
|
||||
// multiplies, though this code does not copy matrices to attempt to eliminate
|
||||
// cache misses.
|
||||
|
||||
aTrans := tA == blas.Trans || tA == blas.ConjTrans
|
||||
bTrans := tB == blas.Trans || tB == blas.ConjTrans
|
||||
|
||||
maxKLen, parBlocks := computeNumBlocks32(a, b, aTrans, bTrans)
|
||||
if parBlocks < minParBlock {
|
||||
// The matrix multiplication is small in the dimensions where it can be
|
||||
// computed concurrently. Just do it in serial.
|
||||
sgemmSerial(tA, tB, a, b, c, alpha)
|
||||
return
|
||||
}
|
||||
|
||||
nWorkers := runtime.GOMAXPROCS(0)
|
||||
if parBlocks < nWorkers {
|
||||
nWorkers = parBlocks
|
||||
}
|
||||
// There is a tradeoff between the workers having to wait for work
|
||||
// and a large buffer making operations slow.
|
||||
buf := buffMul * nWorkers
|
||||
if buf > parBlocks {
|
||||
buf = parBlocks
|
||||
}
|
||||
|
||||
sendChan := make(chan subMul, buf)
|
||||
|
||||
// Launch workers. A worker receives an {i, j} submatrix of c, and computes
|
||||
// A_ik B_ki (or the transposed version) storing the result in c_ij. When the
|
||||
// channel is finally closed, it signals to the waitgroup that it has finished
|
||||
// computing.
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < nWorkers; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
// Make local copies of otherwise global variables to reduce shared memory.
|
||||
// This has a noticable effect on benchmarks in some cases.
|
||||
alpha := alpha
|
||||
aTrans := aTrans
|
||||
bTrans := bTrans
|
||||
crows := c.rows
|
||||
ccols := c.cols
|
||||
for sub := range sendChan {
|
||||
i := sub.i
|
||||
j := sub.j
|
||||
leni := blockSize
|
||||
if i+leni > crows {
|
||||
leni = crows - i
|
||||
}
|
||||
lenj := blockSize
|
||||
if j+lenj > ccols {
|
||||
lenj = ccols - j
|
||||
}
|
||||
cSub := c.view(i, j, leni, lenj)
|
||||
|
||||
// Compute A_ik B_kj for all k
|
||||
for k := 0; k < maxKLen; k += blockSize {
|
||||
lenk := blockSize
|
||||
if k+lenk > maxKLen {
|
||||
lenk = maxKLen - k
|
||||
}
|
||||
var aSub, bSub general32
|
||||
if aTrans {
|
||||
aSub = a.view(k, i, lenk, leni)
|
||||
} else {
|
||||
aSub = a.view(i, k, leni, lenk)
|
||||
}
|
||||
if bTrans {
|
||||
bSub = b.view(j, k, lenj, lenk)
|
||||
} else {
|
||||
bSub = b.view(k, j, lenk, lenj)
|
||||
}
|
||||
|
||||
sgemmSerial(tA, tB, aSub, bSub, cSub, alpha)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Send out all of the {i, j} subblocks for computation.
|
||||
for i := 0; i < c.rows; i += blockSize {
|
||||
for j := 0; j < c.cols; j += blockSize {
|
||||
sendChan <- subMul{
|
||||
i: i,
|
||||
j: j,
|
||||
}
|
||||
}
|
||||
}
|
||||
close(sendChan)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// computeNumBlocks says how many blocks there are to compute. maxKLen says the length of the
|
||||
// k dimension, parBlocks is the number of blocks that could be computed in parallel
|
||||
// (the submatrices in i and j). expect is the full number of blocks that will be computed.
|
||||
func computeNumBlocks32(a, b general32, aTrans, bTrans bool) (maxKLen, parBlocks int) {
|
||||
aRowBlocks := a.rows / blockSize
|
||||
if a.rows%blockSize != 0 {
|
||||
aRowBlocks++
|
||||
}
|
||||
aColBlocks := a.cols / blockSize
|
||||
if a.cols%blockSize != 0 {
|
||||
aColBlocks++
|
||||
}
|
||||
bRowBlocks := b.rows / blockSize
|
||||
if b.rows%blockSize != 0 {
|
||||
bRowBlocks++
|
||||
}
|
||||
bColBlocks := b.cols / blockSize
|
||||
if b.cols%blockSize != 0 {
|
||||
bColBlocks++
|
||||
}
|
||||
|
||||
switch {
|
||||
case !aTrans && !bTrans:
|
||||
// Cij = \sum_k Aik Bki
|
||||
maxKLen = a.cols
|
||||
parBlocks = aRowBlocks * bColBlocks
|
||||
case aTrans && !bTrans:
|
||||
// Cij = \sum_k Aki Bkj
|
||||
maxKLen = a.rows
|
||||
parBlocks = aColBlocks * bColBlocks
|
||||
case !aTrans && bTrans:
|
||||
// Cij = \sum_k Aik Bjk
|
||||
maxKLen = a.cols
|
||||
parBlocks = aRowBlocks * bRowBlocks
|
||||
case aTrans && bTrans:
|
||||
// Cij = \sum_k Aki Bjk
|
||||
maxKLen = a.rows
|
||||
parBlocks = aColBlocks * bRowBlocks
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// sgemmSerial is serial matrix multiply
|
||||
func sgemmSerial(tA, tB blas.Transpose, a, b, c general32, alpha float32) {
|
||||
switch {
|
||||
case tA == blas.NoTrans && tB == blas.NoTrans:
|
||||
sgemmSerialNotNot(a, b, c, alpha)
|
||||
return
|
||||
case tA != blas.NoTrans && tB == blas.NoTrans:
|
||||
sgemmSerialTransNot(a, b, c, alpha)
|
||||
return
|
||||
case tA == blas.NoTrans && tB != blas.NoTrans:
|
||||
sgemmSerialNotTrans(a, b, c, alpha)
|
||||
return
|
||||
case tA != blas.NoTrans && tB != blas.NoTrans:
|
||||
sgemmSerialTransTrans(a, b, c, alpha)
|
||||
return
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// sgemmSerial where neither a nor b are transposed
|
||||
func sgemmSerialNotNot(a, b, c general32, alpha float32) {
|
||||
if debug {
|
||||
if a.cols != b.rows {
|
||||
panic("inner dimension mismatch")
|
||||
}
|
||||
if a.rows != c.rows {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
if b.cols != c.cols {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
// This style is used instead of the literal [i*stride +j]) is used because
|
||||
// approximately 5 times faster as of go 1.3.
|
||||
for i := 0; i < a.rows; i++ {
|
||||
ctmp := c.data[i*c.stride : i*c.stride+c.cols]
|
||||
for l, v := range a.data[i*a.stride : i*a.stride+a.cols] {
|
||||
tmp := alpha * v
|
||||
if tmp != 0 {
|
||||
asm.SaxpyUnitary(tmp, b.data[l*b.stride:l*b.stride+b.cols], ctmp, ctmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sgemmSerial where neither a is transposed and b is not
|
||||
func sgemmSerialTransNot(a, b, c general32, alpha float32) {
|
||||
if debug {
|
||||
if a.rows != b.rows {
|
||||
fmt.Println(a.rows, b.rows)
|
||||
panic("inner dimension mismatch")
|
||||
}
|
||||
if a.cols != c.rows {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
if b.cols != c.cols {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
// This style is used instead of the literal [i*stride +j]) is used because
|
||||
// approximately 5 times faster as of go 1.3.
|
||||
for l := 0; l < a.rows; l++ {
|
||||
btmp := b.data[l*b.stride : l*b.stride+b.cols]
|
||||
for i, v := range a.data[l*a.stride : l*a.stride+a.cols] {
|
||||
tmp := alpha * v
|
||||
ctmp := c.data[i*c.stride : i*c.stride+c.cols]
|
||||
if tmp != 0 {
|
||||
asm.SaxpyUnitary(tmp, btmp, ctmp, ctmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sgemmSerial where neither a is not transposed and b is
|
||||
func sgemmSerialNotTrans(a, b, c general32, alpha float32) {
|
||||
if debug {
|
||||
if a.cols != b.cols {
|
||||
panic("inner dimension mismatch")
|
||||
}
|
||||
if a.rows != c.rows {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
if b.rows != c.cols {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
// This style is used instead of the literal [i*stride +j]) is used because
|
||||
// approximately 5 times faster as of go 1.3.
|
||||
for i := 0; i < a.rows; i++ {
|
||||
atmp := a.data[i*a.stride : i*a.stride+a.cols]
|
||||
ctmp := c.data[i*c.stride : i*c.stride+c.cols]
|
||||
for j := 0; j < b.rows; j++ {
|
||||
ctmp[j] += alpha * asm.SdotUnitary(atmp, b.data[j*b.stride:j*b.stride+b.cols])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// sgemmSerial where both are transposed
|
||||
func sgemmSerialTransTrans(a, b, c general32, alpha float32) {
|
||||
if debug {
|
||||
if a.rows != b.cols {
|
||||
panic("inner dimension mismatch")
|
||||
}
|
||||
if a.cols != c.rows {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
if b.rows != c.cols {
|
||||
panic("outer dimension mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
// This style is used instead of the literal [i*stride +j]) is used because
|
||||
// approximately 5 times faster as of go 1.3.
|
||||
for l := 0; l < a.rows; l++ {
|
||||
for i, v := range a.data[l*a.stride : l*a.stride+a.cols] {
|
||||
ctmp := c.data[i*c.stride : i*c.stride+c.cols]
|
||||
if v != 0 {
|
||||
tmp := alpha * v
|
||||
if tmp != 0 {
|
||||
asm.SaxpyInc(tmp, b.data[l:], ctmp, uintptr(b.rows), uintptr(b.stride), 1, 0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# 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.
|
||||
|
||||
WARNING='//\
|
||||
// Float32 implementations are autogenerated and not directly tested.\
|
||||
'
|
||||
|
||||
# Level1 routines.
|
||||
|
||||
echo Generating level1single.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > level1single.go
|
||||
cat level1double.go \
|
||||
| gofmt -r 'blas.Float64Level1 -> blas.Float32Level1' \
|
||||
\
|
||||
| gofmt -r 'float64 -> float32' \
|
||||
| gofmt -r 'blas.DrotmParams -> blas.SrotmParams' \
|
||||
\
|
||||
| gofmt -r 'asm.DaxpyInc -> asm.SaxpyInc' \
|
||||
| gofmt -r 'asm.DaxpyUnitary -> asm.SaxpyUnitary' \
|
||||
| gofmt -r 'asm.DdotInc -> asm.SdotInc' \
|
||||
| gofmt -r 'asm.DdotUnitary -> asm.SdotUnitary' \
|
||||
\
|
||||
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNING\1S\2_" \
|
||||
-e 's_^// D_// S_' \
|
||||
-e "s_^\(func (Implementation) \)Id\(.*\)\$_$WARNING\1Is\2_" \
|
||||
-e 's_^// Id_// Is_' \
|
||||
-e 's_"math"_math "github.com/gonum/blas/native/internal/math32"_' \
|
||||
>> level1single.go
|
||||
|
||||
echo Generating level1single_sdot.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > level1single_sdot.go
|
||||
cat level1double_ddot.go \
|
||||
| gofmt -r 'float64 -> float32' \
|
||||
\
|
||||
| gofmt -r 'asm.DdotInc -> asm.SdotInc' \
|
||||
| gofmt -r 'asm.DdotUnitary -> asm.SdotUnitary' \
|
||||
\
|
||||
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNING\1S\2_" \
|
||||
-e 's_^// D_// S_' \
|
||||
>> level1single_sdot.go
|
||||
|
||||
echo Generating level1single_dsdot.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > level1single_dsdot.go
|
||||
cat level1double_ddot.go \
|
||||
| gofmt -r '[]float64 -> []float32' \
|
||||
\
|
||||
| gofmt -r 'asm.DdotInc -> asm.DsdotInc' \
|
||||
| gofmt -r 'asm.DdotUnitary -> asm.DsdotUnitary' \
|
||||
\
|
||||
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNING\1Ds\2_" \
|
||||
-e 's_^// D_// Ds_' \
|
||||
>> level1single_dsdot.go
|
||||
|
||||
echo Generating level1single_sdsdot.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > level1single_sdsdot.go
|
||||
cat level1double_ddot.go \
|
||||
| gofmt -r 'float64 -> float32' \
|
||||
\
|
||||
| gofmt -r 'asm.DdotInc(x, y, f(n), f(incX), f(incY), f(ix), f(iy)) -> alpha + float32(asm.DsdotInc(x, y, f(n), f(incX), f(incY), f(ix), f(iy)))' \
|
||||
| gofmt -r 'asm.DdotUnitary(a, b) -> alpha + float32(asm.DsdotUnitary(a, b))' \
|
||||
\
|
||||
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNING\1Sds\2_" \
|
||||
-e 's_^// D\(.*\)$_// Sds\1 plus a constant_' \
|
||||
-e 's_\\sum_alpha + \\sum_' \
|
||||
-e 's/n int/n int, alpha float32/' \
|
||||
>> level1single_sdsdot.go
|
||||
|
||||
|
||||
# Level2 routines.
|
||||
|
||||
echo Generating level2single.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > level2single.go
|
||||
cat level2double.go \
|
||||
| gofmt -r 'blas.Float64Level2 -> blas.Float32Level2' \
|
||||
\
|
||||
| gofmt -r 'float64 -> float32' \
|
||||
\
|
||||
| gofmt -r 'Dscal -> Sscal' \
|
||||
\
|
||||
| gofmt -r 'asm.DaxpyInc -> asm.SaxpyInc' \
|
||||
| gofmt -r 'asm.DaxpyUnitary -> asm.SaxpyUnitary' \
|
||||
| gofmt -r 'asm.DdotInc -> asm.SdotInc' \
|
||||
| gofmt -r 'asm.DdotUnitary -> asm.SdotUnitary' \
|
||||
\
|
||||
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNING\1S\2_" \
|
||||
-e 's_^// D_// S_' \
|
||||
>> level2single.go
|
||||
|
||||
|
||||
# Level3 routines.
|
||||
|
||||
echo Generating level3single.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > level3single.go
|
||||
cat level3double.go \
|
||||
| gofmt -r 'blas.Float64Level3 -> blas.Float32Level3' \
|
||||
\
|
||||
| gofmt -r 'float64 -> float32' \
|
||||
\
|
||||
| gofmt -r 'asm.DaxpyUnitary -> asm.SaxpyUnitary' \
|
||||
| gofmt -r 'asm.DdotUnitary -> asm.SdotUnitary' \
|
||||
\
|
||||
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNING\1S\2_" \
|
||||
-e 's_^// D_// S_' \
|
||||
>> level3single.go
|
||||
|
||||
echo Generating general_single.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > general_single.go
|
||||
cat general_double.go \
|
||||
| gofmt -r 'float64 -> float32' \
|
||||
\
|
||||
| gofmt -r 'general64 -> general32' \
|
||||
| gofmt -r 'newGeneral64 -> newGeneral32' \
|
||||
\
|
||||
| sed -e 's/(g general64) print()/(g general32) print()/' \
|
||||
-e 's_"math"_math "github.com/gonum/blas/native/internal/math32"_' \
|
||||
>> general_single.go
|
||||
|
||||
echo Generating sgemm.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > sgemm.go
|
||||
cat dgemm.go \
|
||||
| gofmt -r 'float64 -> float32' \
|
||||
| gofmt -r 'general64 -> general32' \
|
||||
\
|
||||
| gofmt -r 'dgemmParallel -> sgemmParallel' \
|
||||
| gofmt -r 'computeNumBlocks64 -> computeNumBlocks32' \
|
||||
| gofmt -r 'dgemmSerial -> sgemmSerial' \
|
||||
| gofmt -r 'dgemmSerialNotNot -> sgemmSerialNotNot' \
|
||||
| gofmt -r 'dgemmSerialTransNot -> sgemmSerialTransNot' \
|
||||
| gofmt -r 'dgemmSerialNotTrans -> sgemmSerialNotTrans' \
|
||||
| gofmt -r 'dgemmSerialTransTrans -> sgemmSerialTransTrans' \
|
||||
\
|
||||
| gofmt -r 'asm.DaxpyInc -> asm.SaxpyInc' \
|
||||
| gofmt -r 'asm.DaxpyUnitary -> asm.SaxpyUnitary' \
|
||||
| gofmt -r 'asm.DdotInc -> asm.SdotInc' \
|
||||
| gofmt -r 'asm.DdotUnitary -> asm.SdotUnitary' \
|
||||
\
|
||||
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNING\1S\2_" \
|
||||
-e 's_^// D_// S_' \
|
||||
-e 's_^// d_// s_' \
|
||||
>> sgemm.go
|
||||
Generated
+1
@@ -0,0 +1 @@
|
||||
test.out
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
language: go
|
||||
|
||||
# Versions of go that are explicitly supported by gonum.
|
||||
go:
|
||||
- 1.5beta1
|
||||
- 1.3.3
|
||||
- 1.4.2
|
||||
|
||||
# Required for coverage.
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
|
||||
# Get deps, build, test, and ensure the code is gofmt'ed.
|
||||
# If we are building as gonum, then we have access to the coveralls api key, so we can run coverage as well.
|
||||
script:
|
||||
- go get -d -t -v ./...
|
||||
- go build -v ./...
|
||||
- go test -v ./...
|
||||
- diff <(gofmt -d .) <("")
|
||||
- if [[ $TRAVIS_SECURE_ENV_VARS = "true" ]]; then bash ./.travis/test-coverage.sh; fi
|
||||
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
- jragonmiris@gmail.com
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# Gonum Graph [](https://travis-ci.org/gonum/graph) [](https://coveralls.io/r/gonum/graph?branch=master)
|
||||
|
||||
This is a generalized graph package for the Go language. It aims to provide a clean, transparent API for common algorithms on arbitrary graphs such as finding the graph's strongly connected components, dominators, or searces.
|
||||
|
||||
The package is currently in testing, and the API is "semi-stable". The signatures of any functions like AStar are unlikely to change much, but the Graph, Node, and Edge interfaces may change a bit.
|
||||
|
||||
## Issues
|
||||
|
||||
If you find any bugs, feel free to file an issue on the github issue tracker. Discussions on API changes, added features, code review, or similar requests are preferred on the Gonum-dev Google Group.
|
||||
|
||||
https://groups.google.com/forum/#!forum/gonum-dev
|
||||
|
||||
## License
|
||||
|
||||
Please see github.com/gonum/license for general license information, contributors, authors, etc on the Gonum suite of packages.
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// Copyright ©2014 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 concrete
|
||||
|
||||
// TODO(anyone) Package level documentation for this describing the overall
|
||||
// reason for the package and a summary for the provided types.
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
// Copyright ©2014 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 concrete
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/matrix/mat64"
|
||||
)
|
||||
|
||||
// DirectedDenseGraph represents a graph such that all IDs are in a contiguous
|
||||
// block from 0 to n-1.
|
||||
type DirectedDenseGraph struct {
|
||||
absent float64
|
||||
mat *mat64.Dense
|
||||
}
|
||||
|
||||
// NewDirectedDenseGraph creates a directed dense graph with n nodes.
|
||||
// If passable is true all pairs of nodes will be connected by an edge
|
||||
// with unit cost, otherwise every node will start unconnected with
|
||||
// the cost specified by absent.
|
||||
func NewDirectedDenseGraph(n int, passable bool, absent float64) *DirectedDenseGraph {
|
||||
mat := make([]float64, n*n)
|
||||
v := 1.
|
||||
if !passable {
|
||||
v = absent
|
||||
}
|
||||
for i := range mat {
|
||||
mat[i] = v
|
||||
}
|
||||
return &DirectedDenseGraph{mat: mat64.NewDense(n, n, mat), absent: absent}
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) Has(n graph.Node) bool {
|
||||
id := n.ID()
|
||||
r, _ := g.mat.Dims()
|
||||
return 0 <= id && id < r
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) Nodes() []graph.Node {
|
||||
r, _ := g.mat.Dims()
|
||||
nodes := make([]graph.Node, r)
|
||||
for i := 0; i < r; i++ {
|
||||
nodes[i] = Node(i)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) Edges() []graph.Edge {
|
||||
var edges []graph.Edge
|
||||
r, _ := g.mat.Dims()
|
||||
for i := 0; i < r; i++ {
|
||||
for j := 0; j < r; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
if !isSame(g.mat.At(i, j), g.absent) {
|
||||
edges = append(edges, Edge{Node(i), Node(j)})
|
||||
}
|
||||
}
|
||||
}
|
||||
return edges
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) From(n graph.Node) []graph.Node {
|
||||
var neighbors []graph.Node
|
||||
id := n.ID()
|
||||
_, c := g.mat.Dims()
|
||||
for j := 0; j < c; j++ {
|
||||
if j == id {
|
||||
continue
|
||||
}
|
||||
if !isSame(g.mat.At(id, j), g.absent) {
|
||||
neighbors = append(neighbors, Node(j))
|
||||
}
|
||||
}
|
||||
return neighbors
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) To(n graph.Node) []graph.Node {
|
||||
var neighbors []graph.Node
|
||||
id := n.ID()
|
||||
r, _ := g.mat.Dims()
|
||||
for i := 0; i < r; i++ {
|
||||
if i == id {
|
||||
continue
|
||||
}
|
||||
if !isSame(g.mat.At(i, id), g.absent) {
|
||||
neighbors = append(neighbors, Node(i))
|
||||
}
|
||||
}
|
||||
return neighbors
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) HasEdge(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
return xid != yid && (!isSame(g.mat.At(xid, yid), g.absent) || !isSame(g.mat.At(yid, xid), g.absent))
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
if g.HasEdge(u, v) {
|
||||
return Edge{u, v}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
uid := u.ID()
|
||||
vid := v.ID()
|
||||
return uid != vid && !isSame(g.mat.At(uid, vid), g.absent)
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) Weight(e graph.Edge) float64 {
|
||||
return g.mat.At(e.From().ID(), e.To().ID())
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) SetEdgeWeight(e graph.Edge, weight float64) {
|
||||
fid := e.From().ID()
|
||||
tid := e.To().ID()
|
||||
if fid == tid {
|
||||
panic("concrete: set edge cost of illegal edge")
|
||||
}
|
||||
g.mat.Set(fid, tid, weight)
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) RemoveEdge(e graph.Edge) {
|
||||
g.mat.Set(e.From().ID(), e.To().ID(), g.absent)
|
||||
}
|
||||
|
||||
func (g *DirectedDenseGraph) Matrix() mat64.Matrix {
|
||||
// Prevent alteration of dimensions of the returned matrix.
|
||||
m := *g.mat
|
||||
return &m
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
// Copyright ©2014 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 concrete
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/matrix/mat64"
|
||||
)
|
||||
|
||||
// UndirectedDenseGraph represents a graph such that all IDs are in a contiguous
|
||||
// block from 0 to n-1.
|
||||
type UndirectedDenseGraph struct {
|
||||
absent float64
|
||||
mat *mat64.SymDense
|
||||
}
|
||||
|
||||
// NewUndirectedDenseGraph creates an undirected dense graph with n nodes.
|
||||
// If passable is true all pairs of nodes will be connected by an edge
|
||||
// with unit cost, otherwise every node will start unconnected with
|
||||
// the cost specified by absent.
|
||||
func NewUndirectedDenseGraph(n int, passable bool, absent float64) *UndirectedDenseGraph {
|
||||
mat := make([]float64, n*n)
|
||||
v := 1.
|
||||
if !passable {
|
||||
v = absent
|
||||
}
|
||||
for i := range mat {
|
||||
mat[i] = v
|
||||
}
|
||||
return &UndirectedDenseGraph{mat: mat64.NewSymDense(n, mat), absent: absent}
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) Has(n graph.Node) bool {
|
||||
id := n.ID()
|
||||
r := g.mat.Symmetric()
|
||||
return 0 <= id && id < r
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) Nodes() []graph.Node {
|
||||
r := g.mat.Symmetric()
|
||||
nodes := make([]graph.Node, r)
|
||||
for i := 0; i < r; i++ {
|
||||
nodes[i] = Node(i)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) Edges() []graph.Edge {
|
||||
var edges []graph.Edge
|
||||
r, _ := g.mat.Dims()
|
||||
for i := 0; i < r; i++ {
|
||||
for j := i + 1; j < r; j++ {
|
||||
if !isSame(g.mat.At(i, j), g.absent) {
|
||||
edges = append(edges, Edge{Node(i), Node(j)})
|
||||
}
|
||||
}
|
||||
}
|
||||
return edges
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) Degree(n graph.Node) int {
|
||||
id := n.ID()
|
||||
var deg int
|
||||
r := g.mat.Symmetric()
|
||||
for i := 0; i < r; i++ {
|
||||
if i == id {
|
||||
continue
|
||||
}
|
||||
if !isSame(g.mat.At(id, i), g.absent) {
|
||||
deg++
|
||||
}
|
||||
}
|
||||
return deg
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) From(n graph.Node) []graph.Node {
|
||||
var neighbors []graph.Node
|
||||
id := n.ID()
|
||||
r := g.mat.Symmetric()
|
||||
for i := 0; i < r; i++ {
|
||||
if i == id {
|
||||
continue
|
||||
}
|
||||
if !isSame(g.mat.At(id, i), g.absent) {
|
||||
neighbors = append(neighbors, Node(i))
|
||||
}
|
||||
}
|
||||
return neighbors
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) HasEdge(u, v graph.Node) bool {
|
||||
uid := u.ID()
|
||||
vid := v.ID()
|
||||
return uid != vid && !isSame(g.mat.At(uid, vid), g.absent)
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.EdgeBetween(u, v)
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) EdgeBetween(u, v graph.Node) graph.Edge {
|
||||
if g.HasEdge(u, v) {
|
||||
return Edge{u, v}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) Weight(e graph.Edge) float64 {
|
||||
return g.mat.At(e.From().ID(), e.To().ID())
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) SetEdgeWeight(e graph.Edge, weight float64) {
|
||||
fid := e.From().ID()
|
||||
tid := e.To().ID()
|
||||
if fid == tid {
|
||||
panic("concrete: set edge cost of illegal edge")
|
||||
}
|
||||
g.mat.SetSym(fid, tid, weight)
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) RemoveEdge(e graph.Edge) {
|
||||
g.mat.SetSym(e.From().ID(), e.To().ID(), g.absent)
|
||||
}
|
||||
|
||||
func (g *UndirectedDenseGraph) Matrix() mat64.Matrix {
|
||||
// Prevent alteration of dimensions of the returned matrix.
|
||||
m := *g.mat
|
||||
return &m
|
||||
}
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
// Copyright ©2014 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 concrete
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
)
|
||||
|
||||
// A Directed graph is a highly generalized MutableDirectedGraph.
|
||||
//
|
||||
// In most cases it's likely more desireable to use a graph specific to your
|
||||
// problem domain.
|
||||
type DirectedGraph struct {
|
||||
successors map[int]map[int]WeightedEdge
|
||||
predecessors map[int]map[int]WeightedEdge
|
||||
nodeMap map[int]graph.Node
|
||||
|
||||
// Add/remove convenience variables
|
||||
maxID int
|
||||
freeMap map[int]struct{}
|
||||
}
|
||||
|
||||
func NewDirectedGraph() *DirectedGraph {
|
||||
return &DirectedGraph{
|
||||
successors: make(map[int]map[int]WeightedEdge),
|
||||
predecessors: make(map[int]map[int]WeightedEdge),
|
||||
nodeMap: make(map[int]graph.Node),
|
||||
maxID: 0,
|
||||
freeMap: make(map[int]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) NewNodeID() int {
|
||||
if g.maxID != maxInt {
|
||||
g.maxID++
|
||||
return g.maxID
|
||||
}
|
||||
|
||||
// Implicitly checks if len(g.freeMap) == 0
|
||||
for id := range g.freeMap {
|
||||
return id
|
||||
}
|
||||
|
||||
// I cannot foresee this ever happening, but just in case
|
||||
if len(g.nodeMap) == maxInt {
|
||||
panic("cannot allocate node: graph too large")
|
||||
}
|
||||
|
||||
for i := 0; i < maxInt; i++ {
|
||||
if _, ok := g.nodeMap[i]; !ok {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
// Should not happen.
|
||||
panic("cannot allocate node id: no free id found")
|
||||
}
|
||||
|
||||
// Adds a node to the graph. Implementation note: if you add a node close to or at
|
||||
// the max int on your machine NewNode will become slower.
|
||||
func (g *DirectedGraph) AddNode(n graph.Node) {
|
||||
if _, exists := g.nodeMap[n.ID()]; exists {
|
||||
panic(fmt.Sprintf("concrete: node ID collision: %d", n.ID()))
|
||||
}
|
||||
g.nodeMap[n.ID()] = n
|
||||
g.successors[n.ID()] = make(map[int]WeightedEdge)
|
||||
g.predecessors[n.ID()] = make(map[int]WeightedEdge)
|
||||
|
||||
delete(g.freeMap, n.ID())
|
||||
g.maxID = max(g.maxID, n.ID())
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) SetEdge(e graph.Edge, cost float64) {
|
||||
var (
|
||||
from = e.From()
|
||||
fid = from.ID()
|
||||
to = e.To()
|
||||
tid = to.ID()
|
||||
)
|
||||
|
||||
if fid == tid {
|
||||
panic("concrete: adding self edge")
|
||||
}
|
||||
|
||||
if !g.Has(from) {
|
||||
g.AddNode(from)
|
||||
}
|
||||
|
||||
if !g.Has(to) {
|
||||
g.AddNode(to)
|
||||
}
|
||||
|
||||
g.successors[fid][tid] = WeightedEdge{Edge: e, Cost: cost}
|
||||
g.predecessors[tid][fid] = WeightedEdge{Edge: e, Cost: cost}
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) RemoveNode(n graph.Node) {
|
||||
if _, ok := g.nodeMap[n.ID()]; !ok {
|
||||
return
|
||||
}
|
||||
delete(g.nodeMap, n.ID())
|
||||
|
||||
for succ := range g.successors[n.ID()] {
|
||||
delete(g.predecessors[succ], n.ID())
|
||||
}
|
||||
delete(g.successors, n.ID())
|
||||
|
||||
for pred := range g.predecessors[n.ID()] {
|
||||
delete(g.successors[pred], n.ID())
|
||||
}
|
||||
delete(g.predecessors, n.ID())
|
||||
|
||||
g.maxID-- // Fun facts: even if this ID doesn't exist this still works!
|
||||
g.freeMap[n.ID()] = struct{}{}
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) RemoveEdge(e graph.Edge) {
|
||||
from, to := e.From(), e.To()
|
||||
if _, ok := g.nodeMap[from.ID()]; !ok {
|
||||
return
|
||||
} else if _, ok := g.nodeMap[to.ID()]; !ok {
|
||||
return
|
||||
}
|
||||
|
||||
delete(g.successors[from.ID()], to.ID())
|
||||
delete(g.predecessors[to.ID()], from.ID())
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) EmptyGraph() {
|
||||
g.successors = make(map[int]map[int]WeightedEdge)
|
||||
g.predecessors = make(map[int]map[int]WeightedEdge)
|
||||
g.nodeMap = make(map[int]graph.Node)
|
||||
}
|
||||
|
||||
/* Graph implementation */
|
||||
|
||||
func (g *DirectedGraph) From(n graph.Node) []graph.Node {
|
||||
if _, ok := g.successors[n.ID()]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
successors := make([]graph.Node, len(g.successors[n.ID()]))
|
||||
i := 0
|
||||
for succ := range g.successors[n.ID()] {
|
||||
successors[i] = g.nodeMap[succ]
|
||||
i++
|
||||
}
|
||||
|
||||
return successors
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) HasEdge(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
if _, ok := g.nodeMap[xid]; !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := g.nodeMap[yid]; !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := g.successors[xid][yid]; ok {
|
||||
return true
|
||||
}
|
||||
_, ok := g.successors[yid][xid]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
if _, ok := g.nodeMap[u.ID()]; !ok {
|
||||
return nil
|
||||
}
|
||||
if _, ok := g.nodeMap[v.ID()]; !ok {
|
||||
return nil
|
||||
}
|
||||
edge, ok := g.successors[u.ID()][v.ID()]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return edge.Edge
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
if _, ok := g.nodeMap[u.ID()]; !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := g.nodeMap[v.ID()]; !ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := g.successors[u.ID()][v.ID()]; !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) To(n graph.Node) []graph.Node {
|
||||
if _, ok := g.successors[n.ID()]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
predecessors := make([]graph.Node, len(g.predecessors[n.ID()]))
|
||||
i := 0
|
||||
for succ := range g.predecessors[n.ID()] {
|
||||
predecessors[i] = g.nodeMap[succ]
|
||||
i++
|
||||
}
|
||||
|
||||
return predecessors
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) Node(id int) graph.Node {
|
||||
return g.nodeMap[id]
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) Has(n graph.Node) bool {
|
||||
_, ok := g.nodeMap[n.ID()]
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) Degree(n graph.Node) int {
|
||||
if _, ok := g.nodeMap[n.ID()]; !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
return len(g.successors[n.ID()]) + len(g.predecessors[n.ID()])
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) Nodes() []graph.Node {
|
||||
nodes := make([]graph.Node, len(g.successors))
|
||||
i := 0
|
||||
for _, n := range g.nodeMap {
|
||||
nodes[i] = n
|
||||
i++
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) Weight(e graph.Edge) float64 {
|
||||
if s, ok := g.successors[e.From().ID()]; ok {
|
||||
if we, ok := s[e.To().ID()]; ok {
|
||||
return we.Cost
|
||||
}
|
||||
}
|
||||
return inf
|
||||
}
|
||||
|
||||
func (g *DirectedGraph) Edges() []graph.Edge {
|
||||
edgeList := make([]graph.Edge, 0, len(g.successors))
|
||||
edgeMap := make(map[int]map[int]struct{}, len(g.successors))
|
||||
for n, succMap := range g.successors {
|
||||
edgeMap[n] = make(map[int]struct{}, len(succMap))
|
||||
for succ, edge := range succMap {
|
||||
if doneMap, ok := edgeMap[succ]; ok {
|
||||
if _, ok := doneMap[n]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
edgeList = append(edgeList, edge)
|
||||
edgeMap[n][succ] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return edgeList
|
||||
}
|
||||
+250
@@ -0,0 +1,250 @@
|
||||
// Copyright ©2014 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 concrete
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
)
|
||||
|
||||
// A simple int alias.
|
||||
type Node int
|
||||
|
||||
func (n Node) ID() int {
|
||||
return int(n)
|
||||
}
|
||||
|
||||
// Just a collection of two nodes
|
||||
type Edge struct {
|
||||
F, T graph.Node
|
||||
}
|
||||
|
||||
func (e Edge) From() graph.Node {
|
||||
return e.F
|
||||
}
|
||||
|
||||
func (e Edge) To() graph.Node {
|
||||
return e.T
|
||||
}
|
||||
|
||||
type WeightedEdge struct {
|
||||
graph.Edge
|
||||
Cost float64
|
||||
}
|
||||
|
||||
// A GonumGraph is a very generalized graph that can handle an arbitrary number of vertices and
|
||||
// edges -- as well as act as either directed or undirected.
|
||||
//
|
||||
// Internally, it uses a map of successors AND predecessors, to speed up some operations (such as
|
||||
// getting all successors/predecessors). It also speeds up things like adding edges (assuming both
|
||||
// edges exist).
|
||||
//
|
||||
// However, its generality is also its weakness (and partially a flaw in needing to satisfy
|
||||
// MutableGraph). For most purposes, creating your own graph is probably better. For instance,
|
||||
// see TileGraph for an example of an immutable 2D grid of tiles that also implements the Graph
|
||||
// interface, but would be more suitable if all you needed was a simple undirected 2D grid.
|
||||
type Graph struct {
|
||||
neighbors map[int]map[int]WeightedEdge
|
||||
nodeMap map[int]graph.Node
|
||||
|
||||
// Node add/remove convenience vars
|
||||
maxID int
|
||||
freeMap map[int]struct{}
|
||||
}
|
||||
|
||||
func NewGraph() *Graph {
|
||||
return &Graph{
|
||||
neighbors: make(map[int]map[int]WeightedEdge),
|
||||
nodeMap: make(map[int]graph.Node),
|
||||
maxID: 0,
|
||||
freeMap: make(map[int]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Graph) NewNodeID() int {
|
||||
if g.maxID != maxInt {
|
||||
g.maxID++
|
||||
return g.maxID
|
||||
}
|
||||
|
||||
// Implicitly checks if len(g.freeMap) == 0
|
||||
for id := range g.freeMap {
|
||||
return id
|
||||
}
|
||||
|
||||
// I cannot foresee this ever happening, but just in case, we check.
|
||||
if len(g.nodeMap) == maxInt {
|
||||
panic("cannot allocate node: graph too large")
|
||||
}
|
||||
|
||||
for i := 0; i < maxInt; i++ {
|
||||
if _, ok := g.nodeMap[i]; !ok {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
// Should not happen.
|
||||
panic("cannot allocate node id: no free id found")
|
||||
}
|
||||
|
||||
func (g *Graph) AddNode(n graph.Node) {
|
||||
if _, exists := g.nodeMap[n.ID()]; exists {
|
||||
panic(fmt.Sprintf("concrete: node ID collision: %d", n.ID()))
|
||||
}
|
||||
g.nodeMap[n.ID()] = n
|
||||
g.neighbors[n.ID()] = make(map[int]WeightedEdge)
|
||||
|
||||
delete(g.freeMap, n.ID())
|
||||
g.maxID = max(g.maxID, n.ID())
|
||||
}
|
||||
|
||||
func (g *Graph) SetEdge(e graph.Edge, cost float64) {
|
||||
var (
|
||||
from = e.From()
|
||||
fid = from.ID()
|
||||
to = e.To()
|
||||
tid = to.ID()
|
||||
)
|
||||
|
||||
if fid == tid {
|
||||
panic("concrete: adding self edge")
|
||||
}
|
||||
|
||||
if !g.Has(from) {
|
||||
g.AddNode(from)
|
||||
}
|
||||
|
||||
if !g.Has(to) {
|
||||
g.AddNode(to)
|
||||
}
|
||||
|
||||
g.neighbors[fid][tid] = WeightedEdge{Edge: e, Cost: cost}
|
||||
g.neighbors[tid][fid] = WeightedEdge{Edge: e, Cost: cost}
|
||||
}
|
||||
|
||||
func (g *Graph) RemoveNode(n graph.Node) {
|
||||
if _, ok := g.nodeMap[n.ID()]; !ok {
|
||||
return
|
||||
}
|
||||
delete(g.nodeMap, n.ID())
|
||||
|
||||
for neigh := range g.neighbors[n.ID()] {
|
||||
delete(g.neighbors[neigh], n.ID())
|
||||
}
|
||||
delete(g.neighbors, n.ID())
|
||||
|
||||
if g.maxID != 0 && n.ID() == g.maxID {
|
||||
g.maxID--
|
||||
}
|
||||
g.freeMap[n.ID()] = struct{}{}
|
||||
}
|
||||
|
||||
func (g *Graph) RemoveEdge(e graph.Edge) {
|
||||
from, to := e.From(), e.To()
|
||||
if _, ok := g.nodeMap[from.ID()]; !ok {
|
||||
return
|
||||
} else if _, ok := g.nodeMap[to.ID()]; !ok {
|
||||
return
|
||||
}
|
||||
|
||||
delete(g.neighbors[from.ID()], to.ID())
|
||||
delete(g.neighbors[to.ID()], from.ID())
|
||||
}
|
||||
|
||||
func (g *Graph) EmptyGraph() {
|
||||
g.neighbors = make(map[int]map[int]WeightedEdge)
|
||||
g.nodeMap = make(map[int]graph.Node)
|
||||
}
|
||||
|
||||
/* Graph implementation */
|
||||
|
||||
func (g *Graph) From(n graph.Node) []graph.Node {
|
||||
if !g.Has(n) {
|
||||
return nil
|
||||
}
|
||||
|
||||
neighbors := make([]graph.Node, len(g.neighbors[n.ID()]))
|
||||
i := 0
|
||||
for id := range g.neighbors[n.ID()] {
|
||||
neighbors[i] = g.nodeMap[id]
|
||||
i++
|
||||
}
|
||||
|
||||
return neighbors
|
||||
}
|
||||
|
||||
func (g *Graph) HasEdge(n, neigh graph.Node) bool {
|
||||
_, ok := g.neighbors[n.ID()][neigh.ID()]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (g *Graph) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.EdgeBetween(u, v)
|
||||
}
|
||||
|
||||
func (g *Graph) EdgeBetween(u, v graph.Node) graph.Edge {
|
||||
// We don't need to check if neigh exists because
|
||||
// it's implicit in the neighbors access.
|
||||
if !g.Has(u) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return g.neighbors[u.ID()][v.ID()].Edge
|
||||
}
|
||||
|
||||
func (g *Graph) Node(id int) graph.Node {
|
||||
return g.nodeMap[id]
|
||||
}
|
||||
|
||||
func (g *Graph) Has(n graph.Node) bool {
|
||||
_, ok := g.nodeMap[n.ID()]
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
func (g *Graph) Nodes() []graph.Node {
|
||||
nodes := make([]graph.Node, len(g.nodeMap))
|
||||
i := 0
|
||||
for _, n := range g.nodeMap {
|
||||
nodes[i] = n
|
||||
i++
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (g *Graph) Weight(e graph.Edge) float64 {
|
||||
if n, ok := g.neighbors[e.From().ID()]; ok {
|
||||
if we, ok := n[e.To().ID()]; ok {
|
||||
return we.Cost
|
||||
}
|
||||
}
|
||||
return inf
|
||||
}
|
||||
|
||||
func (g *Graph) Edges() []graph.Edge {
|
||||
m := make(map[WeightedEdge]struct{})
|
||||
toReturn := make([]graph.Edge, 0)
|
||||
|
||||
for _, neighs := range g.neighbors {
|
||||
for _, we := range neighs {
|
||||
if _, ok := m[we]; !ok {
|
||||
m[we] = struct{}{}
|
||||
toReturn = append(toReturn, we.Edge)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toReturn
|
||||
}
|
||||
|
||||
func (g *Graph) Degree(n graph.Node) int {
|
||||
if _, ok := g.nodeMap[n.ID()]; !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
return len(g.neighbors[n.ID()])
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// Copyright ©2014 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 concrete
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
)
|
||||
|
||||
type nodeSorter []graph.Node
|
||||
|
||||
func (ns nodeSorter) Less(i, j int) bool {
|
||||
return ns[i].ID() < ns[j].ID()
|
||||
}
|
||||
|
||||
func (ns nodeSorter) Swap(i, j int) {
|
||||
ns[i], ns[j] = ns[j], ns[i]
|
||||
}
|
||||
|
||||
func (ns nodeSorter) Len() int {
|
||||
return len(ns)
|
||||
}
|
||||
|
||||
// The math package only provides explicitly sized max
|
||||
// values. This ensures we get the max for the actual
|
||||
// type int.
|
||||
const maxInt int = int(^uint(0) >> 1)
|
||||
|
||||
var inf = math.Inf(1)
|
||||
|
||||
func isSame(a, b float64) bool {
|
||||
return a == b || (math.IsNaN(a) && math.IsNaN(b))
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// Copyright ©2014 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 graph implements functions and interfaces to deal with formal discrete graphs. It aims to
|
||||
be first and foremost flexible, with speed as a strong second priority.
|
||||
|
||||
In this package, graphs are taken to be directed, and undirected graphs are considered to be a
|
||||
special case of directed graphs that happen to have reciprocal edges. Graphs are, by default,
|
||||
unweighted, but functions that require weighted edges have several methods of dealing with this.
|
||||
In order of precedence:
|
||||
|
||||
1. These functions have an argument called Cost (and in some cases, HeuristicCost). If this is
|
||||
present, it will always be used to determine the cost between two nodes.
|
||||
|
||||
2. These functions will check if your graph implements the Coster (and/or HeuristicCoster)
|
||||
interface. If this is present, and the Cost (or HeuristicCost) argument is nil, these functions
|
||||
will be used.
|
||||
|
||||
3. Finally, if no user data is supplied, it will use the functions UniformCost (always returns 1)
|
||||
and/or NulLHeuristic (always returns 0).
|
||||
|
||||
For information on the specification for Cost functions, please see the Coster interface.
|
||||
|
||||
Finally, although the functions take in a Graph -- they will always use the correct behavior.
|
||||
If your graph implements DirectedGraph, it will use Successors and To where applicable,
|
||||
if undirected, it will use From instead. If it implements neither, it will scan the edge list
|
||||
for successors and predecessors where applicable. (This is slow, you should always implement either
|
||||
Directed or Undirected)
|
||||
|
||||
This package will never modify a graph that is not Mutable (and the interface does not allow it to
|
||||
do so). However, return values are free to be modified, so never pass a reference to your own edge
|
||||
list or node list. It also guarantees that any nodes passed back to the user will be the same
|
||||
nodes returned to it -- that is, it will never take a Node's ID and then wrap the ID in a new
|
||||
struct and return that. You'll always get back your original data.
|
||||
*/
|
||||
package graph
|
||||
+383
@@ -0,0 +1,383 @@
|
||||
// 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 dot implements GraphViz DOT marshaling of graphs.
|
||||
//
|
||||
// See the GraphViz DOT Guide and the DOT grammar for more information
|
||||
// on using specific aspects of the DOT language:
|
||||
//
|
||||
// DOT Guide: http://www.graphviz.org/Documentation/dotguide.pdf
|
||||
//
|
||||
// DOT grammar: http://www.graphviz.org/doc/info/lang.html
|
||||
//
|
||||
package dot
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
)
|
||||
|
||||
// Node is a DOT graph node.
|
||||
type Node interface {
|
||||
// DOTID returns a DOT node ID.
|
||||
//
|
||||
// An ID is one of the following:
|
||||
//
|
||||
// - a string of alphabetic ([a-zA-Z\x80-\xff]) characters, underscores ('_').
|
||||
// digits ([0-9]), not beginning with a digit.
|
||||
// - a numeral [-]?(.[0-9]+ | [0-9]+(.[0-9]*)?).
|
||||
// - a double-quoted string ("...") possibly containing escaped quotes (\").
|
||||
// - an HTML string (<...>).
|
||||
DOTID() string
|
||||
}
|
||||
|
||||
// Attributers are graph.Graph values that specify top-level DOT
|
||||
// attributes.
|
||||
type Attributers interface {
|
||||
DOTAttributers() (graph, node, edge Attributer)
|
||||
}
|
||||
|
||||
// Attributer defines graph.Node or graph.Edge values that can
|
||||
// specify DOT attributes.
|
||||
type Attributer interface {
|
||||
DOTAttributes() []Attribute
|
||||
}
|
||||
|
||||
// Attribute is a DOT language key value attribute pair.
|
||||
type Attribute struct {
|
||||
Key, Value string
|
||||
}
|
||||
|
||||
// Porter defines the behavior of graph.Edge values that can specify
|
||||
// connection ports for their end points. The returned port corresponds
|
||||
// to the the DOT node port to be used by the edge, compass corresponds
|
||||
// to DOT compass point to which the edge will be aimed.
|
||||
type Porter interface {
|
||||
FromPort() (port, compass string)
|
||||
ToPort() (port, compass string)
|
||||
}
|
||||
|
||||
// Structurer represents a graph.Graph that can define subgraphs.
|
||||
type Structurer interface {
|
||||
Structure() []Graph
|
||||
}
|
||||
|
||||
// Graph wraps named graph.Graph values.
|
||||
type Graph interface {
|
||||
graph.Graph
|
||||
DOTID() string
|
||||
}
|
||||
|
||||
// Subgrapher wraps graph.Node values that represent subgraphs.
|
||||
type Subgrapher interface {
|
||||
Subgraph() graph.Graph
|
||||
}
|
||||
|
||||
// Marshal returns the DOT encoding for the graph g, applying the prefix
|
||||
// and indent to the encoding. Name is used to specify the graph name. If
|
||||
// name is empty and g implements Graph, the returned string from DOTID
|
||||
// will be used. If strict is true the output bytes will be prefixed with
|
||||
// the DOT "strict" keyword.
|
||||
//
|
||||
// Graph serialization will work for a graph.Graph without modification,
|
||||
// however, advanced GraphViz DOT features provided by Marshal depend on
|
||||
// implementation of the Node, Attributer, Porter, Attributers, Structurer,
|
||||
// Subgrapher and Graph interfaces.
|
||||
func Marshal(g graph.Graph, name, prefix, indent string, strict bool) ([]byte, error) {
|
||||
var p printer
|
||||
p.indent = indent
|
||||
p.prefix = prefix
|
||||
p.visited = make(map[edge]bool)
|
||||
if strict {
|
||||
p.buf.WriteString("strict ")
|
||||
}
|
||||
err := p.print(g, name, false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.buf.Bytes(), nil
|
||||
}
|
||||
|
||||
type printer struct {
|
||||
buf bytes.Buffer
|
||||
|
||||
prefix string
|
||||
indent string
|
||||
depth int
|
||||
|
||||
visited map[edge]bool
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
type edge struct {
|
||||
inGraph string
|
||||
from, to int
|
||||
}
|
||||
|
||||
func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool) error {
|
||||
nodes := g.Nodes()
|
||||
sort.Sort(byID(nodes))
|
||||
|
||||
p.buf.WriteString(p.prefix)
|
||||
if needsIndent {
|
||||
for i := 0; i < p.depth; i++ {
|
||||
p.buf.WriteString(p.indent)
|
||||
}
|
||||
}
|
||||
_, isDirected := g.(graph.Directed)
|
||||
if isSubgraph {
|
||||
p.buf.WriteString("sub")
|
||||
} else if isDirected {
|
||||
p.buf.WriteString("di")
|
||||
}
|
||||
p.buf.WriteString("graph")
|
||||
|
||||
if name == "" {
|
||||
if g, ok := g.(Graph); ok {
|
||||
name = g.DOTID()
|
||||
}
|
||||
}
|
||||
if name != "" {
|
||||
p.buf.WriteByte(' ')
|
||||
p.buf.WriteString(name)
|
||||
}
|
||||
|
||||
p.openBlock(" {")
|
||||
if a, ok := g.(Attributers); ok {
|
||||
p.writeAttributeComplex(a)
|
||||
}
|
||||
if s, ok := g.(Structurer); ok {
|
||||
for _, g := range s.Structure() {
|
||||
_, subIsDirected := g.(graph.Directed)
|
||||
if subIsDirected != isDirected {
|
||||
return errors.New("dot: mismatched graph type")
|
||||
}
|
||||
p.buf.WriteByte('\n')
|
||||
p.print(g, g.DOTID(), true, true)
|
||||
}
|
||||
}
|
||||
|
||||
havePrintedNodeHeader := false
|
||||
for _, n := range nodes {
|
||||
if s, ok := n.(Subgrapher); ok {
|
||||
// If the node is not linked to any other node
|
||||
// the graph needs to be written now.
|
||||
if len(g.From(n)) == 0 {
|
||||
g := s.Subgraph()
|
||||
_, subIsDirected := g.(graph.Directed)
|
||||
if subIsDirected != isDirected {
|
||||
return errors.New("dot: mismatched graph type")
|
||||
}
|
||||
if !havePrintedNodeHeader {
|
||||
p.newline()
|
||||
p.buf.WriteString("// Node definitions.")
|
||||
havePrintedNodeHeader = true
|
||||
}
|
||||
p.newline()
|
||||
p.print(g, graphID(g, n), false, true)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !havePrintedNodeHeader {
|
||||
p.newline()
|
||||
p.buf.WriteString("// Node definitions.")
|
||||
havePrintedNodeHeader = true
|
||||
}
|
||||
p.newline()
|
||||
p.writeNode(n)
|
||||
if a, ok := n.(Attributer); ok {
|
||||
p.writeAttributeList(a)
|
||||
}
|
||||
p.buf.WriteByte(';')
|
||||
}
|
||||
|
||||
havePrintedEdgeHeader := false
|
||||
for _, n := range nodes {
|
||||
to := g.From(n)
|
||||
sort.Sort(byID(to))
|
||||
for _, t := range to {
|
||||
if isDirected {
|
||||
if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
|
||||
continue
|
||||
}
|
||||
p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
|
||||
} else {
|
||||
if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
|
||||
continue
|
||||
}
|
||||
p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
|
||||
p.visited[edge{inGraph: name, from: t.ID(), to: n.ID()}] = true
|
||||
}
|
||||
|
||||
if !havePrintedEdgeHeader {
|
||||
p.buf.WriteByte('\n')
|
||||
p.buf.WriteString(strings.TrimRight(p.prefix, " \t\xa0")) // Trim whitespace suffix.
|
||||
p.newline()
|
||||
p.buf.WriteString("// Edge definitions.")
|
||||
havePrintedEdgeHeader = true
|
||||
}
|
||||
p.newline()
|
||||
|
||||
if s, ok := n.(Subgrapher); ok {
|
||||
g := s.Subgraph()
|
||||
_, subIsDirected := g.(graph.Directed)
|
||||
if subIsDirected != isDirected {
|
||||
return errors.New("dot: mismatched graph type")
|
||||
}
|
||||
p.print(g, graphID(g, n), false, true)
|
||||
} else {
|
||||
p.writeNode(n)
|
||||
}
|
||||
e, edgeIsPorter := g.Edge(n, t).(Porter)
|
||||
if edgeIsPorter {
|
||||
p.writePorts(e.FromPort())
|
||||
}
|
||||
|
||||
if isDirected {
|
||||
p.buf.WriteString(" -> ")
|
||||
} else {
|
||||
p.buf.WriteString(" -- ")
|
||||
}
|
||||
|
||||
if s, ok := t.(Subgrapher); ok {
|
||||
g := s.Subgraph()
|
||||
_, subIsDirected := g.(graph.Directed)
|
||||
if subIsDirected != isDirected {
|
||||
return errors.New("dot: mismatched graph type")
|
||||
}
|
||||
p.print(g, graphID(g, t), false, true)
|
||||
} else {
|
||||
p.writeNode(t)
|
||||
}
|
||||
if edgeIsPorter {
|
||||
p.writePorts(e.ToPort())
|
||||
}
|
||||
|
||||
if a, ok := g.Edge(n, t).(Attributer); ok {
|
||||
p.writeAttributeList(a)
|
||||
}
|
||||
|
||||
p.buf.WriteByte(';')
|
||||
}
|
||||
}
|
||||
p.closeBlock("}")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *printer) writeNode(n graph.Node) {
|
||||
p.buf.WriteString(nodeID(n))
|
||||
}
|
||||
|
||||
func (p *printer) writePorts(port, cp string) {
|
||||
if port != "" {
|
||||
p.buf.WriteByte(':')
|
||||
p.buf.WriteString(port)
|
||||
}
|
||||
if cp != "" {
|
||||
p.buf.WriteByte(':')
|
||||
p.buf.WriteString(cp)
|
||||
}
|
||||
}
|
||||
|
||||
func nodeID(n graph.Node) string {
|
||||
switch n := n.(type) {
|
||||
case Node:
|
||||
return n.DOTID()
|
||||
default:
|
||||
return fmt.Sprint(n.ID())
|
||||
}
|
||||
}
|
||||
|
||||
func graphID(g graph.Graph, n graph.Node) string {
|
||||
switch g := g.(type) {
|
||||
case Node:
|
||||
return g.DOTID()
|
||||
default:
|
||||
return nodeID(n)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printer) writeAttributeList(a Attributer) {
|
||||
attributes := a.DOTAttributes()
|
||||
switch len(attributes) {
|
||||
case 0:
|
||||
case 1:
|
||||
p.buf.WriteString(" [")
|
||||
p.buf.WriteString(attributes[0].Key)
|
||||
p.buf.WriteByte('=')
|
||||
p.buf.WriteString(attributes[0].Value)
|
||||
p.buf.WriteString("]")
|
||||
default:
|
||||
p.openBlock(" [")
|
||||
for _, att := range attributes {
|
||||
p.newline()
|
||||
p.buf.WriteString(att.Key)
|
||||
p.buf.WriteByte('=')
|
||||
p.buf.WriteString(att.Value)
|
||||
}
|
||||
p.closeBlock("]")
|
||||
}
|
||||
}
|
||||
|
||||
var attType = []string{"graph", "node", "edge"}
|
||||
|
||||
func (p *printer) writeAttributeComplex(ca Attributers) {
|
||||
g, n, e := ca.DOTAttributers()
|
||||
haveWrittenBlock := false
|
||||
for i, a := range []Attributer{g, n, e} {
|
||||
attributes := a.DOTAttributes()
|
||||
if len(attributes) == 0 {
|
||||
continue
|
||||
}
|
||||
if haveWrittenBlock {
|
||||
p.buf.WriteByte(';')
|
||||
}
|
||||
p.newline()
|
||||
p.buf.WriteString(attType[i])
|
||||
p.openBlock(" [")
|
||||
for _, att := range attributes {
|
||||
p.newline()
|
||||
p.buf.WriteString(att.Key)
|
||||
p.buf.WriteByte('=')
|
||||
p.buf.WriteString(att.Value)
|
||||
}
|
||||
p.closeBlock("]")
|
||||
haveWrittenBlock = true
|
||||
}
|
||||
if haveWrittenBlock {
|
||||
p.buf.WriteString(";\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printer) newline() {
|
||||
p.buf.WriteByte('\n')
|
||||
p.buf.WriteString(p.prefix)
|
||||
for i := 0; i < p.depth; i++ {
|
||||
p.buf.WriteString(p.indent)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printer) openBlock(b string) {
|
||||
p.buf.WriteString(b)
|
||||
p.depth++
|
||||
}
|
||||
|
||||
func (p *printer) closeBlock(b string) {
|
||||
p.depth--
|
||||
p.newline()
|
||||
p.buf.WriteString(b)
|
||||
}
|
||||
|
||||
type byID []graph.Node
|
||||
|
||||
func (n byID) Len() int { return len(n) }
|
||||
func (n byID) Less(i, j int) bool { return n[i].ID() < n[j].ID() }
|
||||
func (n byID) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
// Copyright ©2014 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 graph
|
||||
|
||||
import "math"
|
||||
|
||||
// Node is a graph node. It returns a graph-unique integer ID.
|
||||
type Node interface {
|
||||
ID() int
|
||||
}
|
||||
|
||||
// Edge is a graph edge. In directed graphs, the direction of the
|
||||
// edge is given from -> to, otherwise the edge is semantically
|
||||
// unordered.
|
||||
type Edge interface {
|
||||
From() Node
|
||||
To() Node
|
||||
}
|
||||
|
||||
// Graph is a generalized graph.
|
||||
type Graph interface {
|
||||
// Has returns whether the node exists within the graph.
|
||||
Has(Node) bool
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
Nodes() []Node
|
||||
|
||||
// From returns all nodes that can be reached directly
|
||||
// from the given node.
|
||||
From(Node) []Node
|
||||
|
||||
// HasEdge returns whether an edge exists between
|
||||
// nodes x and y without considering direction.
|
||||
HasEdge(x, y Node) bool
|
||||
|
||||
// Edge returns the edge from u to v if such an edge
|
||||
// exists and nil otherwise. The node v must be directly
|
||||
// reachable from u as defined by the From method.
|
||||
Edge(u, v Node) Edge
|
||||
}
|
||||
|
||||
// Undirected is an undirected graph.
|
||||
type Undirected interface {
|
||||
Graph
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y.
|
||||
EdgeBetween(x, y Node) Edge
|
||||
}
|
||||
|
||||
// Directed is a directed graph.
|
||||
type Directed interface {
|
||||
Graph
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists
|
||||
// in the graph from u to v.
|
||||
HasEdgeFromTo(u, v Node) bool
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the given node.
|
||||
To(Node) []Node
|
||||
}
|
||||
|
||||
// Weighter defines graphs that can report edge weights.
|
||||
type Weighter interface {
|
||||
// Weight returns the weight for the given edge.
|
||||
Weight(Edge) float64
|
||||
}
|
||||
|
||||
// Mutable is an interface for generalized graph mutation.
|
||||
type Mutable interface {
|
||||
// NewNodeID returns a new unique arbitrary ID.
|
||||
NewNodeID() int
|
||||
|
||||
// Adds a node to the graph. AddNode panics if
|
||||
// the added node ID matches an existing node ID.
|
||||
AddNode(Node)
|
||||
|
||||
// RemoveNode removes a node from the graph, as
|
||||
// well as any edges attached to it. If the node
|
||||
// is not in the graph it is a no-op.
|
||||
RemoveNode(Node)
|
||||
|
||||
// SetEdge adds an edge from one node to another.
|
||||
// If the nodes do not exist, they are added.
|
||||
// SetEdge will panic if the IDs of the e.From
|
||||
// and e.To are equal.
|
||||
SetEdge(e Edge, cost float64)
|
||||
|
||||
// RemoveEdge removes the given edge, leaving the
|
||||
// terminal nodes. If the edge does not exist it
|
||||
// is a no-op.
|
||||
RemoveEdge(Edge)
|
||||
}
|
||||
|
||||
// MutableUndirected is an undirected graph that can be arbitrarily altered.
|
||||
type MutableUndirected interface {
|
||||
Undirected
|
||||
Mutable
|
||||
}
|
||||
|
||||
// MutableDirected is a directed graph that can be arbitrarily altered.
|
||||
type MutableDirected interface {
|
||||
Directed
|
||||
Mutable
|
||||
}
|
||||
|
||||
// WeightFunc is a mapping between an edge and an edge weight.
|
||||
type WeightFunc func(Edge) float64
|
||||
|
||||
// UniformCost is a WeightFunc that returns an edge cost of 1 for a non-nil Edge
|
||||
// and Inf for a nil Edge.
|
||||
func UniformCost(e Edge) float64 {
|
||||
if e == nil {
|
||||
return math.Inf(1)
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// CopyUndirected copies nodes and edges as undirected edges from the source to the
|
||||
// destination without first clearing the destination. CopyUndirected will panic if
|
||||
// a node ID in the source graph matches a node ID in the destination. If the source
|
||||
// does not implement Weighter, UniformCost is used to define edge weights.
|
||||
//
|
||||
// Note that if the source is a directed graph and a fundamental cycle exists with
|
||||
// two nodes where the edge weights differ, the resulting destination graph's edge
|
||||
// weight between those nodes is undefined.
|
||||
func CopyUndirected(dst MutableUndirected, src Graph) {
|
||||
var weight WeightFunc
|
||||
if g, ok := src.(Weighter); ok {
|
||||
weight = g.Weight
|
||||
} else {
|
||||
weight = UniformCost
|
||||
}
|
||||
|
||||
nodes := src.Nodes()
|
||||
for _, n := range nodes {
|
||||
dst.AddNode(n)
|
||||
}
|
||||
for _, u := range nodes {
|
||||
for _, v := range src.From(u) {
|
||||
edge := src.Edge(u, v)
|
||||
dst.SetEdge(edge, weight(edge))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CopyDirected copies nodes and edges as directed edges from the source to the
|
||||
// destination without first clearing the destination. CopyDirected will panic if
|
||||
// a node ID in the source graph matches a node ID in the destination. If the
|
||||
// source is undirected both directions will be present in the destination after
|
||||
// the copy is complete. If the source does not implement Weighter, UniformCost
|
||||
// is used to define edge weights.
|
||||
func CopyDirected(dst MutableDirected, src Graph) {
|
||||
var weight WeightFunc
|
||||
if g, ok := src.(Weighter); ok {
|
||||
weight = g.Weight
|
||||
} else {
|
||||
weight = UniformCost
|
||||
}
|
||||
|
||||
nodes := src.Nodes()
|
||||
for _, n := range nodes {
|
||||
dst.AddNode(n)
|
||||
}
|
||||
for _, u := range nodes {
|
||||
for _, v := range src.From(u) {
|
||||
edge := src.Edge(u, v)
|
||||
dst.SetEdge(edge, weight(edge))
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
// 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 internal
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
)
|
||||
|
||||
// NodeStack implements a LIFO stack of graph.Node.
|
||||
type NodeStack []graph.Node
|
||||
|
||||
// Len returns the number of graph.Nodes on the stack.
|
||||
func (s *NodeStack) Len() int { return len(*s) }
|
||||
|
||||
// Pop returns the last graph.Node on the stack and removes it
|
||||
// from the stack.
|
||||
func (s *NodeStack) Pop() graph.Node {
|
||||
v := *s
|
||||
v, n := v[:len(v)-1], v[len(v)-1]
|
||||
*s = v
|
||||
return n
|
||||
}
|
||||
|
||||
// Push adds the node n to the stack at the last position.
|
||||
func (s *NodeStack) Push(n graph.Node) { *s = append(*s, n) }
|
||||
|
||||
// NodeQueue implements a FIFO queue.
|
||||
type NodeQueue struct {
|
||||
head int
|
||||
data []graph.Node
|
||||
}
|
||||
|
||||
// Len returns the number of graph.Nodes in the queue.
|
||||
func (q *NodeQueue) Len() int { return len(q.data) - q.head }
|
||||
|
||||
// Enqueue adds the node n to the back of the queue.
|
||||
func (q *NodeQueue) Enqueue(n graph.Node) {
|
||||
if len(q.data) == cap(q.data) && q.head > 0 {
|
||||
l := q.Len()
|
||||
copy(q.data, q.data[q.head:])
|
||||
q.head = 0
|
||||
q.data = append(q.data[:l], n)
|
||||
} else {
|
||||
q.data = append(q.data, n)
|
||||
}
|
||||
}
|
||||
|
||||
// Dequeue returns the graph.Node at the front of the queue and
|
||||
// removes it from the queue.
|
||||
func (q *NodeQueue) Dequeue() graph.Node {
|
||||
if q.Len() == 0 {
|
||||
panic("queue: empty queue")
|
||||
}
|
||||
|
||||
var n graph.Node
|
||||
n, q.data[q.head] = q.data[q.head], nil
|
||||
q.head++
|
||||
|
||||
if q.Len() == 0 {
|
||||
q.head = 0
|
||||
q.data = q.data[:0]
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// Reset clears the queue for reuse.
|
||||
func (q *NodeQueue) Reset() {
|
||||
q.head = 0
|
||||
q.data = q.data[:0]
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
// Copyright ©2014 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 internal
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
)
|
||||
|
||||
// IntSet is a set of integer identifiers.
|
||||
type IntSet map[int]struct{}
|
||||
|
||||
// The simple accessor methods for Set are provided to allow ease of
|
||||
// implementation change should the need arise.
|
||||
|
||||
// Add inserts an element into the set.
|
||||
func (s IntSet) Add(e int) {
|
||||
s[e] = struct{}{}
|
||||
}
|
||||
|
||||
// Has reports the existence of the element in the set.
|
||||
func (s IntSet) Has(e int) bool {
|
||||
_, ok := s[e]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Remove deletes the specified element from the set.
|
||||
func (s IntSet) Remove(e int) {
|
||||
delete(s, e)
|
||||
}
|
||||
|
||||
// Count reports the number of elements stored in the set.
|
||||
func (s IntSet) Count() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
// Same determines whether two sets are backed by the same store. In the
|
||||
// current implementation using hash maps it makes use of the fact that
|
||||
// hash maps (at least in the gc implementation) are passed as a pointer
|
||||
// to a runtime Hmap struct.
|
||||
//
|
||||
// A map is not seen by the runtime as a pointer though, so we cannot
|
||||
// directly compare the sets converted to unsafe.Pointer and need to take
|
||||
// the sets' addressed and dereference them as pointers to some comparable
|
||||
// type.
|
||||
func Same(s1, s2 Set) bool {
|
||||
return *(*uintptr)(unsafe.Pointer(&s1)) == *(*uintptr)(unsafe.Pointer(&s2))
|
||||
}
|
||||
|
||||
// A set is a set of nodes keyed in their integer identifiers.
|
||||
type Set map[int]graph.Node
|
||||
|
||||
// The simple accessor methods for Set are provided to allow ease of
|
||||
// implementation change should the need arise.
|
||||
|
||||
// Add inserts an element into the set.
|
||||
func (s Set) Add(n graph.Node) {
|
||||
s[n.ID()] = n
|
||||
}
|
||||
|
||||
// Remove deletes the specified element from the set.
|
||||
func (s Set) Remove(e graph.Node) {
|
||||
delete(s, e.ID())
|
||||
}
|
||||
|
||||
// Has reports the existence of the element in the set.
|
||||
func (s Set) Has(n graph.Node) bool {
|
||||
_, ok := s[n.ID()]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Clear returns an empty set, possibly using the same backing store.
|
||||
// Clear is not provided as a method since there is no way to replace
|
||||
// the calling value if clearing is performed by a make(set). Clear
|
||||
// should never be called without keeping the returned value.
|
||||
func Clear(s Set) Set {
|
||||
if len(s) == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
return make(Set)
|
||||
}
|
||||
|
||||
// Copy performs a perfect copy from s1 to dst (meaning the sets will
|
||||
// be equal).
|
||||
func (dst Set) Copy(src Set) Set {
|
||||
if Same(src, dst) {
|
||||
return dst
|
||||
}
|
||||
|
||||
if len(dst) > 0 {
|
||||
dst = make(Set, len(src))
|
||||
}
|
||||
|
||||
for e, n := range src {
|
||||
dst[e] = n
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Equal reports set equality between the parameters. Sets are equal if
|
||||
// and only if they have the same elements.
|
||||
func Equal(s1, s2 Set) bool {
|
||||
if Same(s1, s2) {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for e := range s1 {
|
||||
if _, ok := s2[e]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Union takes the union of s1 and s2, and stores it in dst.
|
||||
//
|
||||
// The union of two sets, s1 and s2, is the set containing all the
|
||||
// elements of each, for instance:
|
||||
//
|
||||
// {a,b,c} UNION {d,e,f} = {a,b,c,d,e,f}
|
||||
//
|
||||
// Since sets may not have repetition, unions of two sets that overlap
|
||||
// do not contain repeat elements, that is:
|
||||
//
|
||||
// {a,b,c} UNION {b,c,d} = {a,b,c,d}
|
||||
//
|
||||
func (dst Set) Union(s1, s2 Set) Set {
|
||||
if Same(s1, s2) {
|
||||
return dst.Copy(s1)
|
||||
}
|
||||
|
||||
if !Same(s1, dst) && !Same(s2, dst) {
|
||||
dst = Clear(dst)
|
||||
}
|
||||
|
||||
if !Same(dst, s1) {
|
||||
for e, n := range s1 {
|
||||
dst[e] = n
|
||||
}
|
||||
}
|
||||
|
||||
if !Same(dst, s2) {
|
||||
for e, n := range s2 {
|
||||
dst[e] = n
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Intersect takes the intersection of s1 and s2, and stores it in dst.
|
||||
//
|
||||
// The intersection of two sets, s1 and s2, is the set containing all
|
||||
// the elements shared between the two sets, for instance:
|
||||
//
|
||||
// {a,b,c} INTERSECT {b,c,d} = {b,c}
|
||||
//
|
||||
// The intersection between a set and itself is itself, and thus
|
||||
// effectively a copy operation:
|
||||
//
|
||||
// {a,b,c} INTERSECT {a,b,c} = {a,b,c}
|
||||
//
|
||||
// The intersection between two sets that share no elements is the empty
|
||||
// set:
|
||||
//
|
||||
// {a,b,c} INTERSECT {d,e,f} = {}
|
||||
//
|
||||
func (dst Set) Intersect(s1, s2 Set) Set {
|
||||
var swap Set
|
||||
|
||||
if Same(s1, s2) {
|
||||
return dst.Copy(s1)
|
||||
}
|
||||
if Same(s1, dst) {
|
||||
swap = s2
|
||||
} else if Same(s2, dst) {
|
||||
swap = s1
|
||||
} else {
|
||||
dst = Clear(dst)
|
||||
|
||||
if len(s1) > len(s2) {
|
||||
s1, s2 = s2, s1
|
||||
}
|
||||
|
||||
for e, n := range s1 {
|
||||
if _, ok := s2[e]; ok {
|
||||
dst[e] = n
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
for e := range dst {
|
||||
if _, ok := swap[e]; !ok {
|
||||
delete(dst, e)
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// 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 internal
|
||||
|
||||
// BySliceValues implements the sort.Interface sorting a slice of
|
||||
// []int lexically by the values of the []int.
|
||||
type BySliceValues [][]int
|
||||
|
||||
func (c BySliceValues) Len() int { return len(c) }
|
||||
func (c BySliceValues) Less(i, j int) bool {
|
||||
a, b := c[i], c[j]
|
||||
l := len(a)
|
||||
if len(b) < l {
|
||||
l = len(b)
|
||||
}
|
||||
for k, v := range a[:l] {
|
||||
if v < b[k] {
|
||||
return true
|
||||
}
|
||||
if v > b[k] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return len(a) < len(b)
|
||||
}
|
||||
func (c BySliceValues) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
// Copyright ©2014 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 path
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/internal"
|
||||
)
|
||||
|
||||
// Heuristic returns an estimate of the cost of travelling between two nodes.
|
||||
type Heuristic func(x, y graph.Node) float64
|
||||
|
||||
// HeuristicCoster wraps the HeuristicCost method. A graph implementing the
|
||||
// interface provides a heuristic between any two given nodes.
|
||||
type HeuristicCoster interface {
|
||||
HeuristicCost(x, y graph.Node) float64
|
||||
}
|
||||
|
||||
// AStar finds the A*-shortest path from s to t in g using the heuristic h. The path and
|
||||
// its cost are returned in a Shortest along with paths and costs to all nodes explored
|
||||
// during the search. The number of expanded nodes is also returned. This value may help
|
||||
// with heuristic tuning.
|
||||
//
|
||||
// The path will be the shortest path if the heuristic is admissible. A heuristic is
|
||||
// admissible if for any node, n, in the graph, the heuristic estimate of the cost of
|
||||
// the path from n to t is less than or equal to the true cost of that path.
|
||||
//
|
||||
// If h is nil, AStar will use the g.HeuristicCost method if g implements HeuristicCoster,
|
||||
// falling back to NullHeuristic otherwise. If the graph does not implement graph.Weighter,
|
||||
// graph.UniformCost is used. AStar will panic if g has an A*-reachable negative edge weight.
|
||||
func AStar(s, t graph.Node, g graph.Graph, h Heuristic) (path Shortest, expanded int) {
|
||||
if !g.Has(s) || !g.Has(t) {
|
||||
return Shortest{from: s}, 0
|
||||
}
|
||||
var weight graph.WeightFunc
|
||||
if g, ok := g.(graph.Weighter); ok {
|
||||
weight = g.Weight
|
||||
} else {
|
||||
weight = graph.UniformCost
|
||||
}
|
||||
if h == nil {
|
||||
if g, ok := g.(HeuristicCoster); ok {
|
||||
h = g.HeuristicCost
|
||||
} else {
|
||||
h = NullHeuristic
|
||||
}
|
||||
}
|
||||
|
||||
path = newShortestFrom(s, g.Nodes())
|
||||
tid := t.ID()
|
||||
|
||||
visited := make(internal.IntSet)
|
||||
open := &aStarQueue{indexOf: make(map[int]int)}
|
||||
heap.Push(open, aStarNode{node: s, gscore: 0, fscore: h(s, t)})
|
||||
|
||||
for open.Len() != 0 {
|
||||
u := heap.Pop(open).(aStarNode)
|
||||
uid := u.node.ID()
|
||||
i := path.indexOf[uid]
|
||||
expanded++
|
||||
|
||||
if uid == tid {
|
||||
break
|
||||
}
|
||||
|
||||
visited.Add(uid)
|
||||
for _, v := range g.From(u.node) {
|
||||
vid := v.ID()
|
||||
if visited.Has(vid) {
|
||||
continue
|
||||
}
|
||||
j := path.indexOf[vid]
|
||||
|
||||
w := weight(g.Edge(u.node, v))
|
||||
if w < 0 {
|
||||
panic("A*: negative edge weight")
|
||||
}
|
||||
g := u.gscore + w
|
||||
if n, ok := open.node(vid); !ok {
|
||||
path.set(j, g, i)
|
||||
heap.Push(open, aStarNode{node: v, gscore: g, fscore: g + h(v, t)})
|
||||
} else if g < n.gscore {
|
||||
path.set(j, g, i)
|
||||
open.update(vid, g, g+h(v, t))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return path, expanded
|
||||
}
|
||||
|
||||
// NullHeuristic is an admissible, consistent heuristic that will not speed up computation.
|
||||
func NullHeuristic(_, _ graph.Node) float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// aStarNode adds A* accounting to a graph.Node.
|
||||
type aStarNode struct {
|
||||
node graph.Node
|
||||
gscore float64
|
||||
fscore float64
|
||||
}
|
||||
|
||||
// aStarQueue is an A* priority queue.
|
||||
type aStarQueue struct {
|
||||
indexOf map[int]int
|
||||
nodes []aStarNode
|
||||
}
|
||||
|
||||
func (q *aStarQueue) Less(i, j int) bool {
|
||||
return q.nodes[i].fscore < q.nodes[j].fscore
|
||||
}
|
||||
|
||||
func (q *aStarQueue) Swap(i, j int) {
|
||||
q.indexOf[q.nodes[i].node.ID()] = j
|
||||
q.indexOf[q.nodes[j].node.ID()] = i
|
||||
q.nodes[i], q.nodes[j] = q.nodes[j], q.nodes[i]
|
||||
}
|
||||
|
||||
func (q *aStarQueue) Len() int {
|
||||
return len(q.nodes)
|
||||
}
|
||||
|
||||
func (q *aStarQueue) Push(x interface{}) {
|
||||
n := x.(aStarNode)
|
||||
q.indexOf[n.node.ID()] = len(q.nodes)
|
||||
q.nodes = append(q.nodes, n)
|
||||
}
|
||||
|
||||
func (q *aStarQueue) Pop() interface{} {
|
||||
n := q.nodes[len(q.nodes)-1]
|
||||
q.nodes = q.nodes[:len(q.nodes)-1]
|
||||
delete(q.indexOf, n.node.ID())
|
||||
return n
|
||||
}
|
||||
|
||||
func (q *aStarQueue) update(id int, g, f float64) {
|
||||
i, ok := q.indexOf[id]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
q.nodes[i].gscore = g
|
||||
q.nodes[i].fscore = f
|
||||
heap.Fix(q, i)
|
||||
}
|
||||
|
||||
func (q *aStarQueue) node(id int) (aStarNode, bool) {
|
||||
loc, ok := q.indexOf[id]
|
||||
if ok {
|
||||
return q.nodes[loc], true
|
||||
}
|
||||
return aStarNode{}, false
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// 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 path
|
||||
|
||||
import "github.com/gonum/graph"
|
||||
|
||||
// BellmanFordFrom returns a shortest-path tree for a shortest path from u to all nodes in
|
||||
// the graph g, or false indicating that a negative cycle exists in the graph. If the graph
|
||||
// does not implement graph.Weighter, graph.UniformCost is used.
|
||||
//
|
||||
// The time complexity of BellmanFordFrom is O(|V|.|E|).
|
||||
func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
||||
if !g.Has(u) {
|
||||
return Shortest{from: u}, true
|
||||
}
|
||||
var weight graph.WeightFunc
|
||||
if g, ok := g.(graph.Weighter); ok {
|
||||
weight = g.Weight
|
||||
} else {
|
||||
weight = graph.UniformCost
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
|
||||
path = newShortestFrom(u, nodes)
|
||||
path.dist[path.indexOf[u.ID()]] = 0
|
||||
|
||||
// TODO(kortschak): Consider adding further optimisations
|
||||
// from http://arxiv.org/abs/1111.5414.
|
||||
for i := 1; i < len(nodes); i++ {
|
||||
changed := false
|
||||
for j, u := range nodes {
|
||||
for _, v := range g.From(u) {
|
||||
k := path.indexOf[v.ID()]
|
||||
joint := path.dist[j] + weight(g.Edge(u, v))
|
||||
if joint < path.dist[k] {
|
||||
path.set(k, joint, j)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !changed {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for j, u := range nodes {
|
||||
for _, v := range g.From(u) {
|
||||
k := path.indexOf[v.ID()]
|
||||
if path.dist[j]+weight(g.Edge(u, v)) < path.dist[k] {
|
||||
return path, false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return path, true
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
// Copyright ©2014 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 path
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/internal"
|
||||
)
|
||||
|
||||
// PostDominatores returns all dominators for all nodes in g. It does not
|
||||
// prune for strict post-dominators, immediate dominators etc.
|
||||
//
|
||||
// A dominates B if and only if the only path through B travels through A.
|
||||
func Dominators(start graph.Node, g graph.Graph) map[int]internal.Set {
|
||||
allNodes := make(internal.Set)
|
||||
nlist := g.Nodes()
|
||||
dominators := make(map[int]internal.Set, len(nlist))
|
||||
for _, node := range nlist {
|
||||
allNodes.Add(node)
|
||||
}
|
||||
|
||||
var to func(graph.Node) []graph.Node
|
||||
switch g := g.(type) {
|
||||
case graph.Directed:
|
||||
to = g.To
|
||||
default:
|
||||
to = g.From
|
||||
}
|
||||
|
||||
for _, node := range nlist {
|
||||
dominators[node.ID()] = make(internal.Set)
|
||||
if node.ID() == start.ID() {
|
||||
dominators[node.ID()].Add(start)
|
||||
} else {
|
||||
dominators[node.ID()].Copy(allNodes)
|
||||
}
|
||||
}
|
||||
|
||||
for somethingChanged := true; somethingChanged; {
|
||||
somethingChanged = false
|
||||
for _, node := range nlist {
|
||||
if node.ID() == start.ID() {
|
||||
continue
|
||||
}
|
||||
preds := to(node)
|
||||
if len(preds) == 0 {
|
||||
continue
|
||||
}
|
||||
tmp := make(internal.Set).Copy(dominators[preds[0].ID()])
|
||||
for _, pred := range preds[1:] {
|
||||
tmp.Intersect(tmp, dominators[pred.ID()])
|
||||
}
|
||||
|
||||
dom := make(internal.Set)
|
||||
dom.Add(node)
|
||||
|
||||
dom.Union(dom, tmp)
|
||||
if !internal.Equal(dom, dominators[node.ID()]) {
|
||||
dominators[node.ID()] = dom
|
||||
somethingChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dominators
|
||||
}
|
||||
|
||||
// PostDominatores returns all post-dominators for all nodes in g. It does not
|
||||
// prune for strict post-dominators, immediate post-dominators etc.
|
||||
//
|
||||
// A post-dominates B if and only if all paths from B travel through A.
|
||||
func PostDominators(end graph.Node, g graph.Graph) map[int]internal.Set {
|
||||
allNodes := make(internal.Set)
|
||||
nlist := g.Nodes()
|
||||
dominators := make(map[int]internal.Set, len(nlist))
|
||||
for _, node := range nlist {
|
||||
allNodes.Add(node)
|
||||
}
|
||||
|
||||
for _, node := range nlist {
|
||||
dominators[node.ID()] = make(internal.Set)
|
||||
if node.ID() == end.ID() {
|
||||
dominators[node.ID()].Add(end)
|
||||
} else {
|
||||
dominators[node.ID()].Copy(allNodes)
|
||||
}
|
||||
}
|
||||
|
||||
for somethingChanged := true; somethingChanged; {
|
||||
somethingChanged = false
|
||||
for _, node := range nlist {
|
||||
if node.ID() == end.ID() {
|
||||
continue
|
||||
}
|
||||
succs := g.From(node)
|
||||
if len(succs) == 0 {
|
||||
continue
|
||||
}
|
||||
tmp := make(internal.Set).Copy(dominators[succs[0].ID()])
|
||||
for _, succ := range succs[1:] {
|
||||
tmp.Intersect(tmp, dominators[succ.ID()])
|
||||
}
|
||||
|
||||
dom := make(internal.Set)
|
||||
dom.Add(node)
|
||||
|
||||
dom.Union(dom, tmp)
|
||||
if !internal.Equal(dom, dominators[node.ID()]) {
|
||||
dominators[node.ID()] = dom
|
||||
somethingChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dominators
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
// 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 path
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
)
|
||||
|
||||
// DijkstraFrom returns a shortest-path tree for a shortest path from u to all nodes in
|
||||
// the graph g. If the graph does not implement graph.Weighter, graph.UniformCost is used.
|
||||
// DijkstraFrom will panic if g has a u-reachable negative edge weight.
|
||||
//
|
||||
// The time complexity of DijkstrFrom is O(|E|+|V|.log|V|).
|
||||
func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
|
||||
if !g.Has(u) {
|
||||
return Shortest{from: u}
|
||||
}
|
||||
var weight graph.WeightFunc
|
||||
if g, ok := g.(graph.Weighter); ok {
|
||||
weight = g.Weight
|
||||
} else {
|
||||
weight = graph.UniformCost
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
path := newShortestFrom(u, nodes)
|
||||
|
||||
// Dijkstra's algorithm here is implemented essentially as
|
||||
// described in Function B.2 in figure 6 of UTCS Technical
|
||||
// Report TR-07-54.
|
||||
//
|
||||
// http://www.cs.utexas.edu/ftp/techreports/tr07-54.pdf
|
||||
Q := priorityQueue{{node: u, dist: 0}}
|
||||
for Q.Len() != 0 {
|
||||
mid := heap.Pop(&Q).(distanceNode)
|
||||
k := path.indexOf[mid.node.ID()]
|
||||
if mid.dist < path.dist[k] {
|
||||
path.dist[k] = mid.dist
|
||||
}
|
||||
for _, v := range g.From(mid.node) {
|
||||
j := path.indexOf[v.ID()]
|
||||
w := weight(g.Edge(mid.node, v))
|
||||
if w < 0 {
|
||||
panic("dijkstra: negative edge weight")
|
||||
}
|
||||
joint := path.dist[k] + w
|
||||
if joint < path.dist[j] {
|
||||
heap.Push(&Q, distanceNode{node: v, dist: joint})
|
||||
path.set(j, joint, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
// DijkstraAllPaths returns a shortest-path tree for shortest paths in the graph g.
|
||||
// If the graph does not implement graph.Weighter, graph.UniformCost is used.
|
||||
// DijkstraAllPaths will panic if g has a negative edge weight.
|
||||
//
|
||||
// The time complexity of DijkstrAllPaths is O(|V|.|E|+|V|^2.log|V|).
|
||||
func DijkstraAllPaths(g graph.Graph) (paths AllShortest) {
|
||||
paths = newAllShortest(g.Nodes(), false)
|
||||
dijkstraAllPaths(g, paths)
|
||||
return paths
|
||||
}
|
||||
|
||||
// dijkstraAllPaths is the all-paths implementation of Dijkstra. It is shared
|
||||
// between DijkstraAllPaths and JohnsonAllPaths to avoid repeated allocation
|
||||
// of the nodes slice and the indexOf map. It returns nothing, but stores the
|
||||
// result of the work in the paths parameter which is a reference type.
|
||||
func dijkstraAllPaths(g graph.Graph, paths AllShortest) {
|
||||
var weight graph.WeightFunc
|
||||
if g, ok := g.(graph.Weighter); ok {
|
||||
weight = g.Weight
|
||||
} else {
|
||||
weight = graph.UniformCost
|
||||
}
|
||||
|
||||
var Q priorityQueue
|
||||
for i, u := range paths.nodes {
|
||||
// Dijkstra's algorithm here is implemented essentially as
|
||||
// described in Function B.2 in figure 6 of UTCS Technical
|
||||
// Report TR-07-54 with the addition of handling multiple
|
||||
// co-equal paths.
|
||||
//
|
||||
// http://www.cs.utexas.edu/ftp/techreports/tr07-54.pdf
|
||||
|
||||
// Q must be empty at this point.
|
||||
heap.Push(&Q, distanceNode{node: u, dist: 0})
|
||||
for Q.Len() != 0 {
|
||||
mid := heap.Pop(&Q).(distanceNode)
|
||||
k := paths.indexOf[mid.node.ID()]
|
||||
if mid.dist < paths.dist.At(i, k) {
|
||||
paths.dist.Set(i, k, mid.dist)
|
||||
}
|
||||
for _, v := range g.From(mid.node) {
|
||||
j := paths.indexOf[v.ID()]
|
||||
w := weight(g.Edge(mid.node, v))
|
||||
if w < 0 {
|
||||
panic("dijkstra: negative edge weight")
|
||||
}
|
||||
joint := paths.dist.At(i, k) + w
|
||||
if joint < paths.dist.At(i, j) {
|
||||
heap.Push(&Q, distanceNode{node: v, dist: joint})
|
||||
paths.set(i, j, joint, k)
|
||||
} else if joint == paths.dist.At(i, j) {
|
||||
paths.add(i, j, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type distanceNode struct {
|
||||
node graph.Node
|
||||
dist float64
|
||||
}
|
||||
|
||||
// priorityQueue implements a no-dec priority queue.
|
||||
type priorityQueue []distanceNode
|
||||
|
||||
func (q priorityQueue) Len() int { return len(q) }
|
||||
func (q priorityQueue) Less(i, j int) bool { return q[i].dist < q[j].dist }
|
||||
func (q priorityQueue) Swap(i, j int) { q[i], q[j] = q[j], q[i] }
|
||||
func (q *priorityQueue) Push(n interface{}) { *q = append(*q, n.(distanceNode)) }
|
||||
func (q *priorityQueue) Pop() interface{} {
|
||||
t := *q
|
||||
var n interface{}
|
||||
n, *q = t[len(t)-1], t[:len(t)-1]
|
||||
return n
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
// Copyright ©2014 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 path
|
||||
|
||||
// A disjoint set is a collection of non-overlapping sets. That is, for any two sets in the
|
||||
// disjoint set, their intersection is the empty set.
|
||||
//
|
||||
// A disjoint set has three principle operations: Make Set, Find, and Union.
|
||||
//
|
||||
// Make set creates a new set for an element (presuming it does not already exist in any set in
|
||||
// the disjoint set), Find finds the set containing that element (if any), and Union merges two
|
||||
// sets in the disjoint set. In general, algorithms operating on disjoint sets are "union-find"
|
||||
// algorithms, where two sets are found with Find, and then joined with Union.
|
||||
//
|
||||
// A concrete example of a union-find algorithm can be found as discrete.Kruskal -- which unions
|
||||
// two sets when an edge is created between two vertices, and refuses to make an edge between two
|
||||
// vertices if they're part of the same set.
|
||||
type disjointSet struct {
|
||||
master map[int]*disjointSetNode
|
||||
}
|
||||
|
||||
type disjointSetNode struct {
|
||||
parent *disjointSetNode
|
||||
rank int
|
||||
}
|
||||
|
||||
func newDisjointSet() *disjointSet {
|
||||
return &disjointSet{master: make(map[int]*disjointSetNode)}
|
||||
}
|
||||
|
||||
// If the element isn't already somewhere in there, adds it to the master set and its own tiny set.
|
||||
func (ds *disjointSet) makeSet(e int) {
|
||||
if _, ok := ds.master[e]; ok {
|
||||
return
|
||||
}
|
||||
dsNode := &disjointSetNode{rank: 0}
|
||||
dsNode.parent = dsNode
|
||||
ds.master[e] = dsNode
|
||||
}
|
||||
|
||||
// Returns the set the element belongs to, or nil if none.
|
||||
func (ds *disjointSet) find(e int) *disjointSetNode {
|
||||
dsNode, ok := ds.master[e]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return find(dsNode)
|
||||
}
|
||||
|
||||
func find(dsNode *disjointSetNode) *disjointSetNode {
|
||||
if dsNode.parent != dsNode {
|
||||
dsNode.parent = find(dsNode.parent)
|
||||
}
|
||||
|
||||
return dsNode.parent
|
||||
}
|
||||
|
||||
// Unions two subsets within the disjointSet.
|
||||
//
|
||||
// If x or y are not in this disjoint set, the behavior is undefined. If either pointer is nil,
|
||||
// this function will panic.
|
||||
func (ds *disjointSet) union(x, y *disjointSetNode) {
|
||||
if x == nil || y == nil {
|
||||
panic("Disjoint Set union on nil sets")
|
||||
}
|
||||
xRoot := find(x)
|
||||
yRoot := find(y)
|
||||
if xRoot == nil || yRoot == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if xRoot == yRoot {
|
||||
return
|
||||
}
|
||||
|
||||
if xRoot.rank < yRoot.rank {
|
||||
xRoot.parent = yRoot
|
||||
} else if yRoot.rank < xRoot.rank {
|
||||
yRoot.parent = xRoot
|
||||
} else {
|
||||
yRoot.parent = xRoot
|
||||
xRoot.rank += 1
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
// 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 path
|
||||
|
||||
import "github.com/gonum/graph"
|
||||
|
||||
// FloydWarshall returns a shortest-path tree for the graph g or false indicating
|
||||
// that a negative cycle exists in the graph. If the graph does not implement
|
||||
// graph.Weighter, graph.UniformCost is used.
|
||||
//
|
||||
// The time complexity of FloydWarshall is O(|V|^3).
|
||||
func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
|
||||
var weight graph.WeightFunc
|
||||
if g, ok := g.(graph.Weighter); ok {
|
||||
weight = g.Weight
|
||||
} else {
|
||||
weight = graph.UniformCost
|
||||
}
|
||||
|
||||
nodes := g.Nodes()
|
||||
paths = newAllShortest(nodes, true)
|
||||
for i, u := range nodes {
|
||||
paths.dist.Set(i, i, 0)
|
||||
for _, v := range g.From(u) {
|
||||
j := paths.indexOf[v.ID()]
|
||||
paths.set(i, j, weight(g.Edge(u, v)), j)
|
||||
}
|
||||
}
|
||||
|
||||
for k := range nodes {
|
||||
for i := range nodes {
|
||||
for j := range nodes {
|
||||
ij := paths.dist.At(i, j)
|
||||
joint := paths.dist.At(i, k) + paths.dist.At(k, j)
|
||||
if ij > joint {
|
||||
paths.set(i, j, joint, paths.at(i, k)...)
|
||||
} else if ij-joint == 0 {
|
||||
paths.add(i, j, paths.at(i, k)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok = true
|
||||
for i := range nodes {
|
||||
if paths.dist.At(i, i) < 0 {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return paths, ok
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
// 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 path
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/concrete"
|
||||
)
|
||||
|
||||
// JohnsonAllPaths returns a shortest-path tree for shortest paths in the graph g.
|
||||
// If the graph does not implement graph.Weighter, graph.UniformCost is used.
|
||||
//
|
||||
// The time complexity of JohnsonAllPaths is O(|V|.|E|+|V|^2.log|V|).
|
||||
func JohnsonAllPaths(g graph.Graph) (paths AllShortest, ok bool) {
|
||||
jg := johnsonWeightAdjuster{
|
||||
g: g,
|
||||
from: g.From,
|
||||
edgeTo: g.Edge,
|
||||
}
|
||||
if g, ok := g.(graph.Weighter); ok {
|
||||
jg.weight = g.Weight
|
||||
} else {
|
||||
jg.weight = graph.UniformCost
|
||||
}
|
||||
|
||||
paths = newAllShortest(g.Nodes(), false)
|
||||
|
||||
sign := -1
|
||||
for {
|
||||
// Choose a random node ID until we find
|
||||
// one that is not in g.
|
||||
jg.q = sign * rand.Int()
|
||||
if _, exists := paths.indexOf[jg.q]; !exists {
|
||||
break
|
||||
}
|
||||
sign *= -1
|
||||
}
|
||||
|
||||
jg.bellmanFord = true
|
||||
jg.adjustBy, ok = BellmanFordFrom(johnsonGraphNode(jg.q), jg)
|
||||
if !ok {
|
||||
return paths, false
|
||||
}
|
||||
|
||||
jg.bellmanFord = false
|
||||
dijkstraAllPaths(jg, paths)
|
||||
|
||||
for i, u := range paths.nodes {
|
||||
hu := jg.adjustBy.WeightTo(u)
|
||||
for j, v := range paths.nodes {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
hv := jg.adjustBy.WeightTo(v)
|
||||
paths.dist.Set(i, j, paths.dist.At(i, j)-hu+hv)
|
||||
}
|
||||
}
|
||||
|
||||
return paths, ok
|
||||
}
|
||||
|
||||
type johnsonWeightAdjuster struct {
|
||||
q int
|
||||
g graph.Graph
|
||||
|
||||
from func(graph.Node) []graph.Node
|
||||
edgeTo func(graph.Node, graph.Node) graph.Edge
|
||||
weight graph.WeightFunc
|
||||
|
||||
bellmanFord bool
|
||||
adjustBy Shortest
|
||||
}
|
||||
|
||||
var (
|
||||
// johnsonWeightAdjuster has the behaviour
|
||||
// of a directed graph, but we don't need
|
||||
// to be explicit with the type since it
|
||||
// is not exported.
|
||||
_ graph.Graph = johnsonWeightAdjuster{}
|
||||
_ graph.Weighter = johnsonWeightAdjuster{}
|
||||
)
|
||||
|
||||
func (g johnsonWeightAdjuster) Has(n graph.Node) bool {
|
||||
if g.bellmanFord && n.ID() == g.q {
|
||||
return true
|
||||
}
|
||||
return g.g.Has(n)
|
||||
|
||||
}
|
||||
|
||||
func (g johnsonWeightAdjuster) Nodes() []graph.Node {
|
||||
if g.bellmanFord {
|
||||
return append(g.g.Nodes(), johnsonGraphNode(g.q))
|
||||
}
|
||||
return g.g.Nodes()
|
||||
}
|
||||
|
||||
func (g johnsonWeightAdjuster) From(n graph.Node) []graph.Node {
|
||||
if g.bellmanFord && n.ID() == g.q {
|
||||
return g.g.Nodes()
|
||||
}
|
||||
return g.from(n)
|
||||
}
|
||||
|
||||
func (g johnsonWeightAdjuster) Edge(u, v graph.Node) graph.Edge {
|
||||
if g.bellmanFord && u.ID() == g.q && g.g.Has(v) {
|
||||
return concrete.Edge{johnsonGraphNode(g.q), v}
|
||||
}
|
||||
return g.edgeTo(u, v)
|
||||
}
|
||||
|
||||
func (g johnsonWeightAdjuster) Weight(e graph.Edge) float64 {
|
||||
if g.bellmanFord {
|
||||
switch g.q {
|
||||
case e.From().ID():
|
||||
return 0
|
||||
case e.To().ID():
|
||||
return math.Inf(1)
|
||||
default:
|
||||
return g.weight(e)
|
||||
}
|
||||
}
|
||||
return g.weight(e) + g.adjustBy.WeightTo(e.From()) - g.adjustBy.WeightTo(e.To())
|
||||
}
|
||||
|
||||
func (johnsonWeightAdjuster) HasEdge(_, _ graph.Node) bool {
|
||||
panic("search: unintended use of johnsonWeightAdjuster")
|
||||
}
|
||||
|
||||
type johnsonGraphNode int
|
||||
|
||||
func (n johnsonGraphNode) ID() int { return int(n) }
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
// 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 path
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/matrix/mat64"
|
||||
)
|
||||
|
||||
// Shortest is a shortest-path tree created by the BellmanFordFrom or DijkstraFrom
|
||||
// single-source shortest path functions.
|
||||
type Shortest struct {
|
||||
// from holds the source node given to
|
||||
// DijkstraFrom.
|
||||
from graph.Node
|
||||
|
||||
// nodes hold the nodes of the analysed
|
||||
// graph.
|
||||
nodes []graph.Node
|
||||
// indexOf contains a mapping between
|
||||
// the id-dense representation of the
|
||||
// graph and the potentially id-sparse
|
||||
// nodes held in nodes.
|
||||
indexOf map[int]int
|
||||
|
||||
// dist and next represent the shortest
|
||||
// paths between nodes.
|
||||
//
|
||||
// Indices into dist and next are
|
||||
// mapped through indexOf.
|
||||
//
|
||||
// dist contains the distances
|
||||
// from the from node for each
|
||||
// node in the graph.
|
||||
dist []float64
|
||||
// next contains the shortest-path
|
||||
// tree of the graph. The index is a
|
||||
// linear mapping of to-dense-id.
|
||||
next []int
|
||||
}
|
||||
|
||||
func newShortestFrom(u graph.Node, nodes []graph.Node) Shortest {
|
||||
indexOf := make(map[int]int, len(nodes))
|
||||
uid := u.ID()
|
||||
for i, n := range nodes {
|
||||
indexOf[n.ID()] = i
|
||||
if n.ID() == uid {
|
||||
u = n
|
||||
}
|
||||
}
|
||||
|
||||
p := Shortest{
|
||||
from: u,
|
||||
|
||||
nodes: nodes,
|
||||
indexOf: indexOf,
|
||||
|
||||
dist: make([]float64, len(nodes)),
|
||||
next: make([]int, len(nodes)),
|
||||
}
|
||||
for i := range nodes {
|
||||
p.dist[i] = math.Inf(1)
|
||||
p.next[i] = -1
|
||||
}
|
||||
p.dist[indexOf[uid]] = 0
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p Shortest) set(to int, weight float64, mid int) {
|
||||
p.dist[to] = weight
|
||||
p.next[to] = mid
|
||||
}
|
||||
|
||||
// From returns the starting node of the paths held by the Shortest.
|
||||
func (p Shortest) From() graph.Node { return p.from }
|
||||
|
||||
// WeightTo returns the weight of the minimum path to v.
|
||||
func (p Shortest) WeightTo(v graph.Node) float64 {
|
||||
to, toOK := p.indexOf[v.ID()]
|
||||
if !toOK {
|
||||
return math.Inf(1)
|
||||
}
|
||||
return p.dist[to]
|
||||
}
|
||||
|
||||
// To returns a shortest path to v and the weight of the path.
|
||||
func (p Shortest) To(v graph.Node) (path []graph.Node, weight float64) {
|
||||
to, toOK := p.indexOf[v.ID()]
|
||||
if !toOK || math.IsInf(p.dist[to], 1) {
|
||||
return nil, math.Inf(1)
|
||||
}
|
||||
from := p.indexOf[p.from.ID()]
|
||||
path = []graph.Node{p.nodes[to]}
|
||||
for to != from {
|
||||
path = append(path, p.nodes[p.next[to]])
|
||||
to = p.next[to]
|
||||
}
|
||||
reverse(path)
|
||||
return path, p.dist[p.indexOf[v.ID()]]
|
||||
}
|
||||
|
||||
// AllShortest is a shortest-path tree created by the DijkstraAllPaths, FloydWarshall
|
||||
// or JohnsonAllPaths all-pairs shortest paths functions.
|
||||
type AllShortest struct {
|
||||
// nodes hold the nodes of the analysed
|
||||
// graph.
|
||||
nodes []graph.Node
|
||||
// indexOf contains a mapping between
|
||||
// the id-dense representation of the
|
||||
// graph and the potentially id-sparse
|
||||
// nodes held in nodes.
|
||||
indexOf map[int]int
|
||||
|
||||
// dist, next and forward represent
|
||||
// the shortest paths between nodes.
|
||||
//
|
||||
// Indices into dist and next are
|
||||
// mapped through indexOf.
|
||||
//
|
||||
// dist contains the pairwise
|
||||
// distances between nodes.
|
||||
dist *mat64.Dense
|
||||
// next contains the shortest-path
|
||||
// tree of the graph. The first index
|
||||
// is a linear mapping of from-dense-id
|
||||
// and to-dense-id, to-major with a
|
||||
// stride equal to len(nodes); the
|
||||
// slice indexed to is the list of
|
||||
// intermediates leading from the 'from'
|
||||
// node to the 'to' node represented
|
||||
// by dense id.
|
||||
// The interpretation of next is
|
||||
// dependent on the state of forward.
|
||||
next [][]int
|
||||
// forward indicates the direction of
|
||||
// path reconstruction. Forward
|
||||
// reconstruction is used for Floyd-
|
||||
// Warshall and reverse is used for
|
||||
// Dijkstra.
|
||||
forward bool
|
||||
}
|
||||
|
||||
func newAllShortest(nodes []graph.Node, forward bool) AllShortest {
|
||||
indexOf := make(map[int]int, len(nodes))
|
||||
for i, n := range nodes {
|
||||
indexOf[n.ID()] = i
|
||||
}
|
||||
dist := make([]float64, len(nodes)*len(nodes))
|
||||
for i := range dist {
|
||||
dist[i] = math.Inf(1)
|
||||
}
|
||||
return AllShortest{
|
||||
nodes: nodes,
|
||||
indexOf: indexOf,
|
||||
|
||||
dist: mat64.NewDense(len(nodes), len(nodes), dist),
|
||||
next: make([][]int, len(nodes)*len(nodes)),
|
||||
forward: forward,
|
||||
}
|
||||
}
|
||||
|
||||
func (p AllShortest) at(from, to int) (mid []int) {
|
||||
return p.next[from+to*len(p.nodes)]
|
||||
}
|
||||
|
||||
func (p AllShortest) set(from, to int, weight float64, mid ...int) {
|
||||
p.dist.Set(from, to, weight)
|
||||
p.next[from+to*len(p.nodes)] = append(p.next[from+to*len(p.nodes)][:0], mid...)
|
||||
}
|
||||
|
||||
func (p AllShortest) add(from, to int, mid ...int) {
|
||||
loop: // These are likely to be rare, so just loop over collisions.
|
||||
for _, k := range mid {
|
||||
for _, v := range p.next[from+to*len(p.nodes)] {
|
||||
if k == v {
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
p.next[from+to*len(p.nodes)] = append(p.next[from+to*len(p.nodes)], k)
|
||||
}
|
||||
}
|
||||
|
||||
// Weight returns the weight of the minimum path between u and v.
|
||||
func (p AllShortest) Weight(u, v graph.Node) float64 {
|
||||
from, fromOK := p.indexOf[u.ID()]
|
||||
to, toOK := p.indexOf[v.ID()]
|
||||
if !fromOK || !toOK {
|
||||
return math.Inf(1)
|
||||
}
|
||||
return p.dist.At(from, to)
|
||||
}
|
||||
|
||||
// Between returns a shortest path from u to v and the weight of the path. If more than
|
||||
// one shortest path exists between u and v, a randomly chosen path will be returned and
|
||||
// unique is returned false. If a cycle with zero weight exists in the path, it will not
|
||||
// be included, but unique will be returned false.
|
||||
func (p AllShortest) Between(u, v graph.Node) (path []graph.Node, weight float64, unique bool) {
|
||||
from, fromOK := p.indexOf[u.ID()]
|
||||
to, toOK := p.indexOf[v.ID()]
|
||||
if !fromOK || !toOK || len(p.at(from, to)) == 0 {
|
||||
if u.ID() == v.ID() {
|
||||
return []graph.Node{p.nodes[from]}, 0, true
|
||||
}
|
||||
return nil, math.Inf(1), false
|
||||
}
|
||||
|
||||
seen := make([]int, len(p.nodes))
|
||||
for i := range seen {
|
||||
seen[i] = -1
|
||||
}
|
||||
var n graph.Node
|
||||
if p.forward {
|
||||
n = p.nodes[from]
|
||||
seen[from] = 0
|
||||
} else {
|
||||
n = p.nodes[to]
|
||||
seen[to] = 0
|
||||
}
|
||||
|
||||
path = []graph.Node{n}
|
||||
weight = p.dist.At(from, to)
|
||||
unique = true
|
||||
|
||||
var next int
|
||||
for from != to {
|
||||
c := p.at(from, to)
|
||||
if len(c) != 1 {
|
||||
unique = false
|
||||
next = c[rand.Intn(len(c))]
|
||||
} else {
|
||||
next = c[0]
|
||||
}
|
||||
if seen[next] >= 0 {
|
||||
path = path[:seen[next]]
|
||||
}
|
||||
seen[next] = len(path)
|
||||
path = append(path, p.nodes[next])
|
||||
if p.forward {
|
||||
from = next
|
||||
} else {
|
||||
to = next
|
||||
}
|
||||
}
|
||||
if !p.forward {
|
||||
reverse(path)
|
||||
}
|
||||
|
||||
return path, weight, unique
|
||||
}
|
||||
|
||||
// AllBetween returns all shortest paths from u to v and the weight of the paths. Paths
|
||||
// containing zero-weight cycles are not returned.
|
||||
func (p AllShortest) AllBetween(u, v graph.Node) (paths [][]graph.Node, weight float64) {
|
||||
from, fromOK := p.indexOf[u.ID()]
|
||||
to, toOK := p.indexOf[v.ID()]
|
||||
if !fromOK || !toOK || len(p.at(from, to)) == 0 {
|
||||
if u.ID() == v.ID() {
|
||||
return [][]graph.Node{{p.nodes[from]}}, 0
|
||||
}
|
||||
return nil, math.Inf(1)
|
||||
}
|
||||
|
||||
var n graph.Node
|
||||
if p.forward {
|
||||
n = u
|
||||
} else {
|
||||
n = v
|
||||
}
|
||||
seen := make([]bool, len(p.nodes))
|
||||
paths = p.allBetween(from, to, seen, []graph.Node{n}, nil)
|
||||
|
||||
return paths, p.dist.At(from, to)
|
||||
}
|
||||
|
||||
func (p AllShortest) allBetween(from, to int, seen []bool, path []graph.Node, paths [][]graph.Node) [][]graph.Node {
|
||||
if p.forward {
|
||||
seen[from] = true
|
||||
} else {
|
||||
seen[to] = true
|
||||
}
|
||||
if from == to {
|
||||
if path == nil {
|
||||
return paths
|
||||
}
|
||||
if !p.forward {
|
||||
reverse(path)
|
||||
}
|
||||
return append(paths, path)
|
||||
}
|
||||
first := true
|
||||
for _, n := range p.at(from, to) {
|
||||
if seen[n] {
|
||||
continue
|
||||
}
|
||||
if first {
|
||||
path = append([]graph.Node(nil), path...)
|
||||
first = false
|
||||
}
|
||||
if p.forward {
|
||||
from = n
|
||||
} else {
|
||||
to = n
|
||||
}
|
||||
paths = p.allBetween(from, to, append([]bool(nil), seen...), append(path, p.nodes[n]), paths)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
func reverse(p []graph.Node) {
|
||||
for i, j := 0, len(p)-1; i < j; i, j = i+1, j-1 {
|
||||
p[i], p[j] = p[j], p[i]
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
// Copyright ©2014 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 path
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/concrete"
|
||||
"github.com/gonum/graph/internal"
|
||||
)
|
||||
|
||||
// EdgeListerGraph is an undirected graph than returns its complete set of edges.
|
||||
type EdgeListerGraph interface {
|
||||
graph.Undirected
|
||||
Edges() []graph.Edge
|
||||
}
|
||||
|
||||
// Prim generates a minimum spanning tree of g by greedy tree extension, placing
|
||||
// the result in the destination. The destination is not cleared first.
|
||||
func Prim(dst graph.MutableUndirected, g EdgeListerGraph) {
|
||||
var weight graph.WeightFunc
|
||||
if g, ok := g.(graph.Weighter); ok {
|
||||
weight = g.Weight
|
||||
} else {
|
||||
weight = graph.UniformCost
|
||||
}
|
||||
|
||||
nlist := g.Nodes()
|
||||
|
||||
if nlist == nil || len(nlist) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
dst.AddNode(nlist[0])
|
||||
remainingNodes := make(internal.IntSet)
|
||||
for _, node := range nlist[1:] {
|
||||
remainingNodes.Add(node.ID())
|
||||
}
|
||||
|
||||
edgeList := g.Edges()
|
||||
for remainingNodes.Count() != 0 {
|
||||
var edges []concrete.WeightedEdge
|
||||
for _, edge := range edgeList {
|
||||
if (dst.Has(edge.From()) && remainingNodes.Has(edge.To().ID())) ||
|
||||
(dst.Has(edge.To()) && remainingNodes.Has(edge.From().ID())) {
|
||||
|
||||
edges = append(edges, concrete.WeightedEdge{Edge: edge, Cost: weight(edge)})
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(byWeight(edges))
|
||||
myEdge := edges[0]
|
||||
|
||||
dst.SetEdge(myEdge.Edge, myEdge.Cost)
|
||||
remainingNodes.Remove(myEdge.Edge.From().ID())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Kruskal generates a minimum spanning tree of g by greedy tree coalesence, placing
|
||||
// the result in the destination. The destination is not cleared first.
|
||||
func Kruskal(dst graph.MutableUndirected, g EdgeListerGraph) {
|
||||
var weight graph.WeightFunc
|
||||
if g, ok := g.(graph.Weighter); ok {
|
||||
weight = g.Weight
|
||||
} else {
|
||||
weight = graph.UniformCost
|
||||
}
|
||||
|
||||
edgeList := g.Edges()
|
||||
edges := make([]concrete.WeightedEdge, 0, len(edgeList))
|
||||
for _, edge := range edgeList {
|
||||
edges = append(edges, concrete.WeightedEdge{Edge: edge, Cost: weight(edge)})
|
||||
}
|
||||
|
||||
sort.Sort(byWeight(edges))
|
||||
|
||||
ds := newDisjointSet()
|
||||
for _, node := range g.Nodes() {
|
||||
ds.makeSet(node.ID())
|
||||
}
|
||||
|
||||
for _, edge := range edges {
|
||||
// The disjoint set doesn't really care for which is head and which is tail so this
|
||||
// should work fine without checking both ways
|
||||
if s1, s2 := ds.find(edge.Edge.From().ID()), ds.find(edge.Edge.To().ID()); s1 != s2 {
|
||||
ds.union(s1, s2)
|
||||
dst.SetEdge(edge.Edge, edge.Cost)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type byWeight []concrete.WeightedEdge
|
||||
|
||||
func (e byWeight) Len() int {
|
||||
return len(e)
|
||||
}
|
||||
|
||||
func (e byWeight) Less(i, j int) bool {
|
||||
return e[i].Cost < e[j].Cost
|
||||
}
|
||||
|
||||
func (e byWeight) Swap(i, j int) {
|
||||
e[i], e[j] = e[j], e[i]
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
// 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 topo
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/internal"
|
||||
)
|
||||
|
||||
// VertexOrdering returns the vertex ordering and the k-cores of
|
||||
// the undirected graph g.
|
||||
func VertexOrdering(g graph.Undirected) (order []graph.Node, cores [][]graph.Node) {
|
||||
nodes := g.Nodes()
|
||||
|
||||
// The algorithm used here is essentially as described at
|
||||
// http://en.wikipedia.org/w/index.php?title=Degeneracy_%28graph_theory%29&oldid=640308710
|
||||
|
||||
// Initialize an output list L.
|
||||
var l []graph.Node
|
||||
|
||||
// Compute a number d_v for each vertex v in G,
|
||||
// the number of neighbors of v that are not already in L.
|
||||
// Initially, these numbers are just the degrees of the vertices.
|
||||
dv := make(map[int]int, len(nodes))
|
||||
var (
|
||||
maxDegree int
|
||||
neighbours = make(map[int][]graph.Node)
|
||||
)
|
||||
for _, n := range nodes {
|
||||
adj := g.From(n)
|
||||
neighbours[n.ID()] = adj
|
||||
dv[n.ID()] = len(adj)
|
||||
if len(adj) > maxDegree {
|
||||
maxDegree = len(adj)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize an array D such that D[i] contains a list of the
|
||||
// vertices v that are not already in L for which d_v = i.
|
||||
d := make([][]graph.Node, maxDegree+1)
|
||||
for _, n := range nodes {
|
||||
deg := dv[n.ID()]
|
||||
d[deg] = append(d[deg], n)
|
||||
}
|
||||
|
||||
// Initialize k to 0.
|
||||
k := 0
|
||||
// Repeat n times:
|
||||
s := []int{0}
|
||||
for _ = range nodes { // TODO(kortschak): Remove blank assignment when go1.3.3 is no longer supported.
|
||||
// Scan the array cells D[0], D[1], ... until
|
||||
// finding an i for which D[i] is nonempty.
|
||||
var (
|
||||
i int
|
||||
di []graph.Node
|
||||
)
|
||||
for i, di = range d {
|
||||
if len(di) != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Set k to max(k,i).
|
||||
if i > k {
|
||||
k = i
|
||||
s = append(s, make([]int, k-len(s)+1)...)
|
||||
}
|
||||
|
||||
// Select a vertex v from D[i]. Add v to the
|
||||
// beginning of L and remove it from D[i].
|
||||
var v graph.Node
|
||||
v, d[i] = di[len(di)-1], di[:len(di)-1]
|
||||
l = append(l, v)
|
||||
s[k]++
|
||||
delete(dv, v.ID())
|
||||
|
||||
// For each neighbor w of v not already in L,
|
||||
// subtract one from d_w and move w to the
|
||||
// cell of D corresponding to the new value of d_w.
|
||||
for _, w := range neighbours[v.ID()] {
|
||||
dw, ok := dv[w.ID()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for i, n := range d[dw] {
|
||||
if n.ID() == w.ID() {
|
||||
d[dw][i], d[dw] = d[dw][len(d[dw])-1], d[dw][:len(d[dw])-1]
|
||||
dw--
|
||||
d[dw] = append(d[dw], w)
|
||||
break
|
||||
}
|
||||
}
|
||||
dv[w.ID()] = dw
|
||||
}
|
||||
}
|
||||
|
||||
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
cores = make([][]graph.Node, len(s))
|
||||
offset := len(l)
|
||||
for i, n := range s {
|
||||
cores[i] = l[offset-n : offset]
|
||||
offset -= n
|
||||
}
|
||||
return l, cores
|
||||
}
|
||||
|
||||
// BronKerbosch returns the set of maximal cliques of the undirected graph g.
|
||||
func BronKerbosch(g graph.Undirected) [][]graph.Node {
|
||||
nodes := g.Nodes()
|
||||
|
||||
// The algorithm used here is essentially BronKerbosch3 as described at
|
||||
// http://en.wikipedia.org/w/index.php?title=Bron%E2%80%93Kerbosch_algorithm&oldid=656805858
|
||||
|
||||
p := make(internal.Set, len(nodes))
|
||||
for _, n := range nodes {
|
||||
p.Add(n)
|
||||
}
|
||||
x := make(internal.Set)
|
||||
var bk bronKerbosch
|
||||
order, _ := VertexOrdering(g)
|
||||
for _, v := range order {
|
||||
neighbours := g.From(v)
|
||||
nv := make(internal.Set, len(neighbours))
|
||||
for _, n := range neighbours {
|
||||
nv.Add(n)
|
||||
}
|
||||
bk.maximalCliquePivot(g, []graph.Node{v}, make(internal.Set).Intersect(p, nv), make(internal.Set).Intersect(x, nv))
|
||||
p.Remove(v)
|
||||
x.Add(v)
|
||||
}
|
||||
return bk
|
||||
}
|
||||
|
||||
type bronKerbosch [][]graph.Node
|
||||
|
||||
func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p, x internal.Set) {
|
||||
if len(p) == 0 && len(x) == 0 {
|
||||
*bk = append(*bk, r)
|
||||
return
|
||||
}
|
||||
|
||||
neighbours := bk.choosePivotFrom(g, p, x)
|
||||
nu := make(internal.Set, len(neighbours))
|
||||
for _, n := range neighbours {
|
||||
nu.Add(n)
|
||||
}
|
||||
for _, v := range p {
|
||||
if nu.Has(v) {
|
||||
continue
|
||||
}
|
||||
neighbours := g.From(v)
|
||||
nv := make(internal.Set, len(neighbours))
|
||||
for _, n := range neighbours {
|
||||
nv.Add(n)
|
||||
}
|
||||
|
||||
var found bool
|
||||
for _, n := range r {
|
||||
if n.ID() == v.ID() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
var sr []graph.Node
|
||||
if !found {
|
||||
sr = append(r[:len(r):len(r)], v)
|
||||
}
|
||||
|
||||
bk.maximalCliquePivot(g, sr, make(internal.Set).Intersect(p, nv), make(internal.Set).Intersect(x, nv))
|
||||
p.Remove(v)
|
||||
x.Add(v)
|
||||
}
|
||||
}
|
||||
|
||||
func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x internal.Set) (neighbors []graph.Node) {
|
||||
// TODO(kortschak): Investigate the impact of pivot choice that maximises
|
||||
// |p ⋂ neighbours(u)| as a function of input size. Until then, leave as
|
||||
// compile time option.
|
||||
if !tomitaTanakaTakahashi {
|
||||
for _, n := range p {
|
||||
return g.From(n)
|
||||
}
|
||||
for _, n := range x {
|
||||
return g.From(n)
|
||||
}
|
||||
panic("bronKerbosch: empty set")
|
||||
}
|
||||
|
||||
var (
|
||||
max = -1
|
||||
pivot graph.Node
|
||||
)
|
||||
maxNeighbors := func(s internal.Set) {
|
||||
outer:
|
||||
for _, u := range s {
|
||||
nb := g.From(u)
|
||||
c := len(nb)
|
||||
if c <= max {
|
||||
continue
|
||||
}
|
||||
for n := range nb {
|
||||
if _, ok := p[n]; ok {
|
||||
continue
|
||||
}
|
||||
c--
|
||||
if c <= max {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
max = c
|
||||
pivot = u
|
||||
neighbors = nb
|
||||
}
|
||||
}
|
||||
maxNeighbors(p)
|
||||
maxNeighbors(x)
|
||||
if pivot == nil {
|
||||
panic("bronKerbosch: empty set")
|
||||
}
|
||||
return neighbors
|
||||
}
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
// 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 topo
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/internal"
|
||||
)
|
||||
|
||||
// johnson implements Johnson's "Finding all the elementary
|
||||
// circuits of a directed graph" algorithm. SIAM J. Comput. 4(1):1975.
|
||||
//
|
||||
// Comments in the johnson methods are kept in sync with the comments
|
||||
// and labels from the paper.
|
||||
type johnson struct {
|
||||
adjacent johnsonGraph // SCC adjacency list.
|
||||
b []internal.IntSet // Johnson's "B-list".
|
||||
blocked []bool
|
||||
s int
|
||||
|
||||
stack []graph.Node
|
||||
|
||||
result [][]graph.Node
|
||||
}
|
||||
|
||||
// CyclesIn returns the set of elementary cycles in the graph g.
|
||||
func CyclesIn(g graph.Directed) [][]graph.Node {
|
||||
jg := johnsonGraphFrom(g)
|
||||
j := johnson{
|
||||
adjacent: jg,
|
||||
b: make([]internal.IntSet, len(jg.orig)),
|
||||
blocked: make([]bool, len(jg.orig)),
|
||||
}
|
||||
|
||||
// len(j.nodes) is the order of g.
|
||||
for j.s < len(j.adjacent.orig)-1 {
|
||||
// We use the previous SCC adjacency to reduce the work needed.
|
||||
sccs := TarjanSCC(j.adjacent.subgraph(j.s))
|
||||
// A_k = adjacency structure of strong component K with least
|
||||
// vertex in subgraph of G induced by {s, s+1, ... ,n}.
|
||||
j.adjacent = j.adjacent.sccSubGraph(sccs, 2) // Only allow SCCs with >= 2 vertices.
|
||||
if j.adjacent.order() == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// s = least vertex in V_k
|
||||
if s := j.adjacent.leastVertexIndex(); s < j.s {
|
||||
j.s = s
|
||||
}
|
||||
for i, v := range j.adjacent.orig {
|
||||
if !j.adjacent.nodes.Has(v.ID()) {
|
||||
continue
|
||||
}
|
||||
if len(j.adjacent.succ[v.ID()]) > 0 {
|
||||
j.blocked[i] = false
|
||||
j.b[i] = make(internal.IntSet)
|
||||
}
|
||||
}
|
||||
//L3:
|
||||
_ = j.circuit(j.s)
|
||||
j.s++
|
||||
}
|
||||
|
||||
return j.result
|
||||
}
|
||||
|
||||
// circuit is the CIRCUIT sub-procedure in the paper.
|
||||
func (j *johnson) circuit(v int) bool {
|
||||
f := false
|
||||
n := j.adjacent.orig[v]
|
||||
j.stack = append(j.stack, n)
|
||||
j.blocked[v] = true
|
||||
|
||||
//L1:
|
||||
for w := range j.adjacent.succ[n.ID()] {
|
||||
w = j.adjacent.indexOf(w)
|
||||
if w == j.s {
|
||||
// Output circuit composed of stack followed by s.
|
||||
r := make([]graph.Node, len(j.stack)+1)
|
||||
copy(r, j.stack)
|
||||
r[len(r)-1] = j.adjacent.orig[j.s]
|
||||
j.result = append(j.result, r)
|
||||
f = true
|
||||
} else if !j.blocked[w] {
|
||||
if j.circuit(w) {
|
||||
f = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//L2:
|
||||
if f {
|
||||
j.unblock(v)
|
||||
} else {
|
||||
for w := range j.adjacent.succ[n.ID()] {
|
||||
j.b[j.adjacent.indexOf(w)].Add(v)
|
||||
}
|
||||
}
|
||||
j.stack = j.stack[:len(j.stack)-1]
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// unblock is the UNBLOCK sub-procedure in the paper.
|
||||
func (j *johnson) unblock(u int) {
|
||||
j.blocked[u] = false
|
||||
for w := range j.b[u] {
|
||||
j.b[u].Remove(w)
|
||||
if j.blocked[w] {
|
||||
j.unblock(w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// johnsonGraph is an edge list representation of a graph with helpers
|
||||
// necessary for Johnson's algorithm
|
||||
type johnsonGraph struct {
|
||||
// Keep the original graph nodes and a
|
||||
// look-up to into the non-sparse
|
||||
// collection of potentially sparse IDs.
|
||||
orig []graph.Node
|
||||
index map[int]int
|
||||
|
||||
nodes internal.IntSet
|
||||
succ map[int]internal.IntSet
|
||||
}
|
||||
|
||||
// johnsonGraphFrom returns a deep copy of the graph g.
|
||||
func johnsonGraphFrom(g graph.Directed) johnsonGraph {
|
||||
nodes := g.Nodes()
|
||||
sort.Sort(byID(nodes))
|
||||
c := johnsonGraph{
|
||||
orig: nodes,
|
||||
index: make(map[int]int, len(nodes)),
|
||||
|
||||
nodes: make(internal.IntSet, len(nodes)),
|
||||
succ: make(map[int]internal.IntSet),
|
||||
}
|
||||
for i, u := range nodes {
|
||||
c.index[u.ID()] = i
|
||||
for _, v := range g.From(u) {
|
||||
if c.succ[u.ID()] == nil {
|
||||
c.succ[u.ID()] = make(internal.IntSet)
|
||||
c.nodes.Add(u.ID())
|
||||
}
|
||||
c.nodes.Add(v.ID())
|
||||
c.succ[u.ID()].Add(v.ID())
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
type byID []graph.Node
|
||||
|
||||
func (n byID) Len() int { return len(n) }
|
||||
func (n byID) Less(i, j int) bool { return n[i].ID() < n[j].ID() }
|
||||
func (n byID) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
|
||||
|
||||
// order returns the order of the graph.
|
||||
func (g johnsonGraph) order() int { return g.nodes.Count() }
|
||||
|
||||
// indexOf returns the index of the retained node for the given node ID.
|
||||
func (g johnsonGraph) indexOf(id int) int {
|
||||
return g.index[id]
|
||||
}
|
||||
|
||||
// leastVertexIndex returns the index into orig of the least vertex.
|
||||
func (g johnsonGraph) leastVertexIndex() int {
|
||||
for _, v := range g.orig {
|
||||
if g.nodes.Has(v.ID()) {
|
||||
return g.indexOf(v.ID())
|
||||
}
|
||||
}
|
||||
panic("johnsonCycles: empty set")
|
||||
}
|
||||
|
||||
// subgraph returns a subgraph of g induced by {s, s+1, ... , n}. The
|
||||
// subgraph is destructively generated in g.
|
||||
func (g johnsonGraph) subgraph(s int) johnsonGraph {
|
||||
sn := g.orig[s].ID()
|
||||
for u, e := range g.succ {
|
||||
if u < sn {
|
||||
g.nodes.Remove(u)
|
||||
delete(g.succ, u)
|
||||
continue
|
||||
}
|
||||
for v := range e {
|
||||
if v < sn {
|
||||
g.succ[u].Remove(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
// sccSubGraph returns the graph of the tarjan's strongly connected
|
||||
// components with each SCC containing at least min vertices.
|
||||
// sccSubGraph returns nil if there is no SCC with at least min
|
||||
// members.
|
||||
func (g johnsonGraph) sccSubGraph(sccs [][]graph.Node, min int) johnsonGraph {
|
||||
if len(g.nodes) == 0 {
|
||||
g.nodes = nil
|
||||
g.succ = nil
|
||||
return g
|
||||
}
|
||||
sub := johnsonGraph{
|
||||
orig: g.orig,
|
||||
index: g.index,
|
||||
nodes: make(internal.IntSet),
|
||||
succ: make(map[int]internal.IntSet),
|
||||
}
|
||||
|
||||
var n int
|
||||
for _, scc := range sccs {
|
||||
if len(scc) < min {
|
||||
continue
|
||||
}
|
||||
n++
|
||||
for _, u := range scc {
|
||||
for _, v := range scc {
|
||||
if _, ok := g.succ[u.ID()][v.ID()]; ok {
|
||||
if sub.succ[u.ID()] == nil {
|
||||
sub.succ[u.ID()] = make(internal.IntSet)
|
||||
sub.nodes.Add(u.ID())
|
||||
}
|
||||
sub.nodes.Add(v.ID())
|
||||
sub.succ[u.ID()].Add(v.ID())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
g.nodes = nil
|
||||
g.succ = nil
|
||||
return g
|
||||
}
|
||||
|
||||
return sub
|
||||
}
|
||||
|
||||
// Nodes is required to satisfy Tarjan.
|
||||
func (g johnsonGraph) Nodes() []graph.Node {
|
||||
n := make([]graph.Node, 0, len(g.nodes))
|
||||
for id := range g.nodes {
|
||||
n = append(n, johnsonGraphNode(id))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Successors is required to satisfy Tarjan.
|
||||
func (g johnsonGraph) From(n graph.Node) []graph.Node {
|
||||
adj := g.succ[n.ID()]
|
||||
if len(adj) == 0 {
|
||||
return nil
|
||||
}
|
||||
succ := make([]graph.Node, 0, len(adj))
|
||||
for n := range adj {
|
||||
succ = append(succ, johnsonGraphNode(n))
|
||||
}
|
||||
return succ
|
||||
}
|
||||
|
||||
func (johnsonGraph) Has(graph.Node) bool {
|
||||
panic("search: unintended use of johnsonGraph")
|
||||
}
|
||||
func (johnsonGraph) HasEdge(_, _ graph.Node) bool {
|
||||
panic("search: unintended use of johnsonGraph")
|
||||
}
|
||||
func (johnsonGraph) Edge(_, _ graph.Node) graph.Edge {
|
||||
panic("search: unintended use of johnsonGraph")
|
||||
}
|
||||
func (johnsonGraph) HasEdgeFromTo(_, _ graph.Node) bool {
|
||||
panic("search: unintended use of johnsonGraph")
|
||||
}
|
||||
func (johnsonGraph) To(graph.Node) []graph.Node {
|
||||
panic("search: unintended use of johnsonGraph")
|
||||
}
|
||||
|
||||
type johnsonGraphNode int
|
||||
|
||||
func (n johnsonGraphNode) ID() int { return int(n) }
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// 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.
|
||||
|
||||
//+build !tomita
|
||||
|
||||
package topo
|
||||
|
||||
const tomitaTanakaTakahashi = false
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
// 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 topo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/internal"
|
||||
)
|
||||
|
||||
// Unorderable is an error containing sets of unorderable graph.Nodes.
|
||||
type Unorderable [][]graph.Node
|
||||
|
||||
// Error satisfies the error interface.
|
||||
func (e Unorderable) Error() string {
|
||||
const maxNodes = 10
|
||||
var n int
|
||||
for _, c := range e {
|
||||
n += len(c)
|
||||
}
|
||||
if n > maxNodes {
|
||||
// Don't return errors that are too long.
|
||||
return fmt.Sprintf("topo: no topological ordering: %d nodes in %d cyclic components", n, len(e))
|
||||
}
|
||||
return fmt.Sprintf("topo: no topological ordering: cyclic components: %v", [][]graph.Node(e))
|
||||
}
|
||||
|
||||
// Sort performs a topological sort of the directed graph g returning the 'from' to 'to'
|
||||
// sort order. If a topological ordering is not possible, an Unorderable error is returned
|
||||
// listing cyclic components in g with each cyclic component's members sorted by ID. When
|
||||
// an Unorderable error is returned, each cyclic component's topological position within
|
||||
// the sorted nodes is marked with a nil graph.Node.
|
||||
func Sort(g graph.Directed) (sorted []graph.Node, err error) {
|
||||
sccs := TarjanSCC(g)
|
||||
sorted = make([]graph.Node, 0, len(sccs))
|
||||
var sc Unorderable
|
||||
for _, s := range sccs {
|
||||
if len(s) != 1 {
|
||||
sort.Sort(byID(s))
|
||||
sc = append(sc, s)
|
||||
sorted = append(sorted, nil)
|
||||
continue
|
||||
}
|
||||
sorted = append(sorted, s[0])
|
||||
}
|
||||
if sc != nil {
|
||||
for i, j := 0, len(sc)-1; i < j; i, j = i+1, j-1 {
|
||||
sc[i], sc[j] = sc[j], sc[i]
|
||||
}
|
||||
err = sc
|
||||
}
|
||||
reverse(sorted)
|
||||
return sorted, err
|
||||
}
|
||||
|
||||
func reverse(p []graph.Node) {
|
||||
for i, j := 0, len(p)-1; i < j; i, j = i+1, j-1 {
|
||||
p[i], p[j] = p[j], p[i]
|
||||
}
|
||||
}
|
||||
|
||||
// TarjanSCC returns the strongly connected components of the graph g using Tarjan's algorithm.
|
||||
//
|
||||
// A strongly connected component of a graph is a set of vertices where it's possible to reach any
|
||||
// vertex in the set from any other (meaning there's a cycle between them.)
|
||||
//
|
||||
// Generally speaking, a directed graph where the number of strongly connected components is equal
|
||||
// to the number of nodes is acyclic, unless you count reflexive edges as a cycle (which requires
|
||||
// only a little extra testing.)
|
||||
//
|
||||
func TarjanSCC(g graph.Directed) [][]graph.Node {
|
||||
nodes := g.Nodes()
|
||||
t := tarjan{
|
||||
succ: g.From,
|
||||
|
||||
indexTable: make(map[int]int, len(nodes)),
|
||||
lowLink: make(map[int]int, len(nodes)),
|
||||
onStack: make(internal.IntSet, len(nodes)),
|
||||
}
|
||||
for _, v := range nodes {
|
||||
if t.indexTable[v.ID()] == 0 {
|
||||
t.strongconnect(v)
|
||||
}
|
||||
}
|
||||
return t.sccs
|
||||
}
|
||||
|
||||
// tarjan implements Tarjan's strongly connected component finding
|
||||
// algorithm. The implementation is from the pseudocode at
|
||||
//
|
||||
// http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm?oldid=642744644
|
||||
//
|
||||
type tarjan struct {
|
||||
succ func(graph.Node) []graph.Node
|
||||
|
||||
index int
|
||||
indexTable map[int]int
|
||||
lowLink map[int]int
|
||||
onStack internal.IntSet
|
||||
|
||||
stack []graph.Node
|
||||
|
||||
sccs [][]graph.Node
|
||||
}
|
||||
|
||||
// strongconnect is the strongconnect function described in the
|
||||
// wikipedia article.
|
||||
func (t *tarjan) strongconnect(v graph.Node) {
|
||||
vID := v.ID()
|
||||
|
||||
// Set the depth index for v to the smallest unused index.
|
||||
t.index++
|
||||
t.indexTable[vID] = t.index
|
||||
t.lowLink[vID] = t.index
|
||||
t.stack = append(t.stack, v)
|
||||
t.onStack.Add(vID)
|
||||
|
||||
// Consider successors of v.
|
||||
for _, w := range t.succ(v) {
|
||||
wID := w.ID()
|
||||
if t.indexTable[wID] == 0 {
|
||||
// Successor w has not yet been visited; recur on it.
|
||||
t.strongconnect(w)
|
||||
t.lowLink[vID] = min(t.lowLink[vID], t.lowLink[wID])
|
||||
} else if t.onStack.Has(wID) {
|
||||
// Successor w is in stack s and hence in the current SCC.
|
||||
t.lowLink[vID] = min(t.lowLink[vID], t.indexTable[wID])
|
||||
}
|
||||
}
|
||||
|
||||
// If v is a root node, pop the stack and generate an SCC.
|
||||
if t.lowLink[vID] == t.indexTable[vID] {
|
||||
// Start a new strongly connected component.
|
||||
var (
|
||||
scc []graph.Node
|
||||
w graph.Node
|
||||
)
|
||||
for {
|
||||
w, t.stack = t.stack[len(t.stack)-1], t.stack[:len(t.stack)-1]
|
||||
t.onStack.Remove(w.ID())
|
||||
// Add w to current strongly connected component.
|
||||
scc = append(scc, w)
|
||||
if w.ID() == vID {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Output the current strongly connected component.
|
||||
t.sccs = append(t.sccs, scc)
|
||||
}
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// 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.
|
||||
|
||||
//+build tomita
|
||||
|
||||
package topo
|
||||
|
||||
const tomitaTanakaTakahashi = true
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
// Copyright ©2014 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 topo
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/traverse"
|
||||
)
|
||||
|
||||
// IsPathIn returns whether path is a path in g.
|
||||
//
|
||||
// As special cases, IsPathIn returns true for a zero length path or for
|
||||
// a path of length 1 when the node in path exists in the graph.
|
||||
func IsPathIn(g graph.Graph, path []graph.Node) bool {
|
||||
switch len(path) {
|
||||
case 0:
|
||||
return true
|
||||
case 1:
|
||||
return g.Has(path[0])
|
||||
default:
|
||||
var canReach func(u, v graph.Node) bool
|
||||
switch g := g.(type) {
|
||||
case graph.Directed:
|
||||
canReach = g.HasEdgeFromTo
|
||||
default:
|
||||
canReach = g.HasEdge
|
||||
}
|
||||
|
||||
for i, u := range path[:len(path)-1] {
|
||||
if !canReach(u, path[i+1]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// ConnectedComponents returns the connected components of the undirected graph g.
|
||||
func ConnectedComponents(g graph.Undirected) [][]graph.Node {
|
||||
var (
|
||||
w traverse.DepthFirst
|
||||
c []graph.Node
|
||||
cc [][]graph.Node
|
||||
)
|
||||
during := func(n graph.Node) {
|
||||
c = append(c, n)
|
||||
}
|
||||
after := func() {
|
||||
cc = append(cc, []graph.Node(nil))
|
||||
cc[len(cc)-1] = append(cc[len(cc)-1], c...)
|
||||
c = c[:0]
|
||||
}
|
||||
w.WalkAll(g, nil, after, during)
|
||||
|
||||
return cc
|
||||
}
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
// 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 traverse provides basic graph traversal primitives.
|
||||
package traverse
|
||||
|
||||
import (
|
||||
"github.com/gonum/graph"
|
||||
"github.com/gonum/graph/internal"
|
||||
)
|
||||
|
||||
// BreadthFirst implements stateful breadth-first graph traversal.
|
||||
type BreadthFirst struct {
|
||||
EdgeFilter func(graph.Edge) bool
|
||||
Visit func(u, v graph.Node)
|
||||
queue internal.NodeQueue
|
||||
visited internal.IntSet
|
||||
}
|
||||
|
||||
// Walk performs a breadth-first traversal of the graph g starting from the given node,
|
||||
// depending on the the EdgeFilter field and the until parameter if they are non-nil. The
|
||||
// traversal follows edges for which EdgeFilter(edge) is true and returns the first node
|
||||
// for which until(node, depth) is true. During the traversal, if the Visit field is
|
||||
// non-nil, it is called with the nodes joined by each followed edge.
|
||||
func (b *BreadthFirst) Walk(g graph.Graph, from graph.Node, until func(n graph.Node, d int) bool) graph.Node {
|
||||
if b.visited == nil {
|
||||
b.visited = make(internal.IntSet)
|
||||
}
|
||||
b.queue.Enqueue(from)
|
||||
b.visited.Add(from.ID())
|
||||
|
||||
var (
|
||||
depth int
|
||||
children int
|
||||
untilNext = 1
|
||||
)
|
||||
for b.queue.Len() > 0 {
|
||||
t := b.queue.Dequeue()
|
||||
if until != nil && until(t, depth) {
|
||||
return t
|
||||
}
|
||||
for _, n := range g.From(t) {
|
||||
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(t, n)) {
|
||||
continue
|
||||
}
|
||||
if b.visited.Has(n.ID()) {
|
||||
continue
|
||||
}
|
||||
if b.Visit != nil {
|
||||
b.Visit(t, n)
|
||||
}
|
||||
b.visited.Add(n.ID())
|
||||
children++
|
||||
b.queue.Enqueue(n)
|
||||
}
|
||||
if untilNext--; untilNext == 0 {
|
||||
depth++
|
||||
untilNext = children
|
||||
children = 0
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WalkAll calls Walk for each unvisited node of the graph g using edges independent
|
||||
// of their direction. The functions before and after are called prior to commencing
|
||||
// and after completing each walk if they are non-nil respectively. The function
|
||||
// during is called on each node as it is traversed.
|
||||
func (b *BreadthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) {
|
||||
b.Reset()
|
||||
for _, from := range g.Nodes() {
|
||||
if b.Visited(from) {
|
||||
continue
|
||||
}
|
||||
if before != nil {
|
||||
before()
|
||||
}
|
||||
b.Walk(g, from, func(n graph.Node, _ int) bool {
|
||||
if during != nil {
|
||||
during(n)
|
||||
}
|
||||
return false
|
||||
})
|
||||
if after != nil {
|
||||
after()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Visited returned whether the node n was visited during a traverse.
|
||||
func (b *BreadthFirst) Visited(n graph.Node) bool {
|
||||
_, ok := b.visited[n.ID()]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Reset resets the state of the traverser for reuse.
|
||||
func (b *BreadthFirst) Reset() {
|
||||
b.queue.Reset()
|
||||
b.visited = nil
|
||||
}
|
||||
|
||||
// DepthFirst implements stateful depth-first graph traversal.
|
||||
type DepthFirst struct {
|
||||
EdgeFilter func(graph.Edge) bool
|
||||
Visit func(u, v graph.Node)
|
||||
stack internal.NodeStack
|
||||
visited internal.IntSet
|
||||
}
|
||||
|
||||
// Walk performs a depth-first traversal of the graph g starting from the given node,
|
||||
// depending on the the EdgeFilter field and the until parameter if they are non-nil. The
|
||||
// traversal follows edges for which EdgeFilter(edge) is true and returns the first node
|
||||
// for which until(node) is true. During the traversal, if the Visit field is non-nil, it
|
||||
// is called with the nodes joined by each followed edge.
|
||||
func (d *DepthFirst) Walk(g graph.Graph, from graph.Node, until func(graph.Node) bool) graph.Node {
|
||||
if d.visited == nil {
|
||||
d.visited = make(internal.IntSet)
|
||||
}
|
||||
d.stack.Push(from)
|
||||
d.visited.Add(from.ID())
|
||||
|
||||
for d.stack.Len() > 0 {
|
||||
t := d.stack.Pop()
|
||||
if until != nil && until(t) {
|
||||
return t
|
||||
}
|
||||
for _, n := range g.From(t) {
|
||||
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(t, n)) {
|
||||
continue
|
||||
}
|
||||
if d.visited.Has(n.ID()) {
|
||||
continue
|
||||
}
|
||||
if d.Visit != nil {
|
||||
d.Visit(t, n)
|
||||
}
|
||||
d.visited.Add(n.ID())
|
||||
d.stack.Push(n)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WalkAll calls Walk for each unvisited node of the graph g using edges independent
|
||||
// of their direction. The functions before and after are called prior to commencing
|
||||
// and after completing each walk if they are non-nil respectively. The function
|
||||
// during is called on each node as it is traversed.
|
||||
func (d *DepthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) {
|
||||
d.Reset()
|
||||
for _, from := range g.Nodes() {
|
||||
if d.Visited(from) {
|
||||
continue
|
||||
}
|
||||
if before != nil {
|
||||
before()
|
||||
}
|
||||
d.Walk(g, from, func(n graph.Node) bool {
|
||||
if during != nil {
|
||||
during(n)
|
||||
}
|
||||
return false
|
||||
})
|
||||
if after != nil {
|
||||
after()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Visited returned whether the node n was visited during a traverse.
|
||||
func (d *DepthFirst) Visited(n graph.Node) bool {
|
||||
_, ok := d.visited[n.ID()]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Reset resets the state of the traverser for reuse.
|
||||
func (d *DepthFirst) Reset() {
|
||||
d.stack = d.stack[:0]
|
||||
d.visited = nil
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 asm
|
||||
|
||||
// The extra z parameter is needed because of floats.AddScaledTo
|
||||
func CaxpyUnitary(alpha complex64, x, y, z []complex64) {
|
||||
for i, v := range x {
|
||||
z[i] = alpha*v + y[i]
|
||||
}
|
||||
}
|
||||
|
||||
func CaxpyInc(alpha complex64, x, y []complex64, n, incX, incY, ix, iy uintptr) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
y[iy] += alpha * x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 asm
|
||||
|
||||
func CdotcUnitary(x, y []complex64) (sum complex64) {
|
||||
for i, v := range x {
|
||||
sum += y[i] * conj(v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CdotcInc(x, y []complex64, n, incX, incY, ix, iy uintptr) (sum complex64) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
sum += y[iy] * conj(x[ix])
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
return
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 asm
|
||||
|
||||
func CdotuUnitary(x, y []complex64) (sum complex64) {
|
||||
for i, v := range x {
|
||||
sum += y[i] * v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CdotuInc(x, y []complex64, n, incX, incY, ix, iy uintptr) (sum complex64) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
sum += y[iy] * x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
return
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# 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.
|
||||
|
||||
echo Generating zdotu.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > zdotu.go
|
||||
cat ddot.go \
|
||||
| grep -v '//+build' \
|
||||
| gofmt -r 'float64 -> complex128' \
|
||||
| sed 's/Ddot/Zdotu/' \
|
||||
>> zdotu.go
|
||||
|
||||
echo Generating zdotc.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > zdotc.go
|
||||
cat ddot.go \
|
||||
| grep -v '//+build' \
|
||||
| gofmt -r 'float64 -> complex128' \
|
||||
| gofmt -r 'y[i] * v -> y[i] * cmplx.Conj(v)' \
|
||||
| sed 's/Ddot/Zdotc/' \
|
||||
| goimports \
|
||||
>> zdotc.go
|
||||
|
||||
echo Generating zaxpy.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > zaxpy.go
|
||||
cat daxpy.go \
|
||||
| grep -v '//+build' \
|
||||
| gofmt -r 'float64 -> complex128' \
|
||||
| sed 's/Daxpy/Zaxpy/' \
|
||||
>> zaxpy.go
|
||||
|
||||
echo Generating cdotu.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > cdotu.go
|
||||
cat ddot.go \
|
||||
| grep -v '//+build' \
|
||||
| gofmt -r 'float64 -> complex64' \
|
||||
| sed 's/Ddot/Cdotu/' \
|
||||
>> cdotu.go
|
||||
|
||||
echo Generating cdotc.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > cdotc.go
|
||||
cat ddot.go \
|
||||
| grep -v '//+build' \
|
||||
| gofmt -r 'float64 -> complex64' \
|
||||
| gofmt -r 'y[i] * v -> y[i] * conj(v)' \
|
||||
| sed 's/Ddot/Cdotc/' \
|
||||
| goimports \
|
||||
>> cdotc.go
|
||||
|
||||
echo Generating caxpy.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > caxpy.go
|
||||
cat daxpy.go \
|
||||
| grep -v '//+build' \
|
||||
| gofmt -r 'float64 -> complex64' \
|
||||
| sed 's/Daxpy/Caxpy/' \
|
||||
>> caxpy.go
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// 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 asm
|
||||
|
||||
func conj(c complex64) complex64 { return complex(real(c), -imag(c)) }
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// 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.
|
||||
|
||||
//+build !amd64 noasm
|
||||
|
||||
package asm
|
||||
|
||||
// The extra z parameter is needed because of floats.AddScaledTo
|
||||
func DaxpyUnitary(alpha float64, x, y, z []float64) {
|
||||
for i, v := range x {
|
||||
z[i] = alpha*v + y[i]
|
||||
}
|
||||
}
|
||||
|
||||
func DaxpyInc(alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
y[iy] += alpha * x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// 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.
|
||||
|
||||
//+build !noasm
|
||||
|
||||
package asm
|
||||
|
||||
// The extra z parameter is needed because of floats.AddScaledTo
|
||||
func DaxpyUnitary(alpha float64, x, y, z []float64)
|
||||
|
||||
func DaxpyInc(alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr)
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
// 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.
|
||||
//
|
||||
// Some of the loop unrolling code is copied from:
|
||||
// http://golang.org/src/math/big/arith_amd64.s
|
||||
// which is distributed under these terms:
|
||||
//
|
||||
// Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//+build !noasm
|
||||
|
||||
// TODO(fhs): use textflag.h after we drop Go 1.3 support
|
||||
//#include "textflag.h"
|
||||
// Don't insert stack check preamble.
|
||||
#define NOSPLIT 4
|
||||
|
||||
|
||||
// func DaxpyUnitary(alpha float64, x, y, z []float64)
|
||||
// This function assumes len(y) >= len(x).
|
||||
TEXT ·DaxpyUnitary(SB),NOSPLIT,$0
|
||||
MOVHPD alpha+0(FP), X7
|
||||
MOVLPD alpha+0(FP), X7
|
||||
MOVQ x_len+16(FP), DI // n = len(x)
|
||||
MOVQ x+8(FP), R8
|
||||
MOVQ y+32(FP), R9
|
||||
MOVQ z+56(FP), R10
|
||||
|
||||
MOVQ $0, SI // i = 0
|
||||
SUBQ $2, DI // n -= 2
|
||||
JL V1 // if n < 0 goto V1
|
||||
|
||||
U1: // n >= 0
|
||||
// y[i] += alpha * x[i] unrolled 2x.
|
||||
MOVUPD 0(R8)(SI*8), X0
|
||||
MOVUPD 0(R9)(SI*8), X1
|
||||
MULPD X7, X0
|
||||
ADDPD X0, X1
|
||||
MOVUPD X1, 0(R10)(SI*8)
|
||||
|
||||
ADDQ $2, SI // i += 2
|
||||
SUBQ $2, DI // n -= 2
|
||||
JGE U1 // if n >= 0 goto U1
|
||||
|
||||
V1:
|
||||
ADDQ $2, DI // n += 2
|
||||
JLE E1 // if n <= 0 goto E1
|
||||
|
||||
// y[i] += alpha * x[i] for last iteration if n is odd.
|
||||
MOVSD 0(R8)(SI*8), X0
|
||||
MOVSD 0(R9)(SI*8), X1
|
||||
MULSD X7, X0
|
||||
ADDSD X0, X1
|
||||
MOVSD X1, 0(R10)(SI*8)
|
||||
|
||||
E1:
|
||||
RET
|
||||
|
||||
|
||||
// func DaxpyInc(alpha float64, x, y []float64, n, incX, incY, ix, iy uintptr)
|
||||
TEXT ·DaxpyInc(SB),NOSPLIT,$0
|
||||
MOVHPD alpha+0(FP), X7
|
||||
MOVLPD alpha+0(FP), X7
|
||||
MOVQ x+8(FP), R8
|
||||
MOVQ y+32(FP), R9
|
||||
MOVQ n+56(FP), CX
|
||||
MOVQ incX+64(FP), R11
|
||||
MOVQ incY+72(FP), R12
|
||||
MOVQ ix+80(FP), SI
|
||||
MOVQ iy+88(FP), DI
|
||||
|
||||
MOVQ SI, AX // nextX = ix
|
||||
MOVQ DI, BX // nextY = iy
|
||||
ADDQ R11, AX // nextX += incX
|
||||
ADDQ R12, BX // nextY += incX
|
||||
SHLQ $1, R11 // indX *= 2
|
||||
SHLQ $1, R12 // indY *= 2
|
||||
|
||||
SUBQ $2, CX // n -= 2
|
||||
JL V2 // if n < 0 goto V2
|
||||
|
||||
U2: // n >= 0
|
||||
// y[i] += alpha * x[i] unrolled 2x.
|
||||
MOVHPD 0(R8)(SI*8), X0
|
||||
MOVHPD 0(R9)(DI*8), X1
|
||||
MOVLPD 0(R8)(AX*8), X0
|
||||
MOVLPD 0(R9)(BX*8), X1
|
||||
|
||||
MULPD X7, X0
|
||||
ADDPD X0, X1
|
||||
MOVHPD X1, 0(R9)(DI*8)
|
||||
MOVLPD X1, 0(R9)(BX*8)
|
||||
|
||||
ADDQ R11, SI // ix += incX
|
||||
ADDQ R12, DI // iy += incY
|
||||
ADDQ R11, AX // nextX += incX
|
||||
ADDQ R12, BX // nextY += incY
|
||||
|
||||
SUBQ $2, CX // n -= 2
|
||||
JGE U2 // if n >= 0 goto U2
|
||||
|
||||
V2:
|
||||
ADDQ $2, CX // n += 2
|
||||
JLE E2 // if n <= 0 goto E2
|
||||
|
||||
// y[i] += alpha * x[i] for the last iteration if n is odd.
|
||||
MOVSD 0(R8)(SI*8), X0
|
||||
MOVSD 0(R9)(DI*8), X1
|
||||
MULSD X7, X0
|
||||
ADDSD X0, X1
|
||||
MOVSD X1, 0(R9)(DI*8)
|
||||
|
||||
E2:
|
||||
RET
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// 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.
|
||||
|
||||
//+build !amd64 noasm
|
||||
|
||||
package asm
|
||||
|
||||
func DdotUnitary(x, y []float64) (sum float64) {
|
||||
for i, v := range x {
|
||||
sum += y[i] * v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DdotInc(x, y []float64, n, incX, incY, ix, iy uintptr) (sum float64) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
sum += y[iy] * x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
return
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// 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.
|
||||
|
||||
//+build !noasm
|
||||
|
||||
package asm
|
||||
|
||||
func DdotUnitary(x, y []float64) (sum float64)
|
||||
func DdotInc(x, y []float64, n, incX, incY, ix, iy uintptr) (sum float64)
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
// 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.
|
||||
//
|
||||
// Some of the loop unrolling code is copied from:
|
||||
// http://golang.org/src/math/big/arith_amd64.s
|
||||
// which is distributed under these terms:
|
||||
//
|
||||
// Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//+build !noasm
|
||||
|
||||
// TODO(fhs): use textflag.h after we drop Go 1.3 support
|
||||
//#include "textflag.h"
|
||||
// Don't insert stack check preamble.
|
||||
#define NOSPLIT 4
|
||||
|
||||
|
||||
// func DdotUnitary(x, y []float64) (sum float64)
|
||||
// This function assumes len(y) >= len(x).
|
||||
TEXT ·DdotUnitary(SB),NOSPLIT,$0
|
||||
MOVQ x_len+8(FP), DI // n = len(x)
|
||||
MOVQ x+0(FP), R8
|
||||
MOVQ y+24(FP), R9
|
||||
|
||||
MOVQ $0, SI // i = 0
|
||||
MOVSD $(0.0), X7 // sum = 0
|
||||
|
||||
SUBQ $2, DI // n -= 2
|
||||
JL V1 // if n < 0 goto V1
|
||||
|
||||
U1: // n >= 0
|
||||
// sum += x[i] * y[i] unrolled 2x.
|
||||
MOVUPD 0(R8)(SI*8), X0
|
||||
MOVUPD 0(R9)(SI*8), X1
|
||||
MULPD X1, X0
|
||||
ADDPD X0, X7
|
||||
|
||||
ADDQ $2, SI // i += 2
|
||||
SUBQ $2, DI // n -= 2
|
||||
JGE U1 // if n >= 0 goto U1
|
||||
|
||||
V1: // n > 0
|
||||
ADDQ $2, DI // n += 2
|
||||
JLE E1 // if n <= 0 goto E1
|
||||
|
||||
// sum += x[i] * y[i] for last iteration if n is odd.
|
||||
MOVSD 0(R8)(SI*8), X0
|
||||
MOVSD 0(R9)(SI*8), X1
|
||||
MULSD X1, X0
|
||||
ADDSD X0, X7
|
||||
|
||||
E1:
|
||||
// Add the two sums together.
|
||||
MOVSD X7, X0
|
||||
UNPCKHPD X7, X7
|
||||
ADDSD X0, X7
|
||||
MOVSD X7, sum+48(FP) // return final sum
|
||||
RET
|
||||
|
||||
|
||||
// func DdotInc(x, y []float64, n, incX, incY, ix, iy uintptr) (sum float64)
|
||||
TEXT ·DdotInc(SB),NOSPLIT,$0
|
||||
MOVQ x+0(FP), R8
|
||||
MOVQ y+24(FP), R9
|
||||
MOVQ n+48(FP), CX
|
||||
MOVQ incX+56(FP), R11
|
||||
MOVQ incY+64(FP), R12
|
||||
MOVQ ix+72(FP), R13
|
||||
MOVQ iy+80(FP), R14
|
||||
|
||||
MOVSD $(0.0), X7 // sum = 0
|
||||
LEAQ (R8)(R13*8), SI // p = &x[ix]
|
||||
LEAQ (R9)(R14*8), DI // q = &y[ix]
|
||||
SHLQ $3, R11 // incX *= sizeof(float64)
|
||||
SHLQ $3, R12 // indY *= sizeof(float64)
|
||||
|
||||
SUBQ $2, CX // n -= 2
|
||||
JL V2 // if n < 0 goto V2
|
||||
|
||||
U2: // n >= 0
|
||||
// sum += *p * *q unrolled 2x.
|
||||
MOVHPD (SI), X0
|
||||
MOVHPD (DI), X1
|
||||
ADDQ R11, SI // p += incX
|
||||
ADDQ R12, DI // q += incY
|
||||
MOVLPD (SI), X0
|
||||
MOVLPD (DI), X1
|
||||
ADDQ R11, SI // p += incX
|
||||
ADDQ R12, DI // q += incY
|
||||
|
||||
MULPD X1, X0
|
||||
ADDPD X0, X7
|
||||
|
||||
SUBQ $2, CX // n -= 2
|
||||
JGE U2 // if n >= 0 goto U2
|
||||
|
||||
V2:
|
||||
ADDQ $2, CX // n += 2
|
||||
JLE E2 // if n <= 0 goto E2
|
||||
|
||||
// sum += *p * *q for the last iteration if n is odd.
|
||||
MOVSD (SI), X0
|
||||
MULSD (DI), X0
|
||||
ADDSD X0, X7
|
||||
|
||||
E2:
|
||||
// Add the two sums together.
|
||||
MOVSD X7, X0
|
||||
UNPCKHPD X7, X7
|
||||
ADDSD X0, X7
|
||||
MOVSD X7, sum+88(FP) // return final sum
|
||||
RET
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 asm
|
||||
|
||||
func DsdotUnitary(x, y []float32) (sum float64) {
|
||||
for i, v := range x {
|
||||
sum += float64(y[i]) * float64(v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DsdotInc(x, y []float32, n, incX, incY, ix, iy uintptr) (sum float64) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
sum += float64(y[iy]) * float64(x[ix])
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
return
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// 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.
|
||||
|
||||
//go:generate ./single_precision
|
||||
//go:generate ./complex
|
||||
|
||||
package asm
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 asm
|
||||
|
||||
// The extra z parameter is needed because of floats.AddScaledTo
|
||||
func SaxpyUnitary(alpha float32, x, y, z []float32) {
|
||||
for i, v := range x {
|
||||
z[i] = alpha*v + y[i]
|
||||
}
|
||||
}
|
||||
|
||||
func SaxpyInc(alpha float32, x, y []float32, n, incX, incY, ix, iy uintptr) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
y[iy] += alpha * x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 asm
|
||||
|
||||
func SdotUnitary(x, y []float32) (sum float32) {
|
||||
for i, v := range x {
|
||||
sum += y[i] * v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SdotInc(x, y []float32, n, incX, incY, ix, iy uintptr) (sum float32) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
sum += y[iy] * x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
return
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# 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.
|
||||
|
||||
echo Generating dsdot.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > dsdot.go
|
||||
cat ddot.go \
|
||||
| grep -v '//+build' \
|
||||
| gofmt -r '[]float64 -> []float32' \
|
||||
| gofmt -r 'a * b -> float64(a) * float64(b)' \
|
||||
| sed 's/Ddot/Dsdot/' \
|
||||
>> dsdot.go
|
||||
|
||||
echo Generating sdot.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > sdot.go
|
||||
cat ddot.go \
|
||||
| grep -v '//+build' \
|
||||
| gofmt -r 'float64 -> float32' \
|
||||
| sed 's/Ddot/Sdot/' \
|
||||
>> sdot.go
|
||||
|
||||
echo Generating saxpy.go
|
||||
echo -e '// Generated code do not edit. Run `go generate`.\n' > saxpy.go
|
||||
cat daxpy.go \
|
||||
| grep -v '//+build' \
|
||||
| gofmt -r 'float64 -> float32' \
|
||||
| sed 's/Daxpy/Saxpy/' \
|
||||
>> saxpy.go
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 asm
|
||||
|
||||
// The extra z parameter is needed because of floats.AddScaledTo
|
||||
func ZaxpyUnitary(alpha complex128, x, y, z []complex128) {
|
||||
for i, v := range x {
|
||||
z[i] = alpha*v + y[i]
|
||||
}
|
||||
}
|
||||
|
||||
func ZaxpyInc(alpha complex128, x, y []complex128, n, incX, incY, ix, iy uintptr) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
y[iy] += alpha * x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 asm
|
||||
|
||||
import "math/cmplx"
|
||||
|
||||
func ZdotcUnitary(x, y []complex128) (sum complex128) {
|
||||
for i, v := range x {
|
||||
sum += y[i] * cmplx.Conj(v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ZdotcInc(x, y []complex128, n, incX, incY, ix, iy uintptr) (sum complex128) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
sum += y[iy] * cmplx.Conj(x[ix])
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
return
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Generated code do not edit. Run `go generate`.
|
||||
|
||||
// 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 asm
|
||||
|
||||
func ZdotuUnitary(x, y []complex128) (sum complex128) {
|
||||
for i, v := range x {
|
||||
sum += y[i] * v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ZdotuInc(x, y []complex128, n, incX, incY, ix, iy uintptr) (sum complex128) {
|
||||
for i := 0; i < int(n); i++ {
|
||||
sum += y[iy] * x[ix]
|
||||
ix += incX
|
||||
iy += incY
|
||||
}
|
||||
return
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
clapack/lapack.go
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
sudo: required
|
||||
|
||||
language: go
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BLAS_LIB=OpenBLAS
|
||||
- BLAS_LIB=gonum
|
||||
# Does not currently link correctly. Note that there is an issue with drotgm in ATLAS.
|
||||
# - BLAS_LIB=ATLAS
|
||||
# If we can get multiarch builds on travis.
|
||||
# There are some issues with the Accellerate implementation.
|
||||
#- BLAS_LIB=Accellerate
|
||||
|
||||
# Versions of go that are explicitly supported by gonum.
|
||||
go:
|
||||
- 1.5beta1
|
||||
- 1.3.3
|
||||
- 1.4.2
|
||||
|
||||
# Required for coverage.
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
|
||||
# Install the appropriate BLAS library.
|
||||
install:
|
||||
- bash .travis/$TRAVIS_OS_NAME/$BLAS_LIB/install.sh
|
||||
|
||||
# Get deps, build, test, and ensure the code is gofmt'ed.
|
||||
# If we are building as gonum, then we have access to the coveralls api key, so we can run coverage as well.
|
||||
script:
|
||||
- if [[ "$BLAS_LIB" == "gonum" ]]; then pushd native; fi
|
||||
- go get -d -t -v ./...
|
||||
- go build -v ./...
|
||||
- go test -v ./...
|
||||
- diff <(gofmt -d *.go) <("")
|
||||
- if [[ $TRAVIS_SECURE_ENV_VARS = "true" ]]; then bash -c "${TRAVIS_BUILD_DIR}/.travis/test-coverage.sh"; fi
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
Gonum LAPACK [](https://travis-ci.org/gonum/lapack) [](https://coveralls.io/r/gonum/lapack)
|
||||
======
|
||||
|
||||
A collection of packages to provide LAPACK functionality for the Go programming
|
||||
language (http://golang.org). This provides a partial implementation in native go
|
||||
and a wrapper using cgo to a c-based implementation.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
go get github.com/gonum/blas
|
||||
```
|
||||
|
||||
|
||||
Install OpenBLAS:
|
||||
```
|
||||
git clone https://github.com/xianyi/OpenBLAS
|
||||
cd OpenBLAS
|
||||
make
|
||||
```
|
||||
|
||||
Then install the lapack/cgo package:
|
||||
```sh
|
||||
CGO_LDFLAGS="-L/path/to/OpenBLAS -lopenblas" go install github.com/gonum/lapack/cgo
|
||||
```
|
||||
|
||||
For Windows you can download binary packages for OpenBLAS at
|
||||
http://sourceforge.net/projects/openblas/files/
|
||||
|
||||
If you want to use a different BLAS package such as the Intel MKL you can
|
||||
adjust the `CGO_LDFLAGS` variable:
|
||||
```sh
|
||||
CGO_LDFLAGS="-lmkl_rt" go install github.com/gonum/lapack/cgo
|
||||
```
|
||||
|
||||
## Packages
|
||||
|
||||
### lapack
|
||||
|
||||
Defines the LAPACK API based on http://www.netlib.org/lapack/lapacke.html
|
||||
|
||||
### lapack/clapack
|
||||
|
||||
Binding to a C implementation of the lapacke interface (e.g. OpenBLAS or intel MKL)
|
||||
|
||||
The linker flags (i.e. path to the BLAS library and library name) might have to be adapted.
|
||||
|
||||
The recommended (free) option for good performance on both linux and darwin is OpenBLAS.
|
||||
|
||||
## Issues
|
||||
|
||||
If you find any bugs, feel free to file an issue on the github issue tracker. Discussions on API changes, added features, code review, or similar requests are preferred on the gonum-dev Google Group.
|
||||
|
||||
https://groups.google.com/forum/#!forum/gonum-dev
|
||||
|
||||
## License
|
||||
|
||||
Please see github.com/gonum/license for general license information, contributors, authors, etc on the Gonum suite of packages.
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
// 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 lapack
|
||||
|
||||
import "github.com/gonum/blas"
|
||||
|
||||
const None = 'N'
|
||||
|
||||
type Job byte
|
||||
|
||||
// CompSV determines if the singular values are to be computed in compact form.
|
||||
type CompSV byte
|
||||
|
||||
const (
|
||||
Compact CompSV = 'P'
|
||||
Explicit CompSV = 'I'
|
||||
)
|
||||
|
||||
// Complex128 defines the public complex128 LAPACK API supported by gonum/lapack.
|
||||
type Complex128 interface{}
|
||||
|
||||
// Float64 defines the public float64 LAPACK API supported by gonum/lapack.
|
||||
type Float64 interface {
|
||||
Dpotrf(ul blas.Uplo, n int, a []float64, lda int) (ok bool)
|
||||
}
|
||||
|
||||
// Direct specifies the direction of the multiplication for the Householder matrix.
|
||||
type Direct byte
|
||||
|
||||
const (
|
||||
Forward Direct = 'F' // Reflectors are right-multiplied, H_1 * H_2 * ... * H_k
|
||||
Backward Direct = 'B' // Reflectors are left-multiplied, H_k * ... * H_2 * H_1
|
||||
)
|
||||
|
||||
// StoreV indicates the storage direction of elementary reflectors.
|
||||
type StoreV byte
|
||||
|
||||
const (
|
||||
ColumnWise StoreV = 'C' // Reflector stored in a column of the matrix.
|
||||
RowWise StoreV = 'R' // Reflector stored in a row of the matrix.
|
||||
)
|
||||
|
||||
// MatrixNorm represents the kind of matrix norm to compute.
|
||||
type MatrixNorm byte
|
||||
|
||||
const (
|
||||
MaxAbs MatrixNorm = 'M' // max(abs(A(i,j))) ('M')
|
||||
MaxColumnSum MatrixNorm = 'O' // Maximum column sum (one norm) ('1', 'O')
|
||||
MaxRowSum MatrixNorm = 'I' // Maximum row sum (infinity norm) ('I', 'i')
|
||||
NormFrob MatrixNorm = 'F' // Frobenium norm (sqrt of sum of squares) ('F', 'f', E, 'e')
|
||||
)
|
||||
|
||||
// MatrixType represents the kind of matrix represented in the data.
|
||||
type MatrixType byte
|
||||
|
||||
const (
|
||||
General MatrixType = 'G' // A dense matrix (like blas64.General).
|
||||
)
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
// 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 lapack64 provides a set of convenient wrapper functions for LAPACK
|
||||
// calls, as specified in the netlib standard (www.netlib.org).
|
||||
//
|
||||
// The native Go routines are used by default, and the Use function can be used
|
||||
// to set an alternate implementation.
|
||||
//
|
||||
// If the type of matrix (General, Symmetric, etc.) is known and fixed, it is
|
||||
// used in the wrapper signature. In many cases, however, the type of the matrix
|
||||
// changes during the call to the routine, for example the matrix is symmetric on
|
||||
// entry and is triangular on exit. In these cases the correct types should be checked
|
||||
// in the documentation.
|
||||
//
|
||||
// The full set of Lapack functions is very large, and it is not clear that a
|
||||
// full implementation is desirable, let alone feasible. Please open up an issue
|
||||
// if there is a specific function you need and/or are willing to implement.
|
||||
package lapack64
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/blas/blas64"
|
||||
"github.com/gonum/lapack"
|
||||
"github.com/gonum/lapack/native"
|
||||
)
|
||||
|
||||
var lapack64 lapack.Float64 = native.Implementation{}
|
||||
|
||||
// Use sets the LAPACK float64 implementation to be used by subsequent BLAS calls.
|
||||
// The default implementation is native.Implementation.
|
||||
func Use(l lapack.Float64) {
|
||||
lapack64 = l
|
||||
}
|
||||
|
||||
// Potrf computes the cholesky factorization of a.
|
||||
// A = U^T * U if ul == blas.Upper
|
||||
// A = L * L^T if ul == blas.Lower
|
||||
// The underlying data between the input matrix and output matrix is shared.
|
||||
func Potrf(a blas64.Symmetric) (t blas64.Triangular, ok bool) {
|
||||
ok = lapack64.Dpotrf(a.Uplo, a.N, a.Data, a.Stride)
|
||||
t.Uplo = a.Uplo
|
||||
t.N = a.N
|
||||
t.Data = a.Data
|
||||
t.Stride = a.Stride
|
||||
t.Diag = blas.NonUnit
|
||||
return
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// 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 native
|
||||
|
||||
import "github.com/gonum/blas"
|
||||
|
||||
// Dgelq2 computes the LQ factorization of the m×n matrix a.
|
||||
//
|
||||
// During Dgelq2, a is modified to contain the information to construct Q and L.
|
||||
// The lower triangle of a contains the matrix L. The upper triangular elements
|
||||
// (not including the diagonal) contain the elementary reflectors. Tau is modified
|
||||
// to contain the reflector scales. Tau must have length of at least k = min(m,n)
|
||||
// and this function will panic otherwise.
|
||||
//
|
||||
// See Dgeqr2 for a description of the elementary reflectors and orthonormal
|
||||
// matrix Q. Q is constructed as a product of these elementary reflectors,
|
||||
// Q = H_k ... H_2*H_1.
|
||||
//
|
||||
// Work is temporary storage of length at least m and this function will panic otherwise.
|
||||
func (impl Implementation) Dgelq2(m, n int, a []float64, lda int, tau, work []float64) {
|
||||
checkMatrix(m, n, a, lda)
|
||||
k := min(m, n)
|
||||
if len(tau) < k {
|
||||
panic(badTau)
|
||||
}
|
||||
if len(work) < m {
|
||||
panic(badWork)
|
||||
}
|
||||
for i := 0; i < k; i++ {
|
||||
a[i*lda+i], tau[i] = impl.Dlarfg(n-i, a[i*lda+i], a[i*lda+min(i+1, n-1):], 1)
|
||||
if i < m-1 {
|
||||
aii := a[i*lda+i]
|
||||
a[i*lda+i] = 1
|
||||
impl.Dlarf(blas.Right, m-i-1, n-i,
|
||||
a[i*lda+i:], 1,
|
||||
tau[i],
|
||||
a[(i+1)*lda+i:], lda,
|
||||
work)
|
||||
a[i*lda+i] = aii
|
||||
}
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/lapack"
|
||||
)
|
||||
|
||||
// Dgelqf computes the LQ factorization of the m×n matrix a using a blocked
|
||||
// algorithm. Please see the documentation for Dgelq2 for a description of the
|
||||
// parameters at entry and exit.
|
||||
//
|
||||
// Work is temporary storage, and lwork specifies the usable memory length.
|
||||
// At minimum, lwork >= m, and this function will panic otherwise.
|
||||
// Dgelqf is a blocked LQ factorization, but the block size is limited
|
||||
// by the temporary space available. If lwork == -1, instead of performing Dgelqf,
|
||||
// the optimal work length will be stored into work[0].
|
||||
//
|
||||
// tau must have length at least min(m,n), and this function will panic otherwise.
|
||||
func (impl Implementation) Dgelqf(m, n int, a []float64, lda int, tau, work []float64, lwork int) {
|
||||
nb := impl.Ilaenv(1, "DGELQF", " ", m, n, -1, -1)
|
||||
lworkopt := m * max(nb, 1)
|
||||
if lwork == -1 {
|
||||
work[0] = float64(lworkopt)
|
||||
return
|
||||
}
|
||||
checkMatrix(m, n, a, lda)
|
||||
if len(work) < lwork {
|
||||
panic(shortWork)
|
||||
}
|
||||
if lwork < m {
|
||||
panic(badWork)
|
||||
}
|
||||
k := min(m, n)
|
||||
if len(tau) < k {
|
||||
panic(badTau)
|
||||
}
|
||||
if k == 0 {
|
||||
return
|
||||
}
|
||||
// Find the optimal blocking size based on the size of available memory
|
||||
// and optimal machine parameters.
|
||||
nbmin := 2
|
||||
var nx int
|
||||
iws := m
|
||||
ldwork := nb
|
||||
if nb > 1 && k > nb {
|
||||
nx = max(0, impl.Ilaenv(3, "DGELQF", " ", m, n, -1, -1))
|
||||
if nx < k {
|
||||
iws = m * nb
|
||||
if lwork < iws {
|
||||
nb = lwork / m
|
||||
nbmin = max(2, impl.Ilaenv(2, "DGELQF", " ", m, n, -1, -1))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Computed blocked LQ factorization.
|
||||
var i int
|
||||
if nb >= nbmin && nb < k && nx < k {
|
||||
for i = 0; i < k-nx; i += nb {
|
||||
ib := min(k-i, nb)
|
||||
impl.Dgelq2(ib, n-i, a[i*lda+i:], lda, tau[i:], work)
|
||||
if i+ib < m {
|
||||
impl.Dlarft(lapack.Forward, lapack.RowWise, n-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i:],
|
||||
work, ldwork)
|
||||
impl.Dlarfb(blas.Right, blas.NoTrans, lapack.Forward, lapack.RowWise,
|
||||
m-i-ib, n-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
work, ldwork,
|
||||
a[(i+ib)*lda+i:], lda,
|
||||
work[ib*ldwork:], ldwork)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Perform unblocked LQ factorization on the remainder.
|
||||
if i < k {
|
||||
impl.Dgelq2(m-i, n-i, a[i*lda+i:], lda, tau[i:], work)
|
||||
}
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/lapack"
|
||||
)
|
||||
|
||||
// Dgels finds a minimum-norm solution based on the matrices a and b using the
|
||||
// QR or LQ factorization. Dgels returns false if the matrix
|
||||
// A is singular, and true if this solution was successfully found.
|
||||
//
|
||||
// The minimization problem solved depends on the input parameters.
|
||||
//
|
||||
// 1. If m >= n and trans == blas.NoTrans, Dgels finds X such that || A*X - B||_2
|
||||
// is minimized.
|
||||
// 2. If m < n and trans == blas.NoTrans, Dgels finds the minimum norm solution of
|
||||
// A * X = B.
|
||||
// 3. If m >= n and trans == blas.Trans, Dgels finds the minimum norm solution of
|
||||
// A^T * X = B.
|
||||
// 4. If m < n and trans == blas.Trans, Dgels finds X such that || A*X - B||_2
|
||||
// is minimized.
|
||||
// Note that the least-squares solutions (cases 1 and 3) perform the minimization
|
||||
// per column of B. This is not the same as finding the minimum-norm matrix.
|
||||
//
|
||||
// The matrix a is a general matrix of size m×n and is modified during this call.
|
||||
// The input matrix b is of size max(m,n)×nrhs, and serves two purposes. On entry,
|
||||
// the elements of b specify the input matrix B. B has size m×nrhs if
|
||||
// trans == blas.NoTrans, and n×nrhs if trans == blas.Trans. On exit, the
|
||||
// leading submatrix of b contains the solution vectors X. If trans == blas.NoTrans,
|
||||
// this submatrix is of size n×nrhs, and of size m×nrhs otherwise.
|
||||
//
|
||||
// Work is temporary storage, and lwork specifies the usable memory length.
|
||||
// At minimum, lwork >= max(m,n) + max(m,n,nrhs), and this function will panic
|
||||
// otherwise. A longer work will enable blocked algorithms to be called.
|
||||
// In the special case that lwork == -1, work[0] will be set to the optimal working
|
||||
// length.
|
||||
func (impl Implementation) Dgels(trans blas.Transpose, m, n, nrhs int, a []float64, lda int, b []float64, ldb int, work []float64, lwork int) bool {
|
||||
notran := trans == blas.NoTrans
|
||||
checkMatrix(m, n, a, lda)
|
||||
mn := min(m, n)
|
||||
checkMatrix(mn, nrhs, b, ldb)
|
||||
|
||||
// Find optimal block size.
|
||||
tpsd := true
|
||||
if notran {
|
||||
tpsd = false
|
||||
}
|
||||
var nb int
|
||||
if m >= n {
|
||||
nb = impl.Ilaenv(1, "DGEQRF", " ", m, n, -1, -1)
|
||||
if tpsd {
|
||||
nb = max(nb, impl.Ilaenv(1, "DORMQR", "LN", m, nrhs, n, -1))
|
||||
} else {
|
||||
nb = max(nb, impl.Ilaenv(1, "DORMQR", "LT", m, nrhs, n, -1))
|
||||
}
|
||||
} else {
|
||||
nb = impl.Ilaenv(1, "DGELQF", " ", m, n, -1, -1)
|
||||
if tpsd {
|
||||
nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LT", n, nrhs, m, -1))
|
||||
} else {
|
||||
nb = max(nb, impl.Ilaenv(1, "DORMLQ", "LN", n, nrhs, m, -1))
|
||||
}
|
||||
}
|
||||
if lwork == -1 {
|
||||
work[0] = float64(max(1, mn+max(mn, nrhs)*nb))
|
||||
return true
|
||||
}
|
||||
|
||||
if len(work) < lwork {
|
||||
panic(shortWork)
|
||||
}
|
||||
if lwork < mn+max(mn, nrhs) {
|
||||
panic(badWork)
|
||||
}
|
||||
if m == 0 || n == 0 || nrhs == 0 {
|
||||
impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb)
|
||||
return true
|
||||
}
|
||||
|
||||
// Scale the input matrices if they contain extreme values.
|
||||
smlnum := dlamchS / dlamchP
|
||||
bignum := 1 / smlnum
|
||||
anrm := impl.Dlange(lapack.MaxAbs, m, n, a, lda, nil)
|
||||
var iascl int
|
||||
if anrm > 0 && anrm < smlnum {
|
||||
impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, m, n, a, lda)
|
||||
iascl = 1
|
||||
} else if anrm > bignum {
|
||||
impl.Dlascl(lapack.General, 0, 0, anrm, bignum, m, n, a, lda)
|
||||
} else if anrm == 0 {
|
||||
// Matrix all zeros
|
||||
impl.Dlaset(blas.All, max(m, n), nrhs, 0, 0, b, ldb)
|
||||
return true
|
||||
}
|
||||
brow := m
|
||||
if tpsd {
|
||||
brow = n
|
||||
}
|
||||
bnrm := impl.Dlange(lapack.MaxAbs, brow, nrhs, b, ldb, nil)
|
||||
ibscl := 0
|
||||
if bnrm > 0 && bnrm < smlnum {
|
||||
impl.Dlascl(lapack.General, 0, 0, bnrm, smlnum, brow, nrhs, b, ldb)
|
||||
ibscl = 1
|
||||
} else if bnrm > bignum {
|
||||
impl.Dlascl(lapack.General, 0, 0, bnrm, bignum, brow, nrhs, b, ldb)
|
||||
ibscl = 2
|
||||
}
|
||||
|
||||
// Solve the minimization problem using a QR or an LQ decomposition.
|
||||
var scllen int
|
||||
if m >= n {
|
||||
impl.Dgeqrf(m, n, a, lda, work, work[mn:], lwork-mn)
|
||||
if !tpsd {
|
||||
impl.Dormqr(blas.Left, blas.Trans, m, nrhs, n,
|
||||
a, lda,
|
||||
work,
|
||||
b, ldb,
|
||||
work[mn:], lwork-mn)
|
||||
ok := impl.Dtrtrs(blas.Upper, blas.NoTrans, blas.NonUnit, n, nrhs,
|
||||
a, lda,
|
||||
b, ldb)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
scllen = n
|
||||
} else {
|
||||
ok := impl.Dtrtrs(blas.Upper, blas.Trans, blas.NonUnit, n, nrhs,
|
||||
a, lda,
|
||||
b, ldb)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for i := n; i < m; i++ {
|
||||
for j := 0; j < nrhs; j++ {
|
||||
b[i*ldb+j] = 0
|
||||
}
|
||||
}
|
||||
impl.Dormqr(blas.Left, blas.NoTrans, m, nrhs, n,
|
||||
a, lda,
|
||||
work,
|
||||
b, ldb,
|
||||
work[mn:], lwork-mn)
|
||||
scllen = m
|
||||
}
|
||||
} else {
|
||||
impl.Dgelqf(m, n, a, lda, work, work[mn:], lwork-mn)
|
||||
if !tpsd {
|
||||
ok := impl.Dtrtrs(blas.Lower, blas.NoTrans, blas.NonUnit,
|
||||
m, nrhs,
|
||||
a, lda,
|
||||
b, ldb)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for i := m; i < n; i++ {
|
||||
for j := 0; j < nrhs; j++ {
|
||||
b[i*ldb+j] = 0
|
||||
}
|
||||
}
|
||||
impl.Dormlq(blas.Left, blas.Trans, n, nrhs, m,
|
||||
a, lda,
|
||||
work,
|
||||
b, ldb,
|
||||
work[mn:], lwork-mn)
|
||||
scllen = n
|
||||
} else {
|
||||
impl.Dormlq(blas.Left, blas.NoTrans, n, nrhs, m,
|
||||
a, lda,
|
||||
work,
|
||||
b, ldb,
|
||||
work[mn:], lwork-mn)
|
||||
ok := impl.Dtrtrs(blas.Lower, blas.Trans, blas.NonUnit,
|
||||
m, nrhs,
|
||||
a, lda,
|
||||
b, ldb)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust answer vector based on scaling.
|
||||
if iascl == 1 {
|
||||
impl.Dlascl(lapack.General, 0, 0, anrm, smlnum, scllen, nrhs, b, ldb)
|
||||
}
|
||||
if iascl == 2 {
|
||||
impl.Dlascl(lapack.General, 0, 0, anrm, bignum, scllen, nrhs, b, ldb)
|
||||
}
|
||||
if ibscl == 1 {
|
||||
impl.Dlascl(lapack.General, 0, 0, smlnum, bnrm, scllen, nrhs, b, ldb)
|
||||
}
|
||||
if ibscl == 2 {
|
||||
impl.Dlascl(lapack.General, 0, 0, bignum, bnrm, scllen, nrhs, b, ldb)
|
||||
}
|
||||
return true
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
// 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 native
|
||||
|
||||
import "github.com/gonum/blas"
|
||||
|
||||
// Dgeqr2 computes a QR factorization of the m×n matrix a.
|
||||
//
|
||||
// In a QR factorization, Q is an m×m orthonormal matrix, and R is an
|
||||
// upper triangular m×n matrix.
|
||||
//
|
||||
// During Dgeqr2, a is modified to contain the information to construct Q and R.
|
||||
// The upper triangle of a contains the matrix R. The lower triangular elements
|
||||
// (not including the diagonal) contain the elementary reflectors. Tau is modified
|
||||
// to contain the reflector scales. Tau must have length at least k = min(m,n), and
|
||||
// this function will panic otherwise.
|
||||
//
|
||||
// The ith elementary reflector can be explicitly constructed by first extracting
|
||||
// the
|
||||
// v[j] = 0 j < i
|
||||
// v[j] = i j == i
|
||||
// v[j] = a[i*lda+j] j > i
|
||||
// and computing h_i = I - tau[i] * v * v^T.
|
||||
//
|
||||
// The orthonormal matrix Q can be constucted from a product of these elementary
|
||||
// reflectors, Q = H_1*H_2 ... H_k, where k = min(m,n).
|
||||
//
|
||||
// Work is temporary storage of length at least n and this function will panic otherwise.
|
||||
func (impl Implementation) Dgeqr2(m, n int, a []float64, lda int, tau, work []float64) {
|
||||
// TODO(btracey): This is oriented such that columns of a are eliminated.
|
||||
// This likely could be re-arranged to take better advantage of row-major
|
||||
// storage.
|
||||
checkMatrix(m, n, a, lda)
|
||||
if len(work) < n {
|
||||
panic(badWork)
|
||||
}
|
||||
k := min(m, n)
|
||||
if len(tau) < k {
|
||||
panic(badTau)
|
||||
}
|
||||
for i := 0; i < k; i++ {
|
||||
// Generate elementary reflector H(i).
|
||||
a[i*lda+i], tau[i] = impl.Dlarfg(m-i, a[i*lda+i], a[min((i+1), m-1)*lda+i:], lda)
|
||||
if i < n-1 {
|
||||
aii := a[i*lda+i]
|
||||
a[i*lda+i] = 1
|
||||
impl.Dlarf(blas.Left, m-i, n-i-1,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i],
|
||||
a[i*lda+i+1:], lda,
|
||||
work)
|
||||
a[i*lda+i] = aii
|
||||
}
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/lapack"
|
||||
)
|
||||
|
||||
// Dgeqrf computes the QR factorization of the m×n matrix a using a blocked
|
||||
// algorithm. Please see the documentation for Dgeqr2 for a description of the
|
||||
// parameters at entry and exit.
|
||||
//
|
||||
// Work is temporary storage, and lwork specifies the usable memory length.
|
||||
// At minimum, lwork >= m and this function will panic otherwise.
|
||||
// Dgeqrf is a blocked LQ factorization, but the block size is limited
|
||||
// by the temporary space available. If lwork == -1, instead of performing Dgelqf,
|
||||
// the optimal work length will be stored into work[0].
|
||||
//
|
||||
// tau must be at least len min(m,n), and this function will panic otherwise.
|
||||
func (impl Implementation) Dgeqrf(m, n int, a []float64, lda int, tau, work []float64, lwork int) {
|
||||
// TODO(btracey): This algorithm is oriented for column-major storage.
|
||||
// Consider modifying the algorithm to better suit row-major storage.
|
||||
|
||||
// nb is the optimal blocksize, i.e. the number of columns transformed at a time.
|
||||
nb := impl.Ilaenv(1, "DGEQRF", " ", m, n, -1, -1)
|
||||
lworkopt := n * max(nb, 1)
|
||||
lworkopt = max(n, lworkopt)
|
||||
if lwork == -1 {
|
||||
work[0] = float64(lworkopt)
|
||||
return
|
||||
}
|
||||
checkMatrix(m, n, a, lda)
|
||||
if len(work) < lwork {
|
||||
panic(shortWork)
|
||||
}
|
||||
if lwork < n {
|
||||
panic(badWork)
|
||||
}
|
||||
k := min(m, n)
|
||||
if len(tau) < k {
|
||||
panic(badTau)
|
||||
}
|
||||
if k == 0 {
|
||||
return
|
||||
}
|
||||
nbmin := 2 // Minimal number of blocks
|
||||
var nx int // Use unblocked (unless changed in the next for loop)
|
||||
iws := n
|
||||
ldwork := nb
|
||||
// Only consider blocked if the suggested number of blocks is > 1 and the
|
||||
// number of columns is sufficiently large.
|
||||
if nb > 1 && k > nb {
|
||||
// nx is the crossover point. Above this value the blocked routine should be used.
|
||||
nx = max(0, impl.Ilaenv(3, "DGEQRF", " ", m, n, -1, -1))
|
||||
if k > nx {
|
||||
iws = ldwork * n
|
||||
if lwork < iws {
|
||||
// Not enough workspace to use the optimal number of blocks. Instead,
|
||||
// get the maximum allowable number of blocks.
|
||||
nb = lwork / n
|
||||
nbmin = max(2, impl.Ilaenv(2, "DGEQRF", " ", m, n, -1, -1))
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := range work {
|
||||
work[i] = 0
|
||||
}
|
||||
// Compute QR using a blocked algorithm.
|
||||
var i int
|
||||
if nb >= nbmin && nb < k && nx < k {
|
||||
for i = 0; i < k-nx; i += nb {
|
||||
ib := min(k-i, nb)
|
||||
// Compute the QR factorization of the current block.
|
||||
impl.Dgeqr2(m-i, ib, a[i*lda+i:], lda, tau[i:], work)
|
||||
if i+ib < n {
|
||||
// Form the triangular factor of the block reflector and apply H^T
|
||||
// In Dlarft, work becomes the T matrix.
|
||||
impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i:],
|
||||
work, ldwork)
|
||||
impl.Dlarfb(blas.Left, blas.Trans, lapack.Forward, lapack.ColumnWise,
|
||||
m-i, n-i-ib, ib,
|
||||
a[i*lda+i:], lda,
|
||||
work, ldwork,
|
||||
a[i*lda+i+ib:], lda,
|
||||
work[ib*ldwork:], ldwork)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Call unblocked code on the remaining columns.
|
||||
if i < k {
|
||||
impl.Dgeqr2(m-i, n-i, a[i*lda+i:], lda, tau[i:], work)
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gonum/lapack"
|
||||
)
|
||||
|
||||
// Dlange computes the matrix norm of the general m×n matrix a. The input norm
|
||||
// specifies the norm computed.
|
||||
// lapack.MaxAbs: the maximum absolute value of an element.
|
||||
// lapack.MaxColumnSum: the maximum column sum of the absolute values of the entries.
|
||||
// lapack.MaxRowSum: the maximum row sum of the absolute values of the entries.
|
||||
// lapack.Frobenius: the square root of the sum of the squares of the entries.
|
||||
// If norm == lapack.MaxColumnSum, work must be of length n, and this function will panic otherwise.
|
||||
// There are no restrictions on work for the other matrix norms.
|
||||
func (impl Implementation) Dlange(norm lapack.MatrixNorm, m, n int, a []float64, lda int, work []float64) float64 {
|
||||
// TODO(btracey): These should probably be refactored to use BLAS calls.
|
||||
checkMatrix(m, n, a, lda)
|
||||
if m == 0 && n == 0 {
|
||||
return 0
|
||||
}
|
||||
if norm == lapack.MaxAbs {
|
||||
var value float64
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < n; j++ {
|
||||
value = math.Max(value, math.Abs(a[i*lda+j]))
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
if norm == lapack.MaxColumnSum {
|
||||
if len(work) < n {
|
||||
panic(badWork)
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
work[i] = 0
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < n; j++ {
|
||||
work[j] += math.Abs(a[i*lda+j])
|
||||
}
|
||||
}
|
||||
var value float64
|
||||
for i := 0; i < n; i++ {
|
||||
value = math.Max(value, work[i])
|
||||
}
|
||||
return value
|
||||
}
|
||||
if norm == lapack.MaxRowSum {
|
||||
var value float64
|
||||
for i := 0; i < m; i++ {
|
||||
var sum float64
|
||||
for j := 0; j < n; j++ {
|
||||
sum += math.Abs(a[i*lda+j])
|
||||
}
|
||||
value = math.Max(value, sum)
|
||||
}
|
||||
return value
|
||||
}
|
||||
if norm == lapack.NormFrob {
|
||||
var value float64
|
||||
scale := 0.0
|
||||
sum := 1.0
|
||||
for i := 0; i < m; i++ {
|
||||
scale, sum = impl.Dlassq(n, a[i*lda:], 1, scale, sum)
|
||||
}
|
||||
value = scale * math.Sqrt(sum)
|
||||
return value
|
||||
}
|
||||
panic("lapack: bad matrix norm")
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// 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 native
|
||||
|
||||
import "math"
|
||||
|
||||
// Dlapy2 is the LAPACK version of math.Hypot.
|
||||
func (Implementation) Dlapy2(x, y float64) float64 {
|
||||
return math.Hypot(x, y)
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/blas/blas64"
|
||||
)
|
||||
|
||||
// Dlarf applies an elementary reflector to a general rectangular matrix c.
|
||||
// This computes
|
||||
// c = h * c if side == Left
|
||||
// c = c * h if side == right
|
||||
// where
|
||||
// h = 1 - tau * v * v^T
|
||||
// and c is an m * n matrix.
|
||||
//
|
||||
|
||||
// Work is temporary storage of length at least m if side == Left and at least
|
||||
// n if side == Right. This function will panic if this length requirement is not met.
|
||||
func (impl Implementation) Dlarf(side blas.Side, m, n int, v []float64, incv int, tau float64, c []float64, ldc int, work []float64) {
|
||||
applyleft := side == blas.Left
|
||||
if (applyleft && len(work) < n) || (!applyleft && len(work) < m) {
|
||||
panic(badWork)
|
||||
}
|
||||
checkMatrix(m, n, c, ldc)
|
||||
|
||||
// v has length m if applyleft and n otherwise.
|
||||
lenV := n
|
||||
if applyleft {
|
||||
lenV = m
|
||||
}
|
||||
|
||||
checkVector(lenV, v, incv)
|
||||
|
||||
lastv := 0 // last non-zero element of v
|
||||
lastc := 0 // last non-zero row/column of c
|
||||
if tau != 0 {
|
||||
var i int
|
||||
if applyleft {
|
||||
lastv = m - 1
|
||||
} else {
|
||||
lastv = n - 1
|
||||
}
|
||||
if incv > 0 {
|
||||
i = lastv * incv
|
||||
}
|
||||
|
||||
// Look for the last non-zero row in v.
|
||||
for lastv >= 0 && v[i] == 0 {
|
||||
lastv--
|
||||
i -= incv
|
||||
}
|
||||
if applyleft {
|
||||
// Scan for the last non-zero column in C[0:lastv, :]
|
||||
lastc = impl.Iladlc(lastv+1, n, c, ldc)
|
||||
} else {
|
||||
// Scan for the last non-zero row in C[:, 0:lastv]
|
||||
lastc = impl.Iladlr(m, lastv+1, c, ldc)
|
||||
}
|
||||
}
|
||||
if lastv == -1 || lastc == -1 {
|
||||
return
|
||||
}
|
||||
// Sometimes 1-indexing is nicer ...
|
||||
bi := blas64.Implementation()
|
||||
if applyleft {
|
||||
// Form H * C
|
||||
// w[0:lastc+1] = c[1:lastv+1, 1:lastc+1]^T * v[1:lastv+1,1]
|
||||
bi.Dgemv(blas.Trans, lastv+1, lastc+1, 1, c, ldc, v, incv, 0, work, 1)
|
||||
// c[0: lastv, 0: lastc] = c[...] - w[0:lastv, 1] * v[1:lastc, 1]^T
|
||||
bi.Dger(lastv+1, lastc+1, -tau, v, incv, work, 1, c, ldc)
|
||||
return
|
||||
}
|
||||
// Form C*H
|
||||
// w[0:lastc+1,1] := c[0:lastc+1,0:lastv+1] * v[0:lastv+1,1]
|
||||
bi.Dgemv(blas.NoTrans, lastc+1, lastv+1, 1, c, ldc, v, incv, 0, work, 1)
|
||||
// c[0:lastc+1,0:lastv+1] = c[...] - w[0:lastc+1,0] * v[0:lastv+1,0]^T
|
||||
bi.Dger(lastc+1, lastv+1, -tau, work, 1, v, incv, c, ldc)
|
||||
}
|
||||
+424
@@ -0,0 +1,424 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/blas/blas64"
|
||||
"github.com/gonum/lapack"
|
||||
)
|
||||
|
||||
// Dlarfb applies a block reflector to a matrix.
|
||||
//
|
||||
// In the call to Dlarfb, the mxn c is multiplied by the implicitly defined matrix h as follows:
|
||||
// c = h * c if side == Left and trans == NoTrans
|
||||
// c = c * h if side == Right and trans == NoTrans
|
||||
// c = h^T * c if side == Left and trans == Trans
|
||||
// c = c * h^t if side == Right and trans == Trans
|
||||
// h is a product of elementary reflectors. direct sets the direction of multiplication
|
||||
// h = h_1 * h_2 * ... * h_k if direct == Forward
|
||||
// h = h_k * h_k-1 * ... * h_1 if direct == Backward
|
||||
// The combination of direct and store defines the orientation of the elementary
|
||||
// reflectors. In all cases the ones on the diagonal are implicitly represented.
|
||||
//
|
||||
// If direct == lapack.Forward and store == lapack.ColumnWise
|
||||
// V = ( 1 )
|
||||
// ( v1 1 )
|
||||
// ( v1 v2 1 )
|
||||
// ( v1 v2 v3 )
|
||||
// ( v1 v2 v3 )
|
||||
// If direct == lapack.Forward and store == lapack.RowWise
|
||||
// V = ( 1 v1 v1 v1 v1 )
|
||||
// ( 1 v2 v2 v2 )
|
||||
// ( 1 v3 v3 )
|
||||
// If direct == lapack.Backward and store == lapack.ColumnWise
|
||||
// V = ( v1 v2 v3 )
|
||||
// ( v1 v2 v3 )
|
||||
// ( 1 v2 v3 )
|
||||
// ( 1 v3 )
|
||||
// ( 1 )
|
||||
// If direct == lapack.Backward and store == lapack.RowWise
|
||||
// V = ( v1 v1 1 )
|
||||
// ( v2 v2 v2 1 )
|
||||
// ( v3 v3 v3 v3 1 )
|
||||
// An elementary reflector can be explicitly constructed by extracting the
|
||||
// corresponding elements of v, placing a 1 where the diagonal would be, and
|
||||
// placing zeros in the remaining elements.
|
||||
//
|
||||
// t is a k×k matrix containing the block reflector, and this function will panic
|
||||
// if t is not of sufficient size. See Dlarft for more information.
|
||||
//
|
||||
// Work is a temporary storage matrix with stride ldwork.
|
||||
// Work must be of size at least n×k side == Left and m×k if side == Right, and
|
||||
// this function will panic if this size is not met.
|
||||
func (Implementation) Dlarfb(side blas.Side, trans blas.Transpose, direct lapack.Direct,
|
||||
store lapack.StoreV, m, n, k int, v []float64, ldv int, t []float64, ldt int,
|
||||
c []float64, ldc int, work []float64, ldwork int) {
|
||||
|
||||
checkMatrix(m, n, c, ldc)
|
||||
if m == 0 || n == 0 {
|
||||
return
|
||||
}
|
||||
if k < 0 {
|
||||
panic("lapack: negative number of transforms")
|
||||
}
|
||||
if side != blas.Left && side != blas.Right {
|
||||
panic(badSide)
|
||||
}
|
||||
if trans != blas.Trans && trans != blas.NoTrans {
|
||||
panic(badTrans)
|
||||
}
|
||||
if direct != lapack.Forward && direct != lapack.Backward {
|
||||
panic(badDirect)
|
||||
}
|
||||
if store != lapack.ColumnWise && store != lapack.RowWise {
|
||||
panic(badStore)
|
||||
}
|
||||
|
||||
rowsWork := n
|
||||
if side == blas.Right {
|
||||
rowsWork = m
|
||||
}
|
||||
checkMatrix(rowsWork, k, work, ldwork)
|
||||
|
||||
bi := blas64.Implementation()
|
||||
|
||||
transt := blas.Trans
|
||||
if trans == blas.Trans {
|
||||
transt = blas.NoTrans
|
||||
}
|
||||
// TODO(btracey): This follows the original Lapack code where the
|
||||
// elements are copied into the columns of the working array. The
|
||||
// loops should go in the other direction so the data is written
|
||||
// into the rows of work so the copy is not strided. A bigger change
|
||||
// would be to replace work with work^T, but benchmarks would be
|
||||
// needed to see if the change is merited.
|
||||
if store == lapack.ColumnWise {
|
||||
if direct == lapack.Forward {
|
||||
// V1 is the first k rows of C. V2 is the remaining rows.
|
||||
if side == blas.Left {
|
||||
// W = C^T V = C1^T V1 + C2^T V2 (stored in work).
|
||||
|
||||
// W = C1.
|
||||
for j := 0; j < k; j++ {
|
||||
bi.Dcopy(n, c[j*ldc:], 1, work[j:], ldwork)
|
||||
}
|
||||
// W = W * V1.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit,
|
||||
n, k, 1,
|
||||
v, ldv,
|
||||
work, ldwork)
|
||||
if m > k {
|
||||
// W = W + C2^T V2.
|
||||
bi.Dgemm(blas.Trans, blas.NoTrans, n, k, m-k,
|
||||
1, c[k*ldc:], ldc, v[k*ldv:], ldv,
|
||||
1, work, ldwork)
|
||||
}
|
||||
// W = W * T^T or W * T.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, transt, blas.NonUnit, n, k,
|
||||
1, t, ldt,
|
||||
work, ldwork)
|
||||
// C -= V * W^T.
|
||||
if m > k {
|
||||
// C2 -= V2 * W^T.
|
||||
bi.Dgemm(blas.NoTrans, blas.Trans, m-k, n, k,
|
||||
-1, v[k*ldv:], ldv, work, ldwork,
|
||||
1, c[k*ldc:], ldc)
|
||||
}
|
||||
// W *= V1^T.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, n, k,
|
||||
1, v, ldv,
|
||||
work, ldwork)
|
||||
// C1 -= W^T.
|
||||
// TODO(btracey): This should use blas.Axpy.
|
||||
for i := 0; i < n; i++ {
|
||||
for j := 0; j < k; j++ {
|
||||
c[j*ldc+i] -= work[i*ldwork+j]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Form C = C * H or C * H^T, where C = (C1 C2).
|
||||
|
||||
// W = C1.
|
||||
for i := 0; i < k; i++ {
|
||||
bi.Dcopy(m, c[i:], ldc, work[i:], ldwork)
|
||||
}
|
||||
// W *= V1.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, m, k,
|
||||
1, v, ldv,
|
||||
work, ldwork)
|
||||
if n > k {
|
||||
bi.Dgemm(blas.NoTrans, blas.NoTrans, m, k, n-k,
|
||||
1, c[k:], ldc, v[k*ldv:], ldv,
|
||||
1, work, ldwork)
|
||||
}
|
||||
// W *= T or T^T.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, trans, blas.NonUnit, m, k,
|
||||
1, t, ldt,
|
||||
work, ldwork)
|
||||
if n > k {
|
||||
bi.Dgemm(blas.NoTrans, blas.Trans, m, n-k, k,
|
||||
-1, work, ldwork, v[k*ldv:], ldv,
|
||||
1, c[k:], ldc)
|
||||
}
|
||||
// C -= W * V^T.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, m, k,
|
||||
1, v, ldv,
|
||||
work, ldwork)
|
||||
// C -= W.
|
||||
// TODO(btracey): This should use blas.Axpy.
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < k; j++ {
|
||||
c[i*ldc+j] -= work[i*ldwork+j]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// V = (V1)
|
||||
// = (V2) (last k rows)
|
||||
// Where V2 is unit upper triangular.
|
||||
if side == blas.Left {
|
||||
// Form H * C or
|
||||
// W = C^T V.
|
||||
|
||||
// W = C2^T.
|
||||
for j := 0; j < k; j++ {
|
||||
bi.Dcopy(n, c[(m-k+j)*ldc:], 1, work[j:], ldwork)
|
||||
}
|
||||
// W *= V2.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, n, k,
|
||||
1, v[(m-k)*ldv:], ldv,
|
||||
work, ldwork)
|
||||
if m > k {
|
||||
// W += C1^T * V1.
|
||||
bi.Dgemm(blas.Trans, blas.NoTrans, n, k, m-k,
|
||||
1, c, ldc, v, ldv,
|
||||
1, work, ldwork)
|
||||
}
|
||||
// W *= T or T^T.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, transt, blas.NonUnit, n, k,
|
||||
1, t, ldt,
|
||||
work, ldwork)
|
||||
// C -= V * W^T.
|
||||
if m > k {
|
||||
bi.Dgemm(blas.NoTrans, blas.Trans, m-k, n, k,
|
||||
-1, v, ldv, work, ldwork,
|
||||
1, c, ldc)
|
||||
}
|
||||
// W *= V2^T.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, n, k,
|
||||
1, v[(m-k)*ldv:], ldv,
|
||||
work, ldwork)
|
||||
// C2 -= W^T.
|
||||
// TODO(btracey): This should use blas.Axpy.
|
||||
for i := 0; i < n; i++ {
|
||||
for j := 0; j < k; j++ {
|
||||
c[(m-k+j)*ldc+i] -= work[i*ldwork+j]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Form C * H or C * H^T where C = (C1 C2).
|
||||
// W = C * V.
|
||||
|
||||
// W = C2.
|
||||
for j := 0; j < k; j++ {
|
||||
bi.Dcopy(m, c[n-k+j:], ldc, work[j:], ldwork)
|
||||
}
|
||||
|
||||
// W = W * V2.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, m, k,
|
||||
1, v[(n-k)*ldv:], ldv,
|
||||
work, ldwork)
|
||||
if n > k {
|
||||
bi.Dgemm(blas.NoTrans, blas.NoTrans, m, k, n-k,
|
||||
1, c, ldc, v, ldv,
|
||||
1, work, ldwork)
|
||||
}
|
||||
// W *= T or T^T.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, trans, blas.NonUnit, m, k,
|
||||
1, t, ldt,
|
||||
work, ldwork)
|
||||
// C -= W * V^T.
|
||||
if n > k {
|
||||
// C1 -= W * V1^T.
|
||||
bi.Dgemm(blas.NoTrans, blas.Trans, m, n-k, k,
|
||||
-1, work, ldwork, v, ldv,
|
||||
1, c, ldc)
|
||||
}
|
||||
// W *= V2^T.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, m, k,
|
||||
1, v[(n-k)*ldv:], ldv,
|
||||
work, ldwork)
|
||||
// C2 -= W.
|
||||
// TODO(btracey): This should use blas.Axpy.
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < k; j++ {
|
||||
c[i*ldc+n-k+j] -= work[i*ldwork+j]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Store = Rowwise.
|
||||
if direct == lapack.Forward {
|
||||
// V = (V1 V2) where v1 is unit upper triangular.
|
||||
if side == blas.Left {
|
||||
// Form H * C or H^T * C where C = (C1; C2).
|
||||
// W = C^T * V^T.
|
||||
|
||||
// W = C1^T.
|
||||
for j := 0; j < k; j++ {
|
||||
bi.Dcopy(n, c[j*ldc:], 1, work[j:], ldwork)
|
||||
}
|
||||
// W *= V1^T.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, n, k,
|
||||
1, v, ldv,
|
||||
work, ldwork)
|
||||
if m > k {
|
||||
bi.Dgemm(blas.Trans, blas.Trans, n, k, m-k,
|
||||
1, c[k*ldc:], ldc, v[k:], ldv,
|
||||
1, work, ldwork)
|
||||
}
|
||||
// W *= T or T^T.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, transt, blas.NonUnit, n, k,
|
||||
1, t, ldt,
|
||||
work, ldwork)
|
||||
// C -= V^T * W^T.
|
||||
if m > k {
|
||||
bi.Dgemm(blas.Trans, blas.Trans, m-k, n, k,
|
||||
-1, v[k:], ldv, work, ldwork,
|
||||
1, c[k*ldc:], ldc)
|
||||
}
|
||||
// W *= V1.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, n, k,
|
||||
1, v, ldv,
|
||||
work, ldwork)
|
||||
// C1 -= W^T.
|
||||
// TODO(btracey): This should use blas.Axpy.
|
||||
for i := 0; i < n; i++ {
|
||||
for j := 0; j < k; j++ {
|
||||
c[j*ldc+i] -= work[i*ldwork+j]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Form C * H or C * H^T where C = (C1 C2).
|
||||
// W = C * V^T.
|
||||
|
||||
// W = C1.
|
||||
for j := 0; j < k; j++ {
|
||||
bi.Dcopy(m, c[j:], ldc, work[j:], ldwork)
|
||||
}
|
||||
// W *= V1^T.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, blas.Trans, blas.Unit, m, k,
|
||||
1, v, ldv,
|
||||
work, ldwork)
|
||||
if n > k {
|
||||
bi.Dgemm(blas.NoTrans, blas.Trans, m, k, n-k,
|
||||
1, c[k:], ldc, v[k:], ldv,
|
||||
1, work, ldwork)
|
||||
}
|
||||
// W *= T or T^T.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, trans, blas.NonUnit, m, k,
|
||||
1, t, ldt,
|
||||
work, ldwork)
|
||||
// C -= W * V.
|
||||
if n > k {
|
||||
bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n-k, k,
|
||||
-1, work, ldwork, v[k:], ldv,
|
||||
1, c[k:], ldc)
|
||||
}
|
||||
// W *= V1.
|
||||
bi.Dtrmm(blas.Right, blas.Upper, blas.NoTrans, blas.Unit, m, k,
|
||||
1, v, ldv,
|
||||
work, ldwork)
|
||||
// C1 -= W.
|
||||
// TODO(btracey): This should use blas.Axpy.
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < k; j++ {
|
||||
c[i*ldc+j] -= work[i*ldwork+j]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// V = (V1 V2) where V2 is the last k columns and is lower unit triangular.
|
||||
if side == blas.Left {
|
||||
// Form H * C or H^T C where C = (C1 ; C2).
|
||||
// W = C^T * V^T.
|
||||
|
||||
// W = C2^T.
|
||||
for j := 0; j < k; j++ {
|
||||
bi.Dcopy(n, c[(m-k+j)*ldc:], 1, work[j:], ldwork)
|
||||
}
|
||||
// W *= V2^T.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, n, k,
|
||||
1, v[m-k:], ldv,
|
||||
work, ldwork)
|
||||
if m > k {
|
||||
bi.Dgemm(blas.Trans, blas.Trans, n, k, m-k,
|
||||
1, c, ldc, v, ldv,
|
||||
1, work, ldwork)
|
||||
}
|
||||
// W *= T or T^T.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, transt, blas.NonUnit, n, k,
|
||||
1, t, ldt,
|
||||
work, ldwork)
|
||||
// C -= V^T * W^T.
|
||||
if m > k {
|
||||
bi.Dgemm(blas.Trans, blas.Trans, m-k, n, k,
|
||||
-1, v, ldv, work, ldwork,
|
||||
1, c, ldc)
|
||||
}
|
||||
// W *= V2.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, n, k,
|
||||
1, v[m-k:], ldv,
|
||||
work, ldwork)
|
||||
// C2 -= W^T.
|
||||
// TODO(btracey): This should use blas.Axpy.
|
||||
for i := 0; i < n; i++ {
|
||||
for j := 0; j < k; j++ {
|
||||
c[(m-k+j)*ldc+i] -= work[i*ldwork+j]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// Form C * H or C * H^T where C = (C1 C2).
|
||||
// W = C * V^T.
|
||||
// W = C2.
|
||||
for j := 0; j < k; j++ {
|
||||
bi.Dcopy(m, c[n-k+j:], ldc, work[j:], ldwork)
|
||||
}
|
||||
// W *= V2^T.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, blas.Trans, blas.Unit, m, k,
|
||||
1, v[n-k:], ldv,
|
||||
work, ldwork)
|
||||
if n > k {
|
||||
bi.Dgemm(blas.NoTrans, blas.Trans, m, k, n-k,
|
||||
1, c, ldc, v, ldv,
|
||||
1, work, ldwork)
|
||||
}
|
||||
// W *= T or T^T.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, trans, blas.NonUnit, m, k,
|
||||
1, t, ldt,
|
||||
work, ldwork)
|
||||
// C -= W * V.
|
||||
if n > k {
|
||||
bi.Dgemm(blas.NoTrans, blas.NoTrans, m, n-k, k,
|
||||
-1, work, ldwork, v, ldv,
|
||||
1, c, ldc)
|
||||
}
|
||||
// W *= V2.
|
||||
bi.Dtrmm(blas.Right, blas.Lower, blas.NoTrans, blas.Unit, m, k,
|
||||
1, v[n-k:], ldv,
|
||||
work, ldwork)
|
||||
// C1 -= W.
|
||||
// TODO(btracey): This should use blas.Axpy.
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < k; j++ {
|
||||
c[i*ldc+n-k+j] -= work[i*ldwork+j]
|
||||
}
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gonum/blas/blas64"
|
||||
)
|
||||
|
||||
// Dlarfg generates an elementary reflector for a Householder matrix. It creates
|
||||
// a real elementary reflector of order n such that
|
||||
// H * (alpha) = (beta)
|
||||
// ( x) ( 0)
|
||||
// H^T * H = I
|
||||
// H is represented in the form
|
||||
// H = 1 - tau * (1; v) * (1 v^T)
|
||||
// where tau is a real scalar.
|
||||
//
|
||||
// On entry, x contains the vector x, on exit it contains v.
|
||||
func (impl Implementation) Dlarfg(n int, alpha float64, x []float64, incX int) (beta, tau float64) {
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
if n <= 1 {
|
||||
return alpha, 0
|
||||
}
|
||||
checkVector(n-1, x, incX)
|
||||
bi := blas64.Implementation()
|
||||
xnorm := bi.Dnrm2(n-1, x, incX)
|
||||
if xnorm == 0 {
|
||||
return alpha, 0
|
||||
}
|
||||
beta = -math.Copysign(impl.Dlapy2(alpha, xnorm), alpha)
|
||||
safmin := dlamchS / dlamchE
|
||||
knt := 0
|
||||
if math.Abs(beta) < safmin {
|
||||
// xnorm and beta may be innacurate, scale x and recompute.
|
||||
rsafmn := 1 / safmin
|
||||
for {
|
||||
knt++
|
||||
bi.Dscal(n-1, rsafmn, x, incX)
|
||||
beta *= rsafmn
|
||||
alpha *= rsafmn
|
||||
if math.Abs(beta) >= safmin {
|
||||
break
|
||||
}
|
||||
}
|
||||
xnorm = bi.Dnrm2(n-1, x, incX)
|
||||
beta = -math.Copysign(impl.Dlapy2(alpha, xnorm), alpha)
|
||||
}
|
||||
tau = (beta - alpha) / beta
|
||||
bi.Dscal(n-1, 1/(alpha-beta), x, incX)
|
||||
for j := 0; j < knt; j++ {
|
||||
beta *= safmin
|
||||
}
|
||||
return beta, tau
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/blas/blas64"
|
||||
"github.com/gonum/lapack"
|
||||
)
|
||||
|
||||
// Dlarft forms the triangular factor t of a block reflector, storing the answer
|
||||
// in t.
|
||||
// H = 1 - V * T * V^T if store == lapack.ColumnWise
|
||||
// H = 1 - V^T * T * V if store == lapack.RowWise
|
||||
// H is defined by a product of the elementary reflectors where
|
||||
// H = H_1 * H_2 * ... * H_k if direct == lapack.Forward
|
||||
// H = H_k * H_k-1 * ... * H_1 if direct == lapack.Backward
|
||||
//
|
||||
// t is a k×k triangular matrix. t is upper triangular if direct = lapack.Forward
|
||||
// and lower triangular otherwise. This function will panic if t is not of
|
||||
// sufficient size.
|
||||
//
|
||||
// store describes the storage of the elementary reflectors in v. Please see
|
||||
// Dlarfb for a description of layout.
|
||||
//
|
||||
// tau contains the scalar factor of the elementary reflectors h.
|
||||
func (Implementation) Dlarft(direct lapack.Direct, store lapack.StoreV, n, k int,
|
||||
v []float64, ldv int, tau []float64, t []float64, ldt int) {
|
||||
if n == 0 {
|
||||
return
|
||||
}
|
||||
if n < 0 || k < 0 {
|
||||
panic(negDimension)
|
||||
}
|
||||
if direct != lapack.Forward && direct != lapack.Backward {
|
||||
panic(badDirect)
|
||||
}
|
||||
if store != lapack.RowWise && store != lapack.ColumnWise {
|
||||
panic(badStore)
|
||||
}
|
||||
if len(tau) < k {
|
||||
panic(badTau)
|
||||
}
|
||||
checkMatrix(k, k, t, ldt)
|
||||
bi := blas64.Implementation()
|
||||
// TODO(btracey): There are a number of minor obvious loop optimizations here.
|
||||
// TODO(btracey): It may be possible to rearrange some of the code so that
|
||||
// index of 1 is more common in the Dgemv.
|
||||
if direct == lapack.Forward {
|
||||
prevlastv := n - 1
|
||||
for i := 0; i < k; i++ {
|
||||
prevlastv = max(i, prevlastv)
|
||||
if tau[i] == 0 {
|
||||
for j := 0; j <= i; j++ {
|
||||
t[j*ldt+i] = 0
|
||||
}
|
||||
continue
|
||||
}
|
||||
var lastv int
|
||||
if store == lapack.ColumnWise {
|
||||
// skip trailing zeros
|
||||
for lastv = n - 1; lastv >= i+1; lastv-- {
|
||||
if v[lastv*ldv+i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
t[j*ldt+i] = -tau[i] * v[i*ldv+j]
|
||||
}
|
||||
j := min(lastv, prevlastv)
|
||||
bi.Dgemv(blas.Trans, j-i, i,
|
||||
-tau[i], v[(i+1)*ldv:], ldv, v[(i+1)*ldv+i:], ldv,
|
||||
1, t[i:], ldt)
|
||||
} else {
|
||||
for lastv = n - 1; lastv >= i+1; lastv-- {
|
||||
if v[i*ldv+lastv] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
for j := 0; j < i; j++ {
|
||||
t[j*ldt+i] = -tau[i] * v[j*ldv+i]
|
||||
}
|
||||
j := min(lastv, prevlastv)
|
||||
bi.Dgemv(blas.NoTrans, i, j-i,
|
||||
-tau[i], v[i+1:], ldv, v[i*ldv+i+1:], 1,
|
||||
1, t[i:], ldt)
|
||||
}
|
||||
bi.Dtrmv(blas.Upper, blas.NoTrans, blas.NonUnit, i, t, ldt, t[i:], ldt)
|
||||
t[i*ldt+i] = tau[i]
|
||||
if i > 1 {
|
||||
prevlastv = max(prevlastv, lastv)
|
||||
} else {
|
||||
prevlastv = lastv
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
prevlastv := 0
|
||||
for i := k - 1; i >= 0; i-- {
|
||||
if tau[i] == 0 {
|
||||
for j := i; j < k; j++ {
|
||||
t[j*ldt+i] = 0
|
||||
}
|
||||
continue
|
||||
}
|
||||
var lastv int
|
||||
if i < k-1 {
|
||||
if store == lapack.ColumnWise {
|
||||
for lastv = 0; lastv < i; lastv++ {
|
||||
if v[lastv*ldv+i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
for j := i + 1; j < k; j++ {
|
||||
t[j*ldt+i] = -tau[i] * v[(n-k+i)*ldv+j]
|
||||
}
|
||||
j := max(lastv, prevlastv)
|
||||
bi.Dgemv(blas.Trans, n-k+i-j, k-i-1,
|
||||
-tau[i], v[j*ldv+i+1:], ldv, v[j*ldv+i:], ldv,
|
||||
1, t[(i+1)*ldt+i:], ldt)
|
||||
} else {
|
||||
for lastv := 0; lastv < i; lastv++ {
|
||||
if v[i*ldv+lastv] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
for j := i + 1; j < k; j++ {
|
||||
t[j*ldt+i] = -tau[i] * v[j*ldv+n-k+i]
|
||||
}
|
||||
j := max(lastv, prevlastv)
|
||||
bi.Dgemv(blas.NoTrans, k-i-1, n-k+i-j,
|
||||
-tau[i], v[(i+1)*ldv+j:], ldv, v[i*ldv+j:], 1,
|
||||
1, t[(i+1)*ldt+i:], ldt)
|
||||
}
|
||||
bi.Dtrmv(blas.Lower, blas.NoTrans, blas.NonUnit, k-i-1,
|
||||
t[(i+1)*ldt+i+1:], ldt,
|
||||
t[(i+1)*ldt+i:], ldt)
|
||||
if i > 0 {
|
||||
prevlastv = min(prevlastv, lastv)
|
||||
} else {
|
||||
prevlastv = lastv
|
||||
}
|
||||
}
|
||||
t[i*ldt+i] = tau[i]
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gonum/lapack"
|
||||
)
|
||||
|
||||
// Dlascl multiplies a rectangular matrix by a scalar.
|
||||
func (impl Implementation) Dlascl(kind lapack.MatrixType, kl, ku int, cfrom, cto float64, m, n int, a []float64, lda int) {
|
||||
checkMatrix(m, n, a, lda)
|
||||
if cfrom == 0 {
|
||||
panic("dlascl: zero divisor")
|
||||
}
|
||||
if math.IsNaN(cfrom) || math.IsNaN(cto) {
|
||||
panic("dlascl: NaN scale factor")
|
||||
}
|
||||
if n == 0 || m == 0 {
|
||||
return
|
||||
}
|
||||
smlnum := dlamchS
|
||||
bignum := 1 / smlnum
|
||||
cfromc := cfrom
|
||||
ctoc := cto
|
||||
cfrom1 := cfromc * smlnum
|
||||
for {
|
||||
var done bool
|
||||
var mul, ctol float64
|
||||
if cfrom1 == cfromc {
|
||||
// cfromc is inf
|
||||
mul = ctoc / cfromc
|
||||
done = true
|
||||
ctol = ctoc
|
||||
} else {
|
||||
ctol = ctoc / bignum
|
||||
if ctol == ctoc {
|
||||
// ctoc is either 0 or inf.
|
||||
mul = ctoc
|
||||
done = true
|
||||
cfromc = 1
|
||||
} else if math.Abs(cfrom1) > math.Abs(ctoc) && ctoc != 0 {
|
||||
mul = smlnum
|
||||
done = false
|
||||
cfromc = cfrom1
|
||||
} else if math.Abs(ctol) > math.Abs(cfromc) {
|
||||
mul = bignum
|
||||
done = false
|
||||
ctoc = ctol
|
||||
} else {
|
||||
mul = ctoc / cfromc
|
||||
done = true
|
||||
}
|
||||
}
|
||||
switch kind {
|
||||
default:
|
||||
panic("lapack: not implemented")
|
||||
case lapack.General:
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < n; j++ {
|
||||
a[i*lda+j] = a[i*lda+j] * mul
|
||||
}
|
||||
}
|
||||
}
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// 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 native
|
||||
|
||||
import "github.com/gonum/blas"
|
||||
|
||||
// Dlaset sets the off-diagonal elements of a to alpha, and the diagonal elements
|
||||
// of a to beta. If uplo == blas.Upper, only the upper diagonal elements are set.
|
||||
// If uplo == blas.Lower, only the lower diagonal elements are set. If uplo is
|
||||
// otherwise, all of the elements of a are set.
|
||||
func (impl Implementation) Dlaset(uplo blas.Uplo, m, n int, alpha, beta float64, a []float64, lda int) {
|
||||
checkMatrix(m, n, a, lda)
|
||||
if uplo == blas.Upper {
|
||||
for i := 0; i < m; i++ {
|
||||
for j := i + 1; j < n; j++ {
|
||||
a[i*lda+j] = alpha
|
||||
}
|
||||
}
|
||||
} else if uplo == blas.Lower {
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < i; j++ {
|
||||
a[i*lda+j] = alpha
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < m; i++ {
|
||||
for j := 0; j < n; j++ {
|
||||
a[i*lda+j] = alpha
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := 0; i < min(m, n); i++ {
|
||||
a[i*lda+i] = beta
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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 native
|
||||
|
||||
import "math"
|
||||
|
||||
// Dlassq updates a sum of squares in scaled form. The input parameters scale and
|
||||
// sumsq represent the current scale and total sum of squares. These values are
|
||||
// updated with the information in the first n elements of the vector specified
|
||||
// by x and incX.
|
||||
func (impl Implementation) Dlassq(n int, x []float64, incx int, scale float64, sumsq float64) (scl, smsq float64) {
|
||||
if n <= 0 {
|
||||
return scale, sumsq
|
||||
}
|
||||
for ix := 0; ix <= (n-1)*incx; ix += incx {
|
||||
absxi := math.Abs(x[ix])
|
||||
if absxi > 0 || math.IsNaN(absxi) {
|
||||
if scale < absxi {
|
||||
sumsq = 1 + sumsq*(scale/absxi)*(scale/absxi)
|
||||
scale = absxi
|
||||
} else {
|
||||
sumsq += (absxi / scale) * (absxi / scale)
|
||||
}
|
||||
}
|
||||
}
|
||||
return scale, sumsq
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// 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 native is a pure-go implementation of the LAPACK API. The LAPACK API defines
|
||||
// a set of algorithms for advanced matrix operations.
|
||||
//
|
||||
// The function definitions and implementations follow that of the netlib reference
|
||||
// implementation. Please see http://www.netlib.org/lapack/explore-html/ for more
|
||||
// information, and http://www.netlib.org/lapack/explore-html/d4/de1/_l_i_c_e_n_s_e_source.html
|
||||
// for more license information.
|
||||
//
|
||||
// Slice function arguments frequently represent vectors and matrices. The data
|
||||
// layout is identical to that found in https://godoc.org/github.com/gonum/blas/native.
|
||||
//
|
||||
// Most LAPACK functions are built on top the routines defined in the BLAS API,
|
||||
// and as such the computation time for many LAPACK functions is
|
||||
// dominated by BLAS calls. Here, BLAS is accessed through the
|
||||
// the blas64 package (https://godoc.org/github.com/gonum/blas/blas64). In particular,
|
||||
// this implies that an external BLAS library will be used if it is
|
||||
// registered in blas64.
|
||||
//
|
||||
// The full LAPACK capability has not been implemented at present. The full
|
||||
// API is very large, containing approximately 200 functions for double precision
|
||||
// alone. Future additions will be focused on supporting the gonum matrix
|
||||
// package (https://godoc.org/github.com/gonum/matrix/mat64), though pull requests
|
||||
// with implementations and tests for LAPACK function are encouraged.
|
||||
package native
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
// 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 native
|
||||
|
||||
import "github.com/gonum/blas"
|
||||
|
||||
// Dorm2r multiplies a general matrix c by an orthogonal matrix from a QR factorization
|
||||
// determined by Dgeqrf.
|
||||
// C = Q * C if side == blas.Left and trans == blas.NoTrans
|
||||
// C = Q^T * C if side == blas.Left and trans == blas.Trans
|
||||
// C = C * Q if side == blas.Right and trans == blas.NoTrans
|
||||
// C = C * Q^T if side == blas.Right and trans == blas.Trans
|
||||
// If side == blas.Left, a is a matrix of size m×k, and if side == blas.Right
|
||||
// a is of size n×k.
|
||||
//
|
||||
// Tau contains the householder factors and is of length at least k and this function
|
||||
// will panic otherwise.
|
||||
//
|
||||
// Work is temporary storage of length at least n if side == blas.Left
|
||||
// and at least m if side == blas.Right and this function will panic otherwise.
|
||||
func (impl Implementation) Dorm2r(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64) {
|
||||
if side != blas.Left && side != blas.Right {
|
||||
panic(badSide)
|
||||
}
|
||||
if trans != blas.Trans && trans != blas.NoTrans {
|
||||
panic(badTrans)
|
||||
}
|
||||
|
||||
left := side == blas.Left
|
||||
notran := trans == blas.NoTrans
|
||||
if left {
|
||||
// Q is m x m
|
||||
checkMatrix(m, k, a, lda)
|
||||
if len(work) < n {
|
||||
panic(badWork)
|
||||
}
|
||||
} else {
|
||||
// Q is n x n
|
||||
checkMatrix(n, k, a, lda)
|
||||
if len(work) < m {
|
||||
panic(badWork)
|
||||
}
|
||||
}
|
||||
checkMatrix(m, n, c, ldc)
|
||||
if m == 0 || n == 0 || k == 0 {
|
||||
return
|
||||
}
|
||||
if len(tau) < k {
|
||||
panic(badTau)
|
||||
}
|
||||
if left {
|
||||
if notran {
|
||||
for i := k - 1; i >= 0; i-- {
|
||||
aii := a[i*lda+i]
|
||||
a[i*lda+i] = 1
|
||||
impl.Dlarf(side, m-i, n, a[i*lda+i:], lda, tau[i], c[i*ldc:], ldc, work)
|
||||
a[i*lda+i] = aii
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < k; i++ {
|
||||
aii := a[i*lda+i]
|
||||
a[i*lda+i] = 1
|
||||
impl.Dlarf(side, m-i, n, a[i*lda+i:], lda, tau[i], c[i*ldc:], ldc, work)
|
||||
a[i*lda+i] = aii
|
||||
}
|
||||
return
|
||||
}
|
||||
if notran {
|
||||
for i := 0; i < k; i++ {
|
||||
aii := a[i*lda+i]
|
||||
a[i*lda+i] = 1
|
||||
impl.Dlarf(side, m, n-i, a[i*lda+i:], lda, tau[i], c[i:], ldc, work)
|
||||
a[i*lda+i] = aii
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := k - 1; i >= 0; i-- {
|
||||
aii := a[i*lda+i]
|
||||
a[i*lda+i] = 1
|
||||
impl.Dlarf(side, m, n-i, a[i*lda+i:], lda, tau[i], c[i:], ldc, work)
|
||||
a[i*lda+i] = aii
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
// 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 native
|
||||
|
||||
import "github.com/gonum/blas"
|
||||
|
||||
// Dorml2 multiplies a general matrix c by an orthogonal matrix from an LQ factorization
|
||||
// determined by Dgelqf.
|
||||
// C = Q * C if side == blas.Left and trans == blas.NoTrans
|
||||
// C = Q^T * C if side == blas.Left and trans == blas.Trans
|
||||
// C = C * Q if side == blas.Right and trans == blas.NoTrans
|
||||
// C = C * Q^T if side == blas.Right and trans == blas.Trans
|
||||
// If side == blas.Left, a is a matrix of side k×m, and if side == blas.Right
|
||||
// a is of size k×n.
|
||||
//
|
||||
//
|
||||
// Tau contains the householder factors and is of length at least k and this function will
|
||||
// panic otherwise.
|
||||
//
|
||||
// Work is temporary storage of length at least n if side == blas.Left
|
||||
// and at least m if side == blas.Right and this function will panic otherwise.
|
||||
func (impl Implementation) Dorml2(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64) {
|
||||
if side != blas.Left && side != blas.Right {
|
||||
panic(badSide)
|
||||
}
|
||||
if trans != blas.Trans && trans != blas.NoTrans {
|
||||
panic(badTrans)
|
||||
}
|
||||
|
||||
left := side == blas.Left
|
||||
notran := trans == blas.NoTrans
|
||||
if left {
|
||||
checkMatrix(k, m, a, lda)
|
||||
if len(work) < n {
|
||||
panic(badWork)
|
||||
}
|
||||
} else {
|
||||
checkMatrix(k, n, a, lda)
|
||||
if len(work) < m {
|
||||
panic(badWork)
|
||||
}
|
||||
}
|
||||
checkMatrix(m, n, c, ldc)
|
||||
if m == 0 || n == 0 || k == 0 {
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case left && notran:
|
||||
for i := 0; i < k; i++ {
|
||||
aii := a[i*lda+i]
|
||||
a[i*lda+i] = 1
|
||||
impl.Dlarf(side, m-i, n, a[i*lda+i:], 1, tau[i], c[i*ldc:], ldc, work)
|
||||
a[i*lda+i] = aii
|
||||
}
|
||||
return
|
||||
case left && !notran:
|
||||
for i := k - 1; i >= 0; i-- {
|
||||
aii := a[i*lda+i]
|
||||
a[i*lda+i] = 1
|
||||
impl.Dlarf(side, m-i, n, a[i*lda+i:], 1, tau[i], c[i*ldc:], ldc, work)
|
||||
a[i*lda+i] = aii
|
||||
}
|
||||
return
|
||||
case !left && notran:
|
||||
for i := k - 1; i >= 0; i-- {
|
||||
aii := a[i*lda+i]
|
||||
a[i*lda+i] = 1
|
||||
impl.Dlarf(side, m, n-i, a[i*lda+i:], 1, tau[i], c[i:], ldc, work)
|
||||
a[i*lda+i] = aii
|
||||
}
|
||||
return
|
||||
case !left && !notran:
|
||||
for i := 0; i < k; i++ {
|
||||
aii := a[i*lda+i]
|
||||
a[i*lda+i] = 1
|
||||
impl.Dlarf(side, m, n-i, a[i*lda+i:], 1, tau[i], c[i:], ldc, work)
|
||||
a[i*lda+i] = aii
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/lapack"
|
||||
)
|
||||
|
||||
// Dormlq multiplies the matrix c by the othogonal matrix q defined by the
|
||||
// slices a and tau. A and tau are as returned from Dgelqf.
|
||||
// C = Q * C if side == blas.Left and trans == blas.NoTrans
|
||||
// C = Q^T * C if side == blas.Left and trans == blas.Trans
|
||||
// C = C * Q if side == blas.Right and trans == blas.NoTrans
|
||||
// C = C * Q^T if side == blas.Right and trans == blas.Trans
|
||||
// If side == blas.Left, a is a matrix of side k×m, and if side == blas.Right
|
||||
// a is of size k×n. This uses a blocked algorithm.
|
||||
//
|
||||
// Work is temporary storage, and lwork specifies the usable memory length.
|
||||
// At minimum, lwork >= m if side == blas.Left and lwork >= n if side == blas.Right,
|
||||
// and this function will panic otherwise.
|
||||
// Dormlq uses a block algorithm, but the block size is limited
|
||||
// by the temporary space available. If lwork == -1, instead of performing Dormlq,
|
||||
// the optimal work length will be stored into work[0].
|
||||
//
|
||||
// Tau contains the householder scales and must have length at least k, and
|
||||
// this function will panic otherwise.
|
||||
func (impl Implementation) Dormlq(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) {
|
||||
if side != blas.Left && side != blas.Right {
|
||||
panic(badSide)
|
||||
}
|
||||
if trans != blas.Trans && trans != blas.NoTrans {
|
||||
panic(badTrans)
|
||||
}
|
||||
left := side == blas.Left
|
||||
notran := trans == blas.NoTrans
|
||||
if left {
|
||||
checkMatrix(k, m, a, lda)
|
||||
} else {
|
||||
checkMatrix(k, n, a, lda)
|
||||
}
|
||||
checkMatrix(m, n, c, ldc)
|
||||
if len(tau) < k {
|
||||
panic(badTau)
|
||||
}
|
||||
|
||||
const nbmax = 64
|
||||
nw := n
|
||||
if !left {
|
||||
nw = m
|
||||
}
|
||||
opts := string(side) + string(trans)
|
||||
nb := min(nbmax, impl.Ilaenv(1, "DORMLQ", opts, m, n, k, -1))
|
||||
lworkopt := max(1, nw) * nb
|
||||
if lwork == -1 {
|
||||
work[0] = float64(lworkopt)
|
||||
return
|
||||
}
|
||||
if left {
|
||||
if lwork < n {
|
||||
panic(badWork)
|
||||
}
|
||||
} else {
|
||||
if lwork < m {
|
||||
panic(badWork)
|
||||
}
|
||||
}
|
||||
|
||||
if m == 0 || n == 0 || k == 0 {
|
||||
return
|
||||
}
|
||||
nbmin := 2
|
||||
|
||||
ldwork := nb
|
||||
if nb > 1 && nb < k {
|
||||
iws := nw * nb
|
||||
if lwork < iws {
|
||||
nb = lwork / nw
|
||||
nbmin = max(2, impl.Ilaenv(2, "DORMLQ", opts, m, n, k, -1))
|
||||
}
|
||||
}
|
||||
if nb < nbmin || nb >= k {
|
||||
// Call unblocked code
|
||||
impl.Dorml2(side, trans, m, n, k, a, lda, tau, c, ldc, work)
|
||||
return
|
||||
}
|
||||
ldt := nb
|
||||
t := make([]float64, nb*ldt)
|
||||
|
||||
transt := blas.NoTrans
|
||||
if notran {
|
||||
transt = blas.Trans
|
||||
}
|
||||
|
||||
switch {
|
||||
case left && notran:
|
||||
for i := 0; i < k; i += nb {
|
||||
ib := min(nb, k-i)
|
||||
impl.Dlarft(lapack.Forward, lapack.RowWise, m-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i:],
|
||||
t, ldt)
|
||||
impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m-i, n, ib,
|
||||
a[i*lda+i:], lda,
|
||||
t, ldt,
|
||||
c[i*ldc:], ldc,
|
||||
work, ldwork)
|
||||
}
|
||||
return
|
||||
case left && !notran:
|
||||
for i := ((k - 1) / nb) * nb; i >= 0; i -= nb {
|
||||
ib := min(nb, k-i)
|
||||
impl.Dlarft(lapack.Forward, lapack.RowWise, m-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i:],
|
||||
t, ldt)
|
||||
impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m-i, n, ib,
|
||||
a[i*lda+i:], lda,
|
||||
t, ldt,
|
||||
c[i*ldc:], ldc,
|
||||
work, ldwork)
|
||||
}
|
||||
return
|
||||
case !left && notran:
|
||||
for i := ((k - 1) / nb) * nb; i >= 0; i -= nb {
|
||||
ib := min(nb, k-i)
|
||||
impl.Dlarft(lapack.Forward, lapack.RowWise, n-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i:],
|
||||
t, ldt)
|
||||
impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m, n-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
t, ldt,
|
||||
c[i:], ldc,
|
||||
work, ldwork)
|
||||
}
|
||||
return
|
||||
case !left && !notran:
|
||||
for i := 0; i < k; i += nb {
|
||||
ib := min(nb, k-i)
|
||||
impl.Dlarft(lapack.Forward, lapack.RowWise, n-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i:],
|
||||
t, ldt)
|
||||
impl.Dlarfb(side, transt, lapack.Forward, lapack.RowWise, m, n-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
t, ldt,
|
||||
c[i:], ldc,
|
||||
work, ldwork)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/lapack"
|
||||
)
|
||||
|
||||
// Dormqr multiplies the matrix c by the othogonal matrix q defined by the
|
||||
// slices a and tau. A and tau are as returned from Dgeqrf.
|
||||
// C = Q * C if side == blas.Left and trans == blas.NoTrans
|
||||
// C = Q^T * C if side == blas.Left and trans == blas.Trans
|
||||
// C = C * Q if side == blas.Right and trans == blas.NoTrans
|
||||
// C = C * Q^T if side == blas.Right and trans == blas.Trans
|
||||
// If side == blas.Left, a is a matrix of side k×m, and if side == blas.Right
|
||||
// a is of size k×n. This uses a blocked algorithm.
|
||||
//
|
||||
// Work is temporary storage, and lwork specifies the usable memory length.
|
||||
// At minimum, lwork >= m if side == blas.Left and lwork >= n if side == blas.Right,
|
||||
// and this function will panic otherwise.
|
||||
// Dormqr uses a block algorithm, but the block size is limited
|
||||
// by the temporary space available. If lwork == -1, instead of performing Dormqr,
|
||||
// the optimal work length will be stored into work[0].
|
||||
//
|
||||
// Tau contains the householder scales and must have length at least k, and
|
||||
// this function will panic otherwise.
|
||||
func (impl Implementation) Dormqr(side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) {
|
||||
left := side == blas.Left
|
||||
notran := trans == blas.NoTrans
|
||||
if left {
|
||||
checkMatrix(m, k, a, lda)
|
||||
} else {
|
||||
checkMatrix(n, k, a, lda)
|
||||
}
|
||||
checkMatrix(m, n, c, ldc)
|
||||
|
||||
const nbmax = 64
|
||||
nw := n
|
||||
if side == blas.Right {
|
||||
nw = m
|
||||
}
|
||||
opts := string(side) + string(trans)
|
||||
nb := min(nbmax, impl.Ilaenv(1, "DORMQR", opts, m, n, k, -1))
|
||||
lworkopt := max(1, nw) * nb
|
||||
if lwork == -1 {
|
||||
work[0] = float64(lworkopt)
|
||||
return
|
||||
}
|
||||
if left {
|
||||
if lwork < n {
|
||||
panic(badWork)
|
||||
}
|
||||
} else {
|
||||
if lwork < m {
|
||||
panic(badWork)
|
||||
}
|
||||
}
|
||||
if m == 0 || n == 0 || k == 0 {
|
||||
return
|
||||
}
|
||||
nbmin := 2
|
||||
|
||||
ldwork := nb
|
||||
if nb > 1 && nb < k {
|
||||
iws := nw * nb
|
||||
if lwork < iws {
|
||||
nb = lwork / nw
|
||||
nbmin = max(2, impl.Ilaenv(2, "DORMQR", opts, m, n, k, -1))
|
||||
}
|
||||
}
|
||||
if nb < nbmin || nb >= k {
|
||||
// Call unblocked code
|
||||
impl.Dorm2r(side, trans, m, n, k, a, lda, tau, c, ldc, work)
|
||||
return
|
||||
}
|
||||
ldt := nb
|
||||
t := make([]float64, nb*ldt)
|
||||
switch {
|
||||
case left && notran:
|
||||
for i := ((k - 1) / nb) * nb; i >= 0; i -= nb {
|
||||
ib := min(nb, k-i)
|
||||
impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i:],
|
||||
t, ldt)
|
||||
impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m-i, n, ib,
|
||||
a[i*lda+i:], lda,
|
||||
t, ldt,
|
||||
c[i*ldc:], ldc,
|
||||
work, ldwork)
|
||||
}
|
||||
return
|
||||
case left && !notran:
|
||||
for i := 0; i < k; i += nb {
|
||||
ib := min(nb, k-i)
|
||||
impl.Dlarft(lapack.Forward, lapack.ColumnWise, m-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i:],
|
||||
t, ldt)
|
||||
impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m-i, n, ib,
|
||||
a[i*lda+i:], lda,
|
||||
t, ldt,
|
||||
c[i*ldc:], ldc,
|
||||
work, ldwork)
|
||||
}
|
||||
return
|
||||
case !left && notran:
|
||||
for i := 0; i < k; i += nb {
|
||||
ib := min(nb, k-i)
|
||||
impl.Dlarft(lapack.Forward, lapack.ColumnWise, n-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i:],
|
||||
t, ldt)
|
||||
impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m, n-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
t, ldt,
|
||||
c[i:], ldc,
|
||||
work, ldwork)
|
||||
}
|
||||
return
|
||||
case !left && !notran:
|
||||
for i := ((k - 1) / nb) * nb; i >= 0; i -= nb {
|
||||
ib := min(nb, k-i)
|
||||
impl.Dlarft(lapack.Forward, lapack.ColumnWise, n-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
tau[i:],
|
||||
t, ldt)
|
||||
impl.Dlarfb(side, trans, lapack.Forward, lapack.ColumnWise, m, n-i, ib,
|
||||
a[i*lda+i:], lda,
|
||||
t, ldt,
|
||||
c[i:], ldc,
|
||||
work, ldwork)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
// 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 native
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gonum/blas"
|
||||
"github.com/gonum/blas/blas64"
|
||||
)
|
||||
|
||||
// Dpotf2 computes the cholesky decomposition of the symmetric positive definite
|
||||
// matrix a. If ul == blas.Upper, then a is stored as an upper-triangular matrix,
|
||||
// and a = U^T U is stored in place into a. If ul == blas.Lower, then a = L L^T
|
||||
// is computed and stored in-place into a. If a is not positive definite, false
|
||||
// is returned. This is the unblocked version of the algorithm.
|
||||
func (Implementation) Dpotf2(ul blas.Uplo, n int, a []float64, lda int) (ok bool) {
|
||||
if ul != blas.Upper && ul != blas.Lower {
|
||||
panic(badUplo)
|
||||
}
|
||||
if n < 0 {
|
||||
panic(nLT0)
|
||||
}
|
||||
if lda < n {
|
||||
panic(badLdA)
|
||||
}
|
||||
if n == 0 {
|
||||
return true
|
||||
}
|
||||
bi := blas64.Implementation()
|
||||
if ul == blas.Upper {
|
||||
for j := 0; j < n; j++ {
|
||||
ajj := a[j*lda+j]
|
||||
if j != 0 {
|
||||
ajj -= bi.Ddot(j, a[j:], lda, a[j:], lda)
|
||||
}
|
||||
if ajj <= 0 || math.IsNaN(ajj) {
|
||||
a[j*lda+j] = ajj
|
||||
return false
|
||||
}
|
||||
ajj = math.Sqrt(ajj)
|
||||
a[j*lda+j] = ajj
|
||||
if j < n-1 {
|
||||
bi.Dgemv(blas.Trans, j, n-j-1,
|
||||
-1, a[j+1:], lda, a[j:], lda,
|
||||
1, a[j*lda+j+1:], 1)
|
||||
bi.Dscal(n-j-1, 1/ajj, a[j*lda+j+1:], 1)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
for j := 0; j < n; j++ {
|
||||
ajj := a[j*lda+j]
|
||||
if j != 0 {
|
||||
ajj -= bi.Ddot(j, a[j*lda:], 1, a[j*lda:], 1)
|
||||
}
|
||||
if ajj <= 0 || math.IsNaN(ajj) {
|
||||
a[j*lda+j] = ajj
|
||||
return false
|
||||
}
|
||||
ajj = math.Sqrt(ajj)
|
||||
a[j*lda+j] = ajj
|
||||
if j < n-1 {
|
||||
bi.Dgemv(blas.NoTrans, n-j-1, j,
|
||||
-1, a[(j+1)*lda:], lda, a[j*lda:], 1,
|
||||
1, a[(j+1)*lda+j:], lda)
|
||||
bi.Dscal(n-j-1, 1/ajj, a[(j+1)*lda+j:], lda)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user