Merge pull request #112692 from liggitt/dot-cleanup

Drop DOT dependency
This commit is contained in:
Kubernetes Prow Robot 2022-09-23 13:02:06 -07:00 committed by GitHub
commit ed8c302cc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
358 changed files with 426 additions and 83779 deletions

View File

@ -1,26 +0,0 @@
= vendor/gonum.org/v1/gonum licensed under: =
Copyright ©2013 The Gonum 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 the gonum project nor the names of its authors and
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 HOLDER 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.
= vendor/gonum.org/v1/gonum/LICENSE 665e67d07d85e236cceb8de602c6255a

23
go.mod
View File

@ -86,7 +86,6 @@ require (
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8
golang.org/x/tools v0.1.12
gonum.org/v1/gonum v0.6.2
google.golang.org/api v0.60.0
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21
google.golang.org/grpc v1.49.0
@ -235,10 +234,8 @@ require (
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/exp v0.0.0-20210220032938-85be41e4509f // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/text v0.3.7 // indirect
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e // indirect
google.golang.org/appengine v1.6.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
@ -256,7 +253,6 @@ replace (
cloud.google.com/go => cloud.google.com/go v0.97.0
cloud.google.com/go/bigquery => cloud.google.com/go/bigquery v1.8.0
cloud.google.com/go/storage => cloud.google.com/go/storage v1.10.0
dmitri.shuralyov.com/gpu/mtl => dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037
github.com/Azure/azure-sdk-for-go => github.com/Azure/azure-sdk-for-go v55.0.0+incompatible
github.com/Azure/go-ansiterm => github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1
github.com/Azure/go-autorest => github.com/Azure/go-autorest v14.2.0+incompatible
@ -269,7 +265,6 @@ replace (
github.com/Azure/go-autorest/logger => github.com/Azure/go-autorest/logger v0.2.1
github.com/Azure/go-autorest/tracing => github.com/Azure/go-autorest/tracing v0.6.0
github.com/BurntSushi/toml => github.com/BurntSushi/toml v0.3.1
github.com/BurntSushi/xgb => github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802
github.com/GoogleCloudPlatform/k8s-cloud-provider => github.com/GoogleCloudPlatform/k8s-cloud-provider v1.18.1-0.20220218231025-f11817397a1b
github.com/JeffAshton/win_pdh => github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab
github.com/MakeNowJust/heredoc => github.com/MakeNowJust/heredoc v1.0.0
@ -278,7 +273,6 @@ replace (
github.com/NYTimes/gziphandler => github.com/NYTimes/gziphandler v1.1.1
github.com/PuerkitoBio/purell => github.com/PuerkitoBio/purell v1.1.1
github.com/PuerkitoBio/urlesc => github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578
github.com/ajstarks/svgo => github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af
github.com/antihax/optional => github.com/antihax/optional v1.0.0
github.com/antlr/antlr4/runtime/Go/antlr => github.com/antlr/antlr4/runtime/Go/antlr v1.4.10
github.com/armon/circbuf => github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e
@ -340,7 +334,6 @@ replace (
github.com/fatih/camelcase => github.com/fatih/camelcase v1.0.0
github.com/felixge/httpsnoop => github.com/felixge/httpsnoop v1.0.3
github.com/flynn/go-shlex => github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
github.com/fogleman/gg => github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90
github.com/form3tech-oss/jwt-go => github.com/form3tech-oss/jwt-go v3.2.3+incompatible
github.com/frankban/quicktest => github.com/frankban/quicktest v1.11.3
github.com/fsnotify/fsnotify => github.com/fsnotify/fsnotify v1.5.4
@ -349,7 +342,6 @@ replace (
github.com/getsentry/raven-go => github.com/getsentry/raven-go v0.2.0
github.com/ghodss/yaml => github.com/ghodss/yaml v1.0.0
github.com/go-errors/errors => github.com/go-errors/errors v1.0.1
github.com/go-gl/glfw/v3.3/glfw => github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4
github.com/go-kit/kit => github.com/go-kit/kit v0.9.0
github.com/go-kit/log => github.com/go-kit/log v0.2.0
github.com/go-logfmt/logfmt => github.com/go-logfmt/logfmt v0.5.1
@ -366,7 +358,6 @@ replace (
github.com/gogo/googleapis => github.com/gogo/googleapis v1.4.1
github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2
github.com/golang-jwt/jwt/v4 => github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang/freetype => github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/golang/glog => github.com/golang/glog v1.0.0
github.com/golang/groupcache => github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
github.com/golang/mock => github.com/golang/mock v1.6.0
@ -404,7 +395,6 @@ replace (
github.com/jpillora/backoff => github.com/jpillora/backoff v1.0.0
github.com/json-iterator/go => github.com/json-iterator/go v1.1.12
github.com/julienschmidt/httprouter => github.com/julienschmidt/httprouter v1.3.0
github.com/jung-kurt/gofpdf => github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5
github.com/karrick/godirwalk => github.com/karrick/godirwalk v1.16.1
github.com/kisielk/errcheck => github.com/kisielk/errcheck v1.5.0
github.com/kisielk/gotool => github.com/kisielk/gotool v1.0.0
@ -453,7 +443,6 @@ replace (
github.com/prometheus/client_model => github.com/prometheus/client_model v0.2.0
github.com/prometheus/common => github.com/prometheus/common v0.37.0
github.com/prometheus/procfs => github.com/prometheus/procfs v0.8.0
github.com/remyoudompheng/bigfft => github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446
github.com/robfig/cron/v3 => github.com/robfig/cron/v3 v3.0.1
github.com/rogpeppe/fastuuid => github.com/rogpeppe/fastuuid v1.2.0
github.com/rogpeppe/go-internal => github.com/rogpeppe/go-internal v1.3.0
@ -505,10 +494,7 @@ replace (
go.uber.org/multierr => go.uber.org/multierr v1.6.0
go.uber.org/zap => go.uber.org/zap v1.19.0
golang.org/x/crypto => golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
golang.org/x/exp => golang.org/x/exp v0.0.0-20210220032938-85be41e4509f
golang.org/x/image => golang.org/x/image v0.0.0-20190802002840-cff245a6509b
golang.org/x/lint => golang.org/x/lint v0.0.0-20190930215403-16217165b5de
golang.org/x/mobile => golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f
golang.org/x/mod => golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/net => golang.org/x/net v0.0.0-20220722155237-a158d28d115b
golang.org/x/oauth2 => golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
@ -519,9 +505,6 @@ replace (
golang.org/x/time => golang.org/x/time v0.0.0-20220210224613-90d013bbcef8
golang.org/x/tools => golang.org/x/tools v0.1.12
golang.org/x/xerrors => golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
gonum.org/v1/gonum => gonum.org/v1/gonum v0.6.2
gonum.org/v1/netlib => gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e
gonum.org/v1/plot => gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b
google.golang.org/api => google.golang.org/api v0.60.0
google.golang.org/appengine => google.golang.org/appengine v1.6.7
google.golang.org/genproto => google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21
@ -572,12 +555,6 @@ replace (
k8s.io/sample-controller => ./staging/src/k8s.io/sample-controller
k8s.io/system-validators => k8s.io/system-validators v1.8.0
k8s.io/utils => k8s.io/utils v0.0.0-20220922133306-665eaaec4324
modernc.org/cc => modernc.org/cc v1.0.0
modernc.org/golex => modernc.org/golex v1.0.0
modernc.org/mathutil => modernc.org/mathutil v1.0.0
modernc.org/strutil => modernc.org/strutil v1.0.0
modernc.org/xc => modernc.org/xc v1.0.0
rsc.io/pdf => rsc.io/pdf v0.1.1
sigs.k8s.io/apiserver-network-proxy/konnectivity-client => sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.32
sigs.k8s.io/json => sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2
sigs.k8s.io/kustomize/api => sigs.k8s.io/kustomize/api v0.12.1

23
go.sum
View File

@ -5,7 +5,6 @@ cloud.google.com/go v0.97.0 h1:3DXvAyifywvq64LfkKaMOmkWPS1CikIQdMe2lY9vxU8=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go v55.0.0+incompatible h1:L4/vUGbg1Xkw5L20LZD+hJI5I+ibWSytqQ68lTCfLwY=
github.com/Azure/azure-sdk-for-go v55.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
@ -30,7 +29,6 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/GoogleCloudPlatform/k8s-cloud-provider v1.18.1-0.20220218231025-f11817397a1b h1:Heo1J/ttaQFgGJSVnCZquy3e5eH5j1nqxBuomztB3P0=
github.com/GoogleCloudPlatform/k8s-cloud-provider v1.18.1-0.20220218231025-f11817397a1b/go.mod h1:FNj4KYEAAHfYu68kRYolGoxkaJn+6mdEsaM12VTwuI0=
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab h1:UKkYhof1njT1/xq4SEg5z+VpTgjmNeHwPGRQl7takDI=
@ -43,7 +41,6 @@ github.com/Microsoft/hcsshim v0.8.22 h1:CulZ3GW8sNJExknToo+RWD+U+6ZM5kkNfuxywSDP
github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
@ -150,7 +147,6 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
@ -164,7 +160,6 @@ github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49P
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
@ -192,7 +187,6 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
@ -259,7 +253,6 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@ -346,7 +339,6 @@ github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@ -443,11 +435,7 @@ go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE=
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20210220032938-85be41e4509f h1:GrkO5AtFUU9U/1f5ctbIBXtBGeSJbWwIYfIsTcFMaX4=
golang.org/x/exp v0.0.0-20210220032938-85be41e4509f/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
@ -467,11 +455,6 @@ golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.6.2 h1:4r+yNT0+8SWcOkXP+63H2zQbN+USnC73cjGUxnDF94Q=
gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e h1:jRyg0XfpwWlhEV8mDfdNGBeSJM2fuyh9Yjrnd8kF2Ts=
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
google.golang.org/api v0.60.0 h1:eq/zs5WPH4J9undYM9IP1O7dSr7Yh8Y0GtSCpzGzIUk=
google.golang.org/api v0.60.0/go.mod h1:d7rl65NZAkEQ90JFzqBjcRq1TVeG5ZoGV3sSpEnnVb4=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
@ -514,12 +497,6 @@ k8s.io/system-validators v1.8.0 h1:tq05tdO9zdJZnNF3SXrq6LE7Knc/KfJm5wk68467JDg=
k8s.io/system-validators v1.8.0/go.mod h1:gP1Ky+R9wtrSiFbrpEPwWMeYz9yqyy1S/KOh0Vci7WI=
k8s.io/utils v0.0.0-20220922133306-665eaaec4324 h1:i+xdFemcSNuJvIfBlaYuXgRondKxK4z4prVPKzEaelI=
k8s.io/utils v0.0.0-20220922133306-665eaaec4324/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.32 h1:2WjukG7txtEsbXsSKWtTibCdsyYAhcu6KFnttyDdZOQ=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.32/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw=
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=

View File

@ -17,22 +17,20 @@ limitations under the License.
package garbagecollector
import (
"bytes"
"fmt"
"io"
"net/http"
"sort"
"strings"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/encoding"
"gonum.org/v1/gonum/graph/encoding/dot"
"gonum.org/v1/gonum/graph/simple"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
type gonumVertex struct {
type dotVertex struct {
uid types.UID
gvk schema.GroupVersionKind
namespace string
@ -41,14 +39,25 @@ type gonumVertex struct {
beingDeleted bool
deletingDependents bool
virtual bool
vertexID int64
}
func (v *gonumVertex) ID() int64 {
return v.vertexID
func (v *dotVertex) MarshalDOT(w io.Writer) error {
attrs := v.Attributes()
if _, err := fmt.Fprintf(w, " %q [\n", v.uid); err != nil {
return err
}
for _, a := range attrs {
if _, err := fmt.Fprintf(w, " %s=%q\n", a.Key, a.Value); err != nil {
return err
}
}
if _, err := fmt.Fprintf(w, " ];\n"); err != nil {
return err
}
return nil
}
func (v *gonumVertex) String() string {
func (v *dotVertex) String() string {
kind := v.gvk.Kind + "." + v.gvk.Version
if len(v.gvk.Group) > 0 {
kind = kind + "." + v.gvk.Group
@ -72,7 +81,12 @@ func (v *gonumVertex) String() string {
return fmt.Sprintf(`%s/%s[%s]-%v%s%s%s%s`, kind, v.name, v.namespace, v.uid, missing, deleting, deletingDependents, virtual)
}
func (v *gonumVertex) Attributes() []encoding.Attribute {
type attribute struct {
Key string
Value string
}
func (v *dotVertex) Attributes() []attribute {
kubectlString := v.gvk.Kind + "." + v.gvk.Version
if len(v.gvk.Group) > 0 {
kubectlString = kubectlString + "." + v.gvk.Group
@ -106,30 +120,30 @@ namespace=%v
label = label + conditionString + "\n"
}
return []encoding.Attribute{
{Key: "label", Value: fmt.Sprintf(`"%v"`, label)},
return []attribute{
{Key: "label", Value: label},
// these place metadata in the correct location, but don't conform to any normal attribute for rendering
{Key: "group", Value: fmt.Sprintf(`"%v"`, v.gvk.Group)},
{Key: "version", Value: fmt.Sprintf(`"%v"`, v.gvk.Version)},
{Key: "kind", Value: fmt.Sprintf(`"%v"`, v.gvk.Kind)},
{Key: "namespace", Value: fmt.Sprintf(`"%v"`, v.namespace)},
{Key: "name", Value: fmt.Sprintf(`"%v"`, v.name)},
{Key: "uid", Value: fmt.Sprintf(`"%v"`, v.uid)},
{Key: "missing", Value: fmt.Sprintf(`"%v"`, v.missingFromGraph)},
{Key: "beingDeleted", Value: fmt.Sprintf(`"%v"`, v.beingDeleted)},
{Key: "deletingDependents", Value: fmt.Sprintf(`"%v"`, v.deletingDependents)},
{Key: "virtual", Value: fmt.Sprintf(`"%v"`, v.virtual)},
{Key: "group", Value: v.gvk.Group},
{Key: "version", Value: v.gvk.Version},
{Key: "kind", Value: v.gvk.Kind},
{Key: "namespace", Value: v.namespace},
{Key: "name", Value: v.name},
{Key: "uid", Value: string(v.uid)},
{Key: "missing", Value: fmt.Sprintf(`%v`, v.missingFromGraph)},
{Key: "beingDeleted", Value: fmt.Sprintf(`%v`, v.beingDeleted)},
{Key: "deletingDependents", Value: fmt.Sprintf(`%v`, v.deletingDependents)},
{Key: "virtual", Value: fmt.Sprintf(`%v`, v.virtual)},
}
}
// NewGonumVertex creates a new gonumVertex.
func NewGonumVertex(node *node, nodeID int64) *gonumVertex {
// NewDOTVertex creates a new dotVertex.
func NewDOTVertex(node *node) *dotVertex {
gv, err := schema.ParseGroupVersion(node.identity.APIVersion)
if err != nil {
// this indicates a bad data serialization that should be prevented during storage of the API
utilruntime.HandleError(err)
}
return &gonumVertex{
return &dotVertex{
uid: node.identity.UID,
gvk: gv.WithKind(node.identity.Kind),
namespace: node.identity.Namespace,
@ -137,36 +151,46 @@ func NewGonumVertex(node *node, nodeID int64) *gonumVertex {
beingDeleted: node.beingDeleted,
deletingDependents: node.deletingDependents,
virtual: node.virtual,
vertexID: nodeID,
}
}
// NewMissingGonumVertex creates a new gonumVertex.
func NewMissingGonumVertex(ownerRef metav1.OwnerReference, nodeID int64) *gonumVertex {
// NewMissingdotVertex creates a new dotVertex.
func NewMissingdotVertex(ownerRef metav1.OwnerReference) *dotVertex {
gv, err := schema.ParseGroupVersion(ownerRef.APIVersion)
if err != nil {
// this indicates a bad data serialization that should be prevented during storage of the API
utilruntime.HandleError(err)
}
return &gonumVertex{
return &dotVertex{
uid: ownerRef.UID,
gvk: gv.WithKind(ownerRef.Kind),
name: ownerRef.Name,
missingFromGraph: true,
vertexID: nodeID,
}
}
func (m *concurrentUIDToNode) ToGonumGraph() graph.Directed {
func (m *concurrentUIDToNode) ToDOTNodesAndEdges() ([]*dotVertex, []dotEdge) {
m.uidToNodeLock.Lock()
defer m.uidToNodeLock.Unlock()
return toGonumGraph(m.uidToNode)
return toDOTNodesAndEdges(m.uidToNode)
}
func toGonumGraph(uidToNode map[types.UID]*node) graph.Directed {
uidToVertex := map[types.UID]*gonumVertex{}
graphBuilder := simple.NewDirectedGraph()
type dotEdge struct {
F types.UID
T types.UID
}
func (e dotEdge) MarshalDOT(w io.Writer) error {
_, err := fmt.Fprintf(w, " %q -> %q;\n", e.F, e.T)
return err
}
func toDOTNodesAndEdges(uidToNode map[types.UID]*node) ([]*dotVertex, []dotEdge) {
nodes := []*dotVertex{}
edges := []dotEdge{}
uidToVertex := map[types.UID]*dotVertex{}
// add the vertices first, then edges. That avoids having to deal with missing refs.
for _, node := range uidToNode {
@ -174,38 +198,42 @@ func toGonumGraph(uidToNode map[types.UID]*node) graph.Directed {
if len(node.dependents) == 0 && len(node.owners) == 0 {
continue
}
vertex := NewGonumVertex(node, graphBuilder.NewNode().ID())
vertex := NewDOTVertex(node)
uidToVertex[node.identity.UID] = vertex
graphBuilder.AddNode(vertex)
nodes = append(nodes, vertex)
}
for _, node := range uidToNode {
currVertex := uidToVertex[node.identity.UID]
for _, ownerRef := range node.owners {
currOwnerVertex, ok := uidToVertex[ownerRef.UID]
if !ok {
currOwnerVertex = NewMissingGonumVertex(ownerRef, graphBuilder.NewNode().ID())
currOwnerVertex = NewMissingdotVertex(ownerRef)
uidToVertex[node.identity.UID] = currOwnerVertex
graphBuilder.AddNode(currOwnerVertex)
nodes = append(nodes, currOwnerVertex)
}
graphBuilder.SetEdge(simple.Edge{
F: currVertex,
T: currOwnerVertex,
})
edges = append(edges, dotEdge{F: currVertex.uid, T: currOwnerVertex.uid})
}
}
return graphBuilder
sort.SliceStable(nodes, func(i, j int) bool { return nodes[i].uid < nodes[j].uid })
sort.SliceStable(edges, func(i, j int) bool {
if edges[i].F != edges[j].F {
return edges[i].F < edges[j].F
}
return edges[i].T < edges[j].T
})
return nodes, edges
}
func (m *concurrentUIDToNode) ToGonumGraphForObj(uids ...types.UID) graph.Directed {
func (m *concurrentUIDToNode) ToDOTNodesAndEdgesForObj(uids ...types.UID) ([]*dotVertex, []dotEdge) {
m.uidToNodeLock.Lock()
defer m.uidToNodeLock.Unlock()
return toGonumGraphForObj(m.uidToNode, uids...)
return toDOTNodesAndEdgesForObj(m.uidToNode, uids...)
}
func toGonumGraphForObj(uidToNode map[types.UID]*node, uids ...types.UID) graph.Directed {
func toDOTNodesAndEdgesForObj(uidToNode map[types.UID]*node, uids ...types.UID) ([]*dotVertex, []dotEdge) {
uidsToCheck := append([]types.UID{}, uids...)
interestingNodes := map[types.UID]*node{}
@ -241,7 +269,7 @@ func toGonumGraphForObj(uidToNode map[types.UID]*node, uids ...types.UID) graph.
}
}
return toGonumGraph(interestingNodes)
return toDOTNodesAndEdges(interestingNodes)
}
// NewDebugHandler creates a new debugHTTPHandler.
@ -253,32 +281,64 @@ type debugHTTPHandler struct {
controller *GarbageCollector
}
func marshalDOT(w io.Writer, nodes []*dotVertex, edges []dotEdge) error {
if _, err := w.Write([]byte("strict digraph full {\n")); err != nil {
return err
}
if len(nodes) > 0 {
if _, err := w.Write([]byte(" // Node definitions.\n")); err != nil {
return err
}
for _, node := range nodes {
if err := node.MarshalDOT(w); err != nil {
return err
}
}
}
if len(edges) > 0 {
if _, err := w.Write([]byte(" // Edge definitions.\n")); err != nil {
return err
}
for _, edge := range edges {
if err := edge.MarshalDOT(w); err != nil {
return err
}
}
}
if _, err := w.Write([]byte("}\n")); err != nil {
return err
}
return nil
}
func (h *debugHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if req.URL.Path != "/graph" {
http.Error(w, "", http.StatusNotFound)
return
}
var graph graph.Directed
var nodes []*dotVertex
var edges []dotEdge
if uidStrings := req.URL.Query()["uid"]; len(uidStrings) > 0 {
uids := []types.UID{}
for _, uidString := range uidStrings {
uids = append(uids, types.UID(uidString))
}
graph = h.controller.dependencyGraphBuilder.uidToNode.ToGonumGraphForObj(uids...)
nodes, edges = h.controller.dependencyGraphBuilder.uidToNode.ToDOTNodesAndEdgesForObj(uids...)
} else {
graph = h.controller.dependencyGraphBuilder.uidToNode.ToGonumGraph()
nodes, edges = h.controller.dependencyGraphBuilder.uidToNode.ToDOTNodesAndEdges()
}
data, err := dot.Marshal(graph, "full", "", " ")
if err != nil {
b := bytes.NewBuffer(nil)
if err := marshalDOT(b, nodes, edges); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/vnd.graphviz")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Write(data)
w.Write(b.Bytes())
w.WriteHeader(http.StatusOK)
}

View File

@ -17,12 +17,13 @@ limitations under the License.
package garbagecollector
import (
"sort"
"bytes"
"os"
"path/filepath"
"testing"
"github.com/davecgh/go-spew/spew"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/simple"
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@ -116,11 +117,12 @@ var (
}
)
func TestToGonumGraph(t *testing.T) {
func TestToDOTGraph(t *testing.T) {
tests := []struct {
name string
uidToNode map[types.UID]*node
expect graph.Directed
name string
uidToNode map[types.UID]*node
expectNodes []*dotVertex
expectEdges []dotEdge
}{
{
name: "simple",
@ -129,24 +131,15 @@ func TestToGonumGraph(t *testing.T) {
types.UID("bravo"): bravoNode(),
types.UID("charlie"): charlieNode(),
},
expect: func() graph.Directed {
graphBuilder := simple.NewDirectedGraph()
alphaVertex := NewGonumVertex(alphaNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(alphaVertex)
bravoVertex := NewGonumVertex(bravoNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(bravoVertex)
charlieVertex := NewGonumVertex(charlieNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(charlieVertex)
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: bravoVertex,
})
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: charlieVertex,
})
return graphBuilder
}(),
expectNodes: []*dotVertex{
NewDOTVertex(alphaNode()),
NewDOTVertex(bravoNode()),
NewDOTVertex(charlieNode()),
},
expectEdges: []dotEdge{
{F: types.UID("alpha"), T: types.UID("bravo")},
{F: types.UID("alpha"), T: types.UID("charlie")},
},
},
{
name: "missing", // synthetic vertex created
@ -154,24 +147,15 @@ func TestToGonumGraph(t *testing.T) {
types.UID("alpha"): alphaNode(),
types.UID("charlie"): charlieNode(),
},
expect: func() graph.Directed {
graphBuilder := simple.NewDirectedGraph()
alphaVertex := NewGonumVertex(alphaNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(alphaVertex)
bravoVertex := NewGonumVertex(bravoNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(bravoVertex)
charlieVertex := NewGonumVertex(charlieNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(charlieVertex)
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: bravoVertex,
})
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: charlieVertex,
})
return graphBuilder
}(),
expectNodes: []*dotVertex{
NewDOTVertex(alphaNode()),
NewDOTVertex(bravoNode()),
NewDOTVertex(charlieNode()),
},
expectEdges: []dotEdge{
{F: types.UID("alpha"), T: types.UID("bravo")},
{F: types.UID("alpha"), T: types.UID("charlie")},
},
},
{
name: "drop-no-ref",
@ -181,24 +165,15 @@ func TestToGonumGraph(t *testing.T) {
types.UID("charlie"): charlieNode(),
types.UID("echo"): echoNode(),
},
expect: func() graph.Directed {
graphBuilder := simple.NewDirectedGraph()
alphaVertex := NewGonumVertex(alphaNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(alphaVertex)
bravoVertex := NewGonumVertex(bravoNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(bravoVertex)
charlieVertex := NewGonumVertex(charlieNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(charlieVertex)
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: bravoVertex,
})
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: charlieVertex,
})
return graphBuilder
}(),
expectNodes: []*dotVertex{
NewDOTVertex(alphaNode()),
NewDOTVertex(bravoNode()),
NewDOTVertex(charlieNode()),
},
expectEdges: []dotEdge{
{F: types.UID("alpha"), T: types.UID("bravo")},
{F: types.UID("alpha"), T: types.UID("charlie")},
},
},
{
name: "two-chains",
@ -210,59 +185,38 @@ func TestToGonumGraph(t *testing.T) {
types.UID("foxtrot"): foxtrotNode(),
types.UID("golf"): golfNode(),
},
expect: func() graph.Directed {
graphBuilder := simple.NewDirectedGraph()
alphaVertex := NewGonumVertex(alphaNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(alphaVertex)
bravoVertex := NewGonumVertex(bravoNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(bravoVertex)
charlieVertex := NewGonumVertex(charlieNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(charlieVertex)
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: bravoVertex,
})
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: charlieVertex,
})
deltaVertex := NewGonumVertex(deltaNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(deltaVertex)
foxtrotVertex := NewGonumVertex(foxtrotNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(foxtrotVertex)
golfVertex := NewGonumVertex(golfNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(golfVertex)
graphBuilder.SetEdge(simple.Edge{
F: deltaVertex,
T: foxtrotVertex,
})
graphBuilder.SetEdge(simple.Edge{
F: foxtrotVertex,
T: golfVertex,
})
return graphBuilder
}(),
expectNodes: []*dotVertex{
NewDOTVertex(alphaNode()),
NewDOTVertex(bravoNode()),
NewDOTVertex(charlieNode()),
NewDOTVertex(deltaNode()),
NewDOTVertex(foxtrotNode()),
NewDOTVertex(golfNode()),
},
expectEdges: []dotEdge{
{F: types.UID("alpha"), T: types.UID("bravo")},
{F: types.UID("alpha"), T: types.UID("charlie")},
{F: types.UID("delta"), T: types.UID("foxtrot")},
{F: types.UID("foxtrot"), T: types.UID("golf")},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := toGonumGraph(test.uidToNode)
compareGraphs(test.expect, actual, t)
actualNodes, actualEdges := toDOTNodesAndEdges(test.uidToNode)
compareGraphs(test.expectNodes, actualNodes, test.expectEdges, actualEdges, t)
})
}
}
func TestToGonumGraphObj(t *testing.T) {
func TestToDOTGraphObj(t *testing.T) {
tests := []struct {
name string
uidToNode map[types.UID]*node
uids []types.UID
expect graph.Directed
name string
uidToNode map[types.UID]*node
uids []types.UID
expectNodes []*dotVertex
expectEdges []dotEdge
}{
{
name: "simple",
@ -272,24 +226,15 @@ func TestToGonumGraphObj(t *testing.T) {
types.UID("charlie"): charlieNode(),
},
uids: []types.UID{types.UID("bravo")},
expect: func() graph.Directed {
graphBuilder := simple.NewDirectedGraph()
alphaVertex := NewGonumVertex(alphaNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(alphaVertex)
bravoVertex := NewGonumVertex(bravoNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(bravoVertex)
charlieVertex := NewGonumVertex(charlieNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(charlieVertex)
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: bravoVertex,
})
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: charlieVertex,
})
return graphBuilder
}(),
expectNodes: []*dotVertex{
NewDOTVertex(alphaNode()),
NewDOTVertex(bravoNode()),
NewDOTVertex(charlieNode()),
},
expectEdges: []dotEdge{
{F: types.UID("alpha"), T: types.UID("bravo")},
{F: types.UID("alpha"), T: types.UID("charlie")},
},
},
{
name: "missing", // synthetic vertex created
@ -297,11 +242,9 @@ func TestToGonumGraphObj(t *testing.T) {
types.UID("alpha"): alphaNode(),
types.UID("charlie"): charlieNode(),
},
uids: []types.UID{types.UID("bravo")},
expect: func() graph.Directed {
graphBuilder := simple.NewDirectedGraph()
return graphBuilder
}(),
uids: []types.UID{types.UID("bravo")},
expectNodes: []*dotVertex{},
expectEdges: []dotEdge{},
},
{
name: "drop-no-ref",
@ -311,11 +254,9 @@ func TestToGonumGraphObj(t *testing.T) {
types.UID("charlie"): charlieNode(),
types.UID("echo"): echoNode(),
},
uids: []types.UID{types.UID("echo")},
expect: func() graph.Directed {
graphBuilder := simple.NewDirectedGraph()
return graphBuilder
}(),
uids: []types.UID{types.UID("echo")},
expectNodes: []*dotVertex{},
expectEdges: []dotEdge{},
},
{
name: "two-chains-from-owner",
@ -328,25 +269,15 @@ func TestToGonumGraphObj(t *testing.T) {
types.UID("golf"): golfNode(),
},
uids: []types.UID{types.UID("golf")},
expect: func() graph.Directed {
graphBuilder := simple.NewDirectedGraph()
deltaVertex := NewGonumVertex(deltaNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(deltaVertex)
foxtrotVertex := NewGonumVertex(foxtrotNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(foxtrotVertex)
golfVertex := NewGonumVertex(golfNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(golfVertex)
graphBuilder.SetEdge(simple.Edge{
F: deltaVertex,
T: foxtrotVertex,
})
graphBuilder.SetEdge(simple.Edge{
F: foxtrotVertex,
T: golfVertex,
})
return graphBuilder
}(),
expectNodes: []*dotVertex{
NewDOTVertex(deltaNode()),
NewDOTVertex(foxtrotNode()),
NewDOTVertex(golfNode()),
},
expectEdges: []dotEdge{
{F: types.UID("delta"), T: types.UID("foxtrot")},
{F: types.UID("foxtrot"), T: types.UID("golf")},
},
},
{
name: "two-chains-from-child",
@ -359,25 +290,15 @@ func TestToGonumGraphObj(t *testing.T) {
types.UID("golf"): golfNode(),
},
uids: []types.UID{types.UID("delta")},
expect: func() graph.Directed {
graphBuilder := simple.NewDirectedGraph()
deltaVertex := NewGonumVertex(deltaNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(deltaVertex)
foxtrotVertex := NewGonumVertex(foxtrotNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(foxtrotVertex)
golfVertex := NewGonumVertex(golfNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(golfVertex)
graphBuilder.SetEdge(simple.Edge{
F: deltaVertex,
T: foxtrotVertex,
})
graphBuilder.SetEdge(simple.Edge{
F: foxtrotVertex,
T: golfVertex,
})
return graphBuilder
}(),
expectNodes: []*dotVertex{
NewDOTVertex(deltaNode()),
NewDOTVertex(foxtrotNode()),
NewDOTVertex(golfNode()),
},
expectEdges: []dotEdge{
{F: types.UID("delta"), T: types.UID("foxtrot")},
{F: types.UID("foxtrot"), T: types.UID("golf")},
},
},
{
name: "two-chains-choose-both",
@ -390,98 +311,125 @@ func TestToGonumGraphObj(t *testing.T) {
types.UID("golf"): golfNode(),
},
uids: []types.UID{types.UID("delta"), types.UID("charlie")},
expect: func() graph.Directed {
graphBuilder := simple.NewDirectedGraph()
alphaVertex := NewGonumVertex(alphaNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(alphaVertex)
bravoVertex := NewGonumVertex(bravoNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(bravoVertex)
charlieVertex := NewGonumVertex(charlieNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(charlieVertex)
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: bravoVertex,
})
graphBuilder.SetEdge(simple.Edge{
F: alphaVertex,
T: charlieVertex,
})
deltaVertex := NewGonumVertex(deltaNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(deltaVertex)
foxtrotVertex := NewGonumVertex(foxtrotNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(foxtrotVertex)
golfVertex := NewGonumVertex(golfNode(), graphBuilder.NewNode().ID())
graphBuilder.AddNode(golfVertex)
graphBuilder.SetEdge(simple.Edge{
F: deltaVertex,
T: foxtrotVertex,
})
graphBuilder.SetEdge(simple.Edge{
F: foxtrotVertex,
T: golfVertex,
})
return graphBuilder
}(),
expectNodes: []*dotVertex{
NewDOTVertex(alphaNode()),
NewDOTVertex(bravoNode()),
NewDOTVertex(charlieNode()),
NewDOTVertex(deltaNode()),
NewDOTVertex(foxtrotNode()),
NewDOTVertex(golfNode()),
},
expectEdges: []dotEdge{
{F: types.UID("alpha"), T: types.UID("bravo")},
{F: types.UID("alpha"), T: types.UID("charlie")},
{F: types.UID("delta"), T: types.UID("foxtrot")},
{F: types.UID("foxtrot"), T: types.UID("golf")},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := toGonumGraphForObj(test.uidToNode, test.uids...)
compareGraphs(test.expect, actual, t)
actualNodes, actualEdges := toDOTNodesAndEdgesForObj(test.uidToNode, test.uids...)
compareGraphs(test.expectNodes, actualNodes, test.expectEdges, actualEdges, t)
})
}
}
func compareGraphs(expected, actual graph.Directed, t *testing.T) {
// sort the edges by from ID, then to ID
// (the slices we get back are from map iteration, where order is not guaranteed)
expectedNodes := expected.Nodes().(graph.NodeSlicer).NodeSlice()
actualNodes := actual.Nodes().(graph.NodeSlicer).NodeSlice()
sort.Sort(gonumByUID(expectedNodes))
sort.Sort(gonumByUID(actualNodes))
func compareGraphs(expectedNodes, actualNodes []*dotVertex, expectedEdges, actualEdges []dotEdge, t *testing.T) {
if len(expectedNodes) != len(actualNodes) {
t.Fatal(spew.Sdump(actual))
t.Fatal(spew.Sdump(actualNodes))
}
for i := range expectedNodes {
currExpected := *expectedNodes[i].(*gonumVertex)
currActual := *actualNodes[i].(*gonumVertex)
currExpected := expectedNodes[i]
currActual := actualNodes[i]
if currExpected.uid != currActual.uid {
t.Errorf("expected %v, got %v", spew.Sdump(currExpected), spew.Sdump(currActual))
}
expectedFrom := append([]graph.Node{}, expected.From(expectedNodes[i].ID()).(graph.NodeSlicer).NodeSlice()...)
actualFrom := append([]graph.Node{}, actual.From(actualNodes[i].ID()).(graph.NodeSlicer).NodeSlice()...)
sort.Sort(gonumByUID(expectedFrom))
sort.Sort(gonumByUID(actualFrom))
if len(expectedFrom) != len(actualFrom) {
t.Errorf("%q: expected %v, got %v", currExpected.uid, spew.Sdump(expectedFrom), spew.Sdump(actualFrom))
}
for i := range expectedFrom {
currExpectedFrom := *expectedFrom[i].(*gonumVertex)
currActualFrom := *actualFrom[i].(*gonumVertex)
if currExpectedFrom.uid != currActualFrom.uid {
t.Errorf("expected %v, got %v", spew.Sdump(currExpectedFrom), spew.Sdump(currActualFrom))
}
}
if len(expectedEdges) != len(actualEdges) {
t.Fatal(spew.Sdump(actualEdges))
}
for i := range expectedEdges {
currExpected := expectedEdges[i]
currActual := actualEdges[i]
if currExpected != currActual {
t.Errorf("expected %v, got %v", spew.Sdump(currExpected), spew.Sdump(currActual))
}
}
}
type gonumByUID []graph.Node
func TestMarshalDOT(t *testing.T) {
ref1 := objectReference{
OwnerReference: metav1.OwnerReference{
UID: types.UID("ref1-[]\"\\Iñtërnâtiônàlizætiøn,🐹"),
Name: "ref1name-Iñtërnâtiônàlizætiøn,🐹",
Kind: "ref1kind-Iñtërnâtiônàlizætiøn,🐹",
APIVersion: "ref1group/version",
},
Namespace: "ref1ns",
}
ref2 := objectReference{
OwnerReference: metav1.OwnerReference{
UID: types.UID("ref2-"),
Name: "ref2name-",
Kind: "ref2kind-",
APIVersion: "ref2group/version",
},
Namespace: "ref2ns",
}
testcases := []struct {
file string
nodes []*dotVertex
edges []dotEdge
}{
{
file: "empty.dot",
},
{
file: "simple.dot",
nodes: []*dotVertex{
NewDOTVertex(alphaNode()),
NewDOTVertex(bravoNode()),
NewDOTVertex(charlieNode()),
NewDOTVertex(deltaNode()),
NewDOTVertex(foxtrotNode()),
NewDOTVertex(golfNode()),
},
edges: []dotEdge{
{F: types.UID("alpha"), T: types.UID("bravo")},
{F: types.UID("alpha"), T: types.UID("charlie")},
{F: types.UID("delta"), T: types.UID("foxtrot")},
{F: types.UID("foxtrot"), T: types.UID("golf")},
},
},
{
file: "escaping.dot",
nodes: []*dotVertex{
NewDOTVertex(makeNode(ref1, withOwners(ref2))),
NewDOTVertex(makeNode(ref2)),
},
edges: []dotEdge{
{F: types.UID(ref1.UID), T: types.UID(ref2.UID)},
},
},
}
func (s gonumByUID) Len() int { return len(s) }
func (s gonumByUID) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
for _, tc := range testcases {
t.Run(tc.file, func(t *testing.T) {
goldenData, err := os.ReadFile(filepath.Join("testdata", tc.file))
if err != nil {
t.Fatal(err)
}
b := bytes.NewBuffer(nil)
if err := marshalDOT(b, tc.nodes, tc.edges); err != nil {
t.Fatal(err)
}
func (s gonumByUID) Less(i, j int) bool {
lhs := s[i].(*gonumVertex)
lhsUID := string(lhs.uid)
rhs := s[j].(*gonumVertex)
rhsUID := string(rhs.uid)
return lhsUID < rhsUID
if e, a := string(goldenData), string(b.Bytes()); cmp.Diff(e, a) != "" {
t.Logf("got\n%s", string(a))
t.Fatalf("unexpected diff:\n%s", cmp.Diff(e, a))
}
})
}
}

View File

@ -0,0 +1,2 @@
strict digraph full {
}

View File

@ -0,0 +1,31 @@
strict digraph full {
// Node definitions.
"ref1-[]\"\\Iñtërnâtiônàlizætiøn,🐹" [
label="uid=ref1-[]\"\\Iñtërnâtiônàlizætiøn,🐹\nnamespace=ref1ns\nref1kind-Iñtërnâtiônàlizætiøn,🐹.version.ref1group/ref1name-Iñtërnâtiônàlizætiøn,🐹\n"
group="ref1group"
version="version"
kind="ref1kind-Iñtërnâtiônàlizætiøn,🐹"
namespace="ref1ns"
name="ref1name-Iñtërnâtiônàlizætiøn,🐹"
uid="ref1-[]\"\\Iñtërnâtiônàlizætiøn,🐹"
missing="false"
beingDeleted="false"
deletingDependents="false"
virtual="false"
];
"ref2-" [
label="uid=ref2-\nnamespace=ref2ns\nref2kind-.version.ref2group/ref2name-\n"
group="ref2group"
version="version"
kind="ref2kind-"
namespace="ref2ns"
name="ref2name-"
uid="ref2-"
missing="false"
beingDeleted="false"
deletingDependents="false"
virtual="false"
];
// Edge definitions.
"ref1-[]\"\\Iñtërnâtiônàlizætiøn,🐹" -> "ref2-";
}

View File

@ -0,0 +1,86 @@
strict digraph full {
// Node definitions.
"alpha" [
label="uid=alpha\nnamespace=\n./\n"
group=""
version=""
kind=""
namespace=""
name=""
uid="alpha"
missing="false"
beingDeleted="false"
deletingDependents="false"
virtual="false"
];
"bravo" [
label="uid=bravo\nnamespace=\n./\n"
group=""
version=""
kind=""
namespace=""
name=""
uid="bravo"
missing="false"
beingDeleted="false"
deletingDependents="false"
virtual="false"
];
"charlie" [
label="uid=charlie\nnamespace=\n./\n"
group=""
version=""
kind=""
namespace=""
name=""
uid="charlie"
missing="false"
beingDeleted="false"
deletingDependents="false"
virtual="false"
];
"delta" [
label="uid=delta\nnamespace=\n./\n"
group=""
version=""
kind=""
namespace=""
name=""
uid="delta"
missing="false"
beingDeleted="false"
deletingDependents="false"
virtual="false"
];
"foxtrot" [
label="uid=foxtrot\nnamespace=\n./\n"
group=""
version=""
kind=""
namespace=""
name=""
uid="foxtrot"
missing="false"
beingDeleted="false"
deletingDependents="false"
virtual="false"
];
"golf" [
label="uid=golf\nnamespace=\n./\n"
group=""
version=""
kind=""
namespace=""
name=""
uid="golf"
missing="false"
beingDeleted="false"
deletingDependents="false"
virtual="false"
];
// Edge definitions.
"alpha" -> "bravo";
"alpha" -> "charlie";
"delta" -> "foxtrot";
"foxtrot" -> "golf";
}

97
vendor/gonum.org/v1/gonum/AUTHORS generated vendored
View File

@ -1,97 +0,0 @@
# This is the official list of gonum authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
# Names should be added to this file as
# Name or Organization <email address>
# The email address is not required for organizations.
# Please keep the list sorted.
Alexander Egurnov <alexander.egurnov@gmail.com>
Bill Gray <wgray@gogray.com>
Bill Noon <noon.bill@gmail.com>
Brendan Tracey <tracey.brendan@gmail.com>
Brent Pedersen <bpederse@gmail.com>
Chad Kunde <kunde21@gmail.com>
Chih-Wei Chang <bert.cwchang@gmail.com>
Chris Tessum <ctessum@gmail.com>
Christophe Meessen <christophe.meessen@gmail.com>
Clayton Northey <clayton.northey@gmail.com>
Dan Kortschak <dan.kortschak@adelaide.edu.au> <dan@kortschak.io>
Daniel Fireman <danielfireman@gmail.com>
Dario Heinisch <dario.heinisch@gmail.com>
David Kleiven <davidkleiven446@gmail.com>
David Samborski <bloggingarrow@gmail.com>
Davor Kapsa <davor.kapsa@gmail.com>
DeepMind Technologies
Delaney Gillilan <delaneygillilan@gmail.com>
Dezmond Goff <goff.dezmond@gmail.com>
Dong-hee Na <donghee.na92@gmail.com>
Egon Elbre <egonelbre@gmail.com>
Ekaterina Efimova <katerina.efimova@gmail.com>
Ethan Burns <burns.ethan@gmail.com>
Evert Lammerts <evert.lammerts@gmail.com>
Facundo Gaich <facugaich@gmail.com>
Fazlul Shahriar <fshahriar@gmail.com>
Francesc Campoy <campoy@golang.org>
Google Inc
Gustaf Johansson <gustaf@pinon.se>
Iakov Davydov <iakov.davydov@unil.ch>
Igor Mikushkin <igor.mikushkin@gmail.com>
Iskander Sharipov <quasilyte@gmail.com>
Jalem Raj Rohit <jrajrohit33@gmail.com>
James Bell <james@stellentus.com>
James Bowman <james.edward.bowman@gmail.com>
James Holmes <32bitkid@gmail.com>
Janne Snabb <snabb@epipe.com>
Jeff Juozapaitis <jjjuozap@email.arizona.edu>
Jeremy Atkinson <jchatkinson@gmail.com>
Jonas Kahler <jonas@derkahler.de>
Jonas Schulze <jonas.schulze@ovgu.de>
Jonathan J Lawlor <jonathan.lawlor@gmail.com>
Jonathan Reiter <jonreiter@gmail.com>
Jonathan Schroeder <jd.schroeder@gmail.com>
Joseph Watson <jtwatson@linux-consulting.us>
Josh Wilson <josh.craig.wilson@gmail.com>
Julien Roland <juroland@gmail.com>
Kai Trukenmüller <ktye78@gmail.com>
Kent English <kent.english@gmail.com>
Kevin C. Zimmerman <kevinczimmerman@gmail.com>
Kirill Motkov <motkov.kirill@gmail.com>
Konstantin Shaposhnikov <k.shaposhnikov@gmail.com>
Leonid Kneller <recondite.matter@gmail.com>
Lyron Winderbaum <lyron.winderbaum@student.adelaide.edu.au>
Martin Diz <github@martindiz.com.ar>
Matthieu Di Mercurio <matthieu.dimercurio@gmail.com>
Max Halford <maxhalford25@gmail.com>
MinJae Kwon <k239507@gmail.com>
Nathan Edwards <etaoinshrdluwho@gmail.com>
Nick Potts <nick@the-potts.com>
Nils Wogatzky <odog@netcologne.de>
Olivier Wulveryck <olivier.wulveryck@gmail.com>
Or Rikon <rikonor@gmail.com>
Pontus Melke <pontusmelke@gmail.com>
Renée French
Rishi Desai <desai.rishi1@gmail.com>
Robin Eklind <r.eklind.87@gmail.com>
Sam Zaydel <szaydel@gmail.com>
Samuel Kelemen <Samuel@Kelemen.us>
Saran Ahluwalia <ahlusar.ahluwalia@gmail.com>
Scott Holden <scott@sshconnection.com>
Sebastien Binet <seb.binet@gmail.com>
Shawn Smith <shawnpsmith@gmail.com>
source{d} <hello@sourced.tech>
Spencer Lyon <spencerlyon2@gmail.com>
Steve McCoy <mccoyst@gmail.com>
Taesu Pyo <pyotaesu@gmail.com>
Takeshi Yoneda <cz.rk.t0415y.g@gmail.com>
The University of Adelaide
The University of Minnesota
The University of Washington
Thomas Berg <tomfuture@gmail.com>
Tobin Harding <me@tobin.cc>
Vincent Thiery <vjmthiery@gmail.com>
Vladimír Chalupecký <vladimir.chalupecky@gmail.com>
Yevgeniy Vahlis <evahlis@gmail.com>
Yucheng Zhu <zyctc000@gmail.com>

View File

@ -1,99 +0,0 @@
# This is the official list of people who can contribute
# (and typically have contributed) code to the gonum
# repository.
#
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees would be listed here
# but not in AUTHORS, because Google would hold the copyright.
#
# When adding J Random Contributor's name to this file,
# either J's name or J's organization's name should be
# added to the AUTHORS file.
#
# Names should be added to this file like so:
# Name <email address>
#
# Please keep the list sorted.
Alexander Egurnov <alexander.egurnov@gmail.com>
Andrew Brampton <brampton@gmail.com>
Bill Gray <wgray@gogray.com>
Bill Noon <noon.bill@gmail.com>
Brendan Tracey <tracey.brendan@gmail.com>
Brent Pedersen <bpederse@gmail.com>
Chad Kunde <kunde21@gmail.com>
Chih-Wei Chang <bert.cwchang@gmail.com>
Chris Tessum <ctessum@gmail.com>
Christophe Meessen <christophe.meessen@gmail.com>
Clayton Northey <clayton.northey@gmail.com>
Dan Kortschak <dan.kortschak@adelaide.edu.au> <dan@kortschak.io>
Daniel Fireman <danielfireman@gmail.com>
Dario Heinisch <dario.heinisch@gmail.com>
David Kleiven <davidkleiven446@gmail.com>
David Samborski <bloggingarrow@gmail.com>
Davor Kapsa <davor.kapsa@gmail.com>
Delaney Gillilan <delaneygillilan@gmail.com>
Dezmond Goff <goff.dezmond@gmail.com>
Dong-hee Na <donghee.na92@gmail.com>
Egon Elbre <egonelbre@gmail.com>
Ekaterina Efimova <katerina.efimova@gmail.com>
Ethan Burns <burns.ethan@gmail.com>
Evert Lammerts <evert.lammerts@gmail.com>
Facundo Gaich <facugaich@gmail.com>
Fazlul Shahriar <fshahriar@gmail.com>
Francesc Campoy <campoy@golang.org>
Gustaf Johansson <gustaf@pinon.se>
Iakov Davydov <iakov.davydov@unil.ch>
Igor Mikushkin <igor.mikushkin@gmail.com>
Iskander Sharipov <quasilyte@gmail.com>
Jalem Raj Rohit <jrajrohit33@gmail.com>
James Bell <james@stellentus.com>
James Bowman <james.edward.bowman@gmail.com>
James Holmes <32bitkid@gmail.com>
Janne Snabb <snabb@epipe.com>
Jeff Juozapaitis <jjjuozap@email.arizona.edu>
Jeremy Atkinson <jchatkinson@gmail.com>
Jonas Kahler <jonas@derkahler.de>
Jonas Schulze <jonas.schulze@ovgu.de>
Jonathan J Lawlor <jonathan.lawlor@gmail.com>
Jonathan Reiter <jonreiter@gmail.com>
Jonathan Schroeder <jd.schroeder@gmail.com>
Joseph Watson <jtwatson@linux-consulting.us>
Josh Wilson <josh.craig.wilson@gmail.com>
Julien Roland <juroland@gmail.com>
Kai Trukenmüller <ktye78@gmail.com>
Kent English <kent.english@gmail.com>
Kevin C. Zimmerman <kevinczimmerman@gmail.com>
Kirill Motkov <motkov.kirill@gmail.com>
Konstantin Shaposhnikov <k.shaposhnikov@gmail.com>
Leonid Kneller <recondite.matter@gmail.com>
Lyron Winderbaum <lyron.winderbaum@student.adelaide.edu.au>
Martin Diz <github@martindiz.com.ar>
Matthieu Di Mercurio <matthieu.dimercurio@gmail.com>
Max Halford <maxhalford25@gmail.com>
MinJae Kwon <k239507@gmail.com>
Nathan Edwards <etaoinshrdluwho@gmail.com>
Nick Potts <nick@the-potts.com>
Nils Wogatzky <odog@netcologne.de>
Olivier Wulveryck <olivier.wulveryck@gmail.com>
Or Rikon <rikonor@gmail.com>
Pontus Melke <pontusmelke@gmail.com>
Renée French
Rishi Desai <desai.rishi1@gmail.com>
Robin Eklind <r.eklind.87@gmail.com>
Sam Zaydel <szaydel@gmail.com>
Samuel Kelemen <Samuel@Kelemen.us>
Saran Ahluwalia <ahlusar.ahluwalia@gmail.com>
Scott Holden <scott@sshconnection.com>
Sebastien Binet <seb.binet@gmail.com>
Shawn Smith <shawnpsmith@gmail.com>
Spencer Lyon <spencerlyon2@gmail.com>
Steve McCoy <mccoyst@gmail.com>
Taesu Pyo <pyotaesu@gmail.com>
Takeshi Yoneda <cz.rk.t0415y.g@gmail.com>
Thomas Berg <tomfuture@gmail.com>
Tobin Harding <me@tobin.cc>
Vincent Thiery <vjmthiery@gmail.com>
Vladimír Chalupecký <vladimir.chalupecky@gmail.com>
Yevgeniy Vahlis <evahlis@gmail.com>
Yucheng Zhu <zyctc000@gmail.com>

23
vendor/gonum.org/v1/gonum/LICENSE generated vendored
View File

@ -1,23 +0,0 @@
Copyright ©2013 The Gonum 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 the gonum project nor the names of its authors and
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 HOLDER 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.

View File

@ -1,47 +0,0 @@
# Gonum BLAS [![GoDoc](https://godoc.org/gonum.org/v1/gonum/blas?status.svg)](https://godoc.org/gonum.org/v1/gonum/blas)
A collection of packages to provide BLAS functionality for the [Go programming
language](http://golang.org)
## Installation
```sh
go get gonum.org/v1/gonum/blas/...
```
## Packages
### blas
Defines [BLAS API](http://www.netlib.org/blas/blast-forum/cinterface.pdf) split in several
interfaces.
### blas/gonum
Go implementation of the BLAS API (incomplete, implements the `float32` and `float64` API).
### 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"
"gonum.org/v1/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 gonum.org/v1/netlib/blas.

View File

@ -1,283 +0,0 @@
// 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.
//go:generate ./conversions.bash
package blas
// Flag constants indicate Givens transformation H matrix state.
type Flag int
const (
Identity Flag = -2 // H is the identity matrix; no rotation is needed.
Rescaling Flag = -1 // H specifies rescaling.
OffDiagonal Flag = 0 // Off-diagonal elements of H are non-unit.
Diagonal Flag = 1 // Diagonal elements of H are non-unit.
)
// 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 specifies the transposition operation of a matrix.
type Transpose byte
const (
NoTrans Transpose = 'N'
Trans Transpose = 'T'
ConjTrans Transpose = 'C'
)
// Uplo specifies whether a matrix is upper or lower triangular.
type Uplo byte
const (
Upper Uplo = 'U'
Lower Uplo = 'L'
All Uplo = 'A'
)
// Diag specifies whether a matrix is unit triangular.
type Diag byte
const (
NonUnit Diag = 'N'
Unit Diag = 'U'
)
// Side specifies from which side a multiplication operation is performed.
type Side byte
const (
Left Side = 'L'
Right Side = 'R'
)
// 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)
}

View File

@ -1,472 +0,0 @@
// 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
import (
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/blas/gonum"
)
var blas64 blas.Float64 = gonum.Implementation{}
// Use sets the BLAS float64 implementation to be used by subsequent BLAS calls.
// The default implementation is
// gonum.org/v1/gonum/blas/gonum.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 {
N int
Data []float64
Inc int
}
// General represents a matrix using the conventional storage scheme.
type General struct {
Rows, Cols int
Data []float64
Stride int
}
// Band represents a band matrix using the band storage scheme.
type Band struct {
Rows, Cols int
KL, KU int
Data []float64
Stride int
}
// Triangular represents a triangular matrix using the conventional storage scheme.
type Triangular struct {
Uplo blas.Uplo
Diag blas.Diag
N int
Data []float64
Stride int
}
// TriangularBand represents a triangular matrix using the band storage scheme.
type TriangularBand struct {
Uplo blas.Uplo
Diag blas.Diag
N, K int
Data []float64
Stride int
}
// TriangularPacked represents a triangular matrix using the packed storage scheme.
type TriangularPacked struct {
Uplo blas.Uplo
Diag blas.Diag
N int
Data []float64
}
// Symmetric represents a symmetric matrix using the conventional storage scheme.
type Symmetric struct {
Uplo blas.Uplo
N int
Data []float64
Stride int
}
// SymmetricBand represents a symmetric matrix using the band storage scheme.
type SymmetricBand struct {
Uplo blas.Uplo
N, K int
Data []float64
Stride int
}
// SymmetricPacked represents a symmetric matrix using the packed storage scheme.
type SymmetricPacked struct {
Uplo blas.Uplo
N int
Data []float64
}
// Level 1
const (
negInc = "blas64: negative vector increment"
badLength = "blas64: vector length mismatch"
)
// Dot computes the dot product of the two vectors:
// \sum_i x[i]*y[i].
// Dot will panic if the lengths of x and y do not match.
func Dot(x, y Vector) float64 {
if x.N != y.N {
panic(badLength)
}
return blas64.Ddot(x.N, x.Data, x.Inc, y.Data, y.Inc)
}
// Nrm2 computes the Euclidean norm of the vector x:
// sqrt(\sum_i x[i]*x[i]).
//
// Nrm2 will panic if the vector increment is negative.
func Nrm2(x Vector) float64 {
if x.Inc < 0 {
panic(negInc)
}
return blas64.Dnrm2(x.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(x Vector) float64 {
if x.Inc < 0 {
panic(negInc)
}
return blas64.Dasum(x.N, x.Data, x.Inc)
}
// Iamax returns the index of an element of x with the largest absolute value.
// 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(x Vector) int {
if x.Inc < 0 {
panic(negInc)
}
return blas64.Idamax(x.N, x.Data, x.Inc)
}
// Swap exchanges the elements of the two vectors:
// x[i], y[i] = y[i], x[i] for all i.
// Swap will panic if the lengths of x and y do not match.
func Swap(x, y Vector) {
if x.N != y.N {
panic(badLength)
}
blas64.Dswap(x.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.
// Copy will panic if the lengths of x and y do not match.
func Copy(x, y Vector) {
if x.N != y.N {
panic(badLength)
}
blas64.Dcopy(x.N, x.Data, x.Inc, y.Data, y.Inc)
}
// Axpy adds x scaled by alpha to y:
// y[i] += alpha*x[i] for all i.
// Axpy will panic if the lengths of x and y do not match.
func Axpy(alpha float64, x, y Vector) {
if x.N != y.N {
panic(badLength)
}
blas64.Daxpy(x.N, alpha, x.Data, x.Inc, y.Data, y.Inc)
}
// Rotg computes the parameters of a Givens plane rotation so that
// ⎡ c s⎤ ⎡a⎤ ⎡r⎤
// ⎣-s c⎦ * ⎣b⎦ = ⎣0⎦
// where a and b are the Cartesian coordinates of a given point.
// c, s, and r are defined as
// r = ±Sqrt(a^2 + b^2),
// c = a/r, the cosine of the rotation angle,
// s = a/r, the sine of the rotation angle,
// and z is defined such that
// if |a| > |b|, z = s,
// otherwise if c != 0, z = 1/c,
// otherwise z = 1.
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 to n points represented by the vectors x
// and y:
// x[i] = c*x[i] + s*y[i],
// y[i] = -s*x[i] + c*y[i], for all i.
func Rot(x, y Vector, c, s float64) {
if x.N != y.N {
panic(badLength)
}
blas64.Drot(x.N, x.Data, x.Inc, y.Data, y.Inc, c, s)
}
// Rotm applies the modified Givens rotation to n points represented by the
// vectors x and y.
func Rotm(x, y Vector, p blas.DrotmParams) {
if x.N != y.N {
panic(badLength)
}
blas64.Drotm(x.N, x.Data, x.Inc, y.Data, y.Inc, p)
}
// Scal scales the vector x by alpha:
// x[i] *= alpha for all i.
//
// Scal will panic if the vector increment is negative.
func Scal(alpha float64, x Vector) {
if x.Inc < 0 {
panic(negInc)
}
blas64.Dscal(x.N, alpha, x.Data, x.Inc)
}
// Level 2
// Gemv computes
// y = alpha * A * x + beta * y if t == blas.NoTrans,
// y = alpha * Aᵀ * x + beta * y if t == blas.Trans or blas.ConjTrans,
// where A is an m×n dense matrix, x and y are vectors, and alpha and beta are scalars.
func Gemv(t blas.Transpose, alpha float64, a General, x Vector, beta float64, y Vector) {
blas64.Dgemv(t, 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 t == blas.NoTrans,
// y = alpha * Aᵀ * x + beta * y if t == blas.Trans or blas.ConjTrans,
// where A is an m×n band matrix, x and y are vectors, and alpha and beta are scalars.
func Gbmv(t blas.Transpose, alpha float64, a Band, x Vector, beta float64, y Vector) {
blas64.Dgbmv(t, 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 t == blas.NoTrans,
// x = Aᵀ * x if t == blas.Trans or blas.ConjTrans,
// where A is an n×n triangular matrix, and x is a vector.
func Trmv(t blas.Transpose, a Triangular, x Vector) {
blas64.Dtrmv(a.Uplo, t, a.Diag, a.N, a.Data, a.Stride, x.Data, x.Inc)
}
// Tbmv computes
// x = A * x if t == blas.NoTrans,
// x = Aᵀ * x if t == blas.Trans or blas.ConjTrans,
// where A is an n×n triangular band matrix, and x is a vector.
func Tbmv(t blas.Transpose, a TriangularBand, x Vector) {
blas64.Dtbmv(a.Uplo, t, a.Diag, a.N, a.K, a.Data, a.Stride, x.Data, x.Inc)
}
// Tpmv computes
// x = A * x if t == blas.NoTrans,
// x = Aᵀ * x if t == blas.Trans or blas.ConjTrans,
// where A is an n×n triangular matrix in packed format, and x is a vector.
func Tpmv(t blas.Transpose, a TriangularPacked, x Vector) {
blas64.Dtpmv(a.Uplo, t, a.Diag, a.N, a.Data, x.Data, x.Inc)
}
// Trsv solves
// A * x = b if t == blas.NoTrans,
// Aᵀ * x = b if t == blas.Trans or blas.ConjTrans,
// where A is an n×n triangular matrix, and x and b are vectors.
//
// 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(t blas.Transpose, a Triangular, x Vector) {
blas64.Dtrsv(a.Uplo, t, a.Diag, a.N, a.Data, a.Stride, x.Data, x.Inc)
}
// Tbsv solves
// A * x = b if t == blas.NoTrans,
// Aᵀ * x = b if t == blas.Trans or blas.ConjTrans,
// where A is an n×n triangular band matrix, and x and b are vectors.
//
// 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(t blas.Transpose, a TriangularBand, x Vector) {
blas64.Dtbsv(a.Uplo, t, a.Diag, a.N, a.K, a.Data, a.Stride, x.Data, x.Inc)
}
// Tpsv solves
// A * x = b if t == blas.NoTrans,
// Aᵀ * x = b if t == blas.Trans or blas.ConjTrans,
// where A is an n×n triangular matrix in packed format, and x and b are
// vectors.
//
// 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(t blas.Transpose, a TriangularPacked, x Vector) {
blas64.Dtpsv(a.Uplo, t, 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 band 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 a rank-1 update
// A += alpha * x * yᵀ,
// 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 a rank-1 update
// A += alpha * x * xᵀ,
// where A is an n×n symmetric matrix, x is a vector, and alpha is a scalar.
func Syr(alpha float64, x Vector, a Symmetric) {
blas64.Dsyr(a.Uplo, a.N, alpha, x.Data, x.Inc, a.Data, a.Stride)
}
// Spr performs the rank-1 update
// A += alpha * x * xᵀ,
// 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 a rank-2 update
// A += alpha * x * yᵀ + alpha * y * xᵀ,
// 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 a rank-2 update
// A += alpha * x * yᵀ + alpha * y * xᵀ,
// where A is an n×n symmetric matrix in packed format, x and y are vectors,
// and alpha is a scalar.
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 = alpha * A * B + beta * C,
// where A, B, and C are dense matrices, and alpha and beta are scalars.
// tA and tB specify whether A or B are transposed.
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
// C = alpha * A * B + beta * C if s == blas.Left,
// C = alpha * B * A + beta * C if s == blas.Right,
// where A is an n×n or m×m 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 a symmetric rank-k update
// C = alpha * A * Aᵀ + beta * C if t == blas.NoTrans,
// C = alpha * Aᵀ * A + beta * C if t == blas.Trans or blas.ConjTrans,
// where C is an n×n symmetric matrix, A is an n×k matrix if t == blas.NoTrans and
// a k×n matrix otherwise, and 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 a symmetric rank-2k update
// C = alpha * A * Bᵀ + alpha * B * Aᵀ + beta * C if t == blas.NoTrans,
// C = alpha * Aᵀ * B + alpha * Bᵀ * A + beta * C if t == blas.Trans or blas.ConjTrans,
// where C is an n×n symmetric matrix, A and B are n×k matrices if t == NoTrans
// and k×n matrices otherwise, and 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 s == blas.Left,
// B = alpha * Aᵀ * B if tA == blas.Trans or blas.ConjTrans, and s == blas.Left,
// B = alpha * B * A if tA == blas.NoTrans and s == blas.Right,
// B = alpha * B * Aᵀ if tA == blas.Trans or blas.ConjTrans, and s == blas.Right,
// where A is an n×n or m×m triangular matrix, B is an m×n matrix, and alpha is
// a scalar.
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 and s == blas.Left,
// Aᵀ * X = alpha * B if tA == blas.Trans or blas.ConjTrans, and s == blas.Left,
// X * A = alpha * B if tA == blas.NoTrans and s == blas.Right,
// X * Aᵀ = alpha * B if tA == blas.Trans or blas.ConjTrans, and s == blas.Right,
// where A is an n×n or m×m triangular matrix, X and B are m×n matrices, 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)
}

View File

@ -1,277 +0,0 @@
// 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
import "gonum.org/v1/gonum/blas"
// GeneralCols represents a matrix using the conventional column-major storage scheme.
type GeneralCols General
// From fills the receiver with elements from a. The receiver
// must have the same dimensions as a and have adequate backing
// data storage.
func (t GeneralCols) From(a General) {
if t.Rows != a.Rows || t.Cols != a.Cols {
panic("blas64: mismatched dimension")
}
if len(t.Data) < (t.Cols-1)*t.Stride+t.Rows {
panic("blas64: short data slice")
}
for i := 0; i < a.Rows; i++ {
for j, v := range a.Data[i*a.Stride : i*a.Stride+a.Cols] {
t.Data[i+j*t.Stride] = v
}
}
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions as a and have adequate backing
// data storage.
func (t General) From(a GeneralCols) {
if t.Rows != a.Rows || t.Cols != a.Cols {
panic("blas64: mismatched dimension")
}
if len(t.Data) < (t.Rows-1)*t.Stride+t.Cols {
panic("blas64: short data slice")
}
for j := 0; j < a.Cols; j++ {
for i, v := range a.Data[j*a.Stride : j*a.Stride+a.Rows] {
t.Data[i*t.Stride+j] = v
}
}
}
// TriangularCols represents a matrix using the conventional column-major storage scheme.
type TriangularCols Triangular
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, uplo and diag as a and have
// adequate backing data storage.
func (t TriangularCols) From(a Triangular) {
if t.N != a.N {
panic("blas64: mismatched dimension")
}
if t.Uplo != a.Uplo {
panic("blas64: mismatched BLAS uplo")
}
if t.Diag != a.Diag {
panic("blas64: mismatched BLAS diag")
}
switch a.Uplo {
default:
panic("blas64: bad BLAS uplo")
case blas.Upper:
for i := 0; i < a.N; i++ {
for j := i; j < a.N; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
case blas.Lower:
for i := 0; i < a.N; i++ {
for j := 0; j <= i; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
case blas.All:
for i := 0; i < a.N; i++ {
for j := 0; j < a.N; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
}
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, uplo and diag as a and have
// adequate backing data storage.
func (t Triangular) From(a TriangularCols) {
if t.N != a.N {
panic("blas64: mismatched dimension")
}
if t.Uplo != a.Uplo {
panic("blas64: mismatched BLAS uplo")
}
if t.Diag != a.Diag {
panic("blas64: mismatched BLAS diag")
}
switch a.Uplo {
default:
panic("blas64: bad BLAS uplo")
case blas.Upper:
for i := 0; i < a.N; i++ {
for j := i; j < a.N; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
case blas.Lower:
for i := 0; i < a.N; i++ {
for j := 0; j <= i; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
case blas.All:
for i := 0; i < a.N; i++ {
for j := 0; j < a.N; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
}
}
// BandCols represents a matrix using the band column-major storage scheme.
type BandCols Band
// From fills the receiver with elements from a. The receiver
// must have the same dimensions and bandwidth as a and have
// adequate backing data storage.
func (t BandCols) From(a Band) {
if t.Rows != a.Rows || t.Cols != a.Cols {
panic("blas64: mismatched dimension")
}
if t.KL != a.KL || t.KU != a.KU {
panic("blas64: mismatched bandwidth")
}
if a.Stride < a.KL+a.KU+1 {
panic("blas64: short stride for source")
}
if t.Stride < t.KL+t.KU+1 {
panic("blas64: short stride for destination")
}
for i := 0; i < a.Rows; i++ {
for j := max(0, i-a.KL); j < min(i+a.KU+1, a.Cols); j++ {
t.Data[i+t.KU-j+j*t.Stride] = a.Data[j+a.KL-i+i*a.Stride]
}
}
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions and bandwidth as a and have
// adequate backing data storage.
func (t Band) From(a BandCols) {
if t.Rows != a.Rows || t.Cols != a.Cols {
panic("blas64: mismatched dimension")
}
if t.KL != a.KL || t.KU != a.KU {
panic("blas64: mismatched bandwidth")
}
if a.Stride < a.KL+a.KU+1 {
panic("blas64: short stride for source")
}
if t.Stride < t.KL+t.KU+1 {
panic("blas64: short stride for destination")
}
for j := 0; j < a.Cols; j++ {
for i := max(0, j-a.KU); i < min(j+a.KL+1, a.Rows); i++ {
t.Data[j+a.KL-i+i*a.Stride] = a.Data[i+t.KU-j+j*t.Stride]
}
}
}
// TriangularBandCols represents a triangular matrix using the band column-major storage scheme.
type TriangularBandCols TriangularBand
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, bandwidth and uplo as a and
// have adequate backing data storage.
func (t TriangularBandCols) From(a TriangularBand) {
if t.N != a.N {
panic("blas64: mismatched dimension")
}
if t.K != a.K {
panic("blas64: mismatched bandwidth")
}
if a.Stride < a.K+1 {
panic("blas64: short stride for source")
}
if t.Stride < t.K+1 {
panic("blas64: short stride for destination")
}
if t.Uplo != a.Uplo {
panic("blas64: mismatched BLAS uplo")
}
if t.Diag != a.Diag {
panic("blas64: mismatched BLAS diag")
}
dst := BandCols{
Rows: t.N, Cols: t.N,
Stride: t.Stride,
Data: t.Data,
}
src := Band{
Rows: a.N, Cols: a.N,
Stride: a.Stride,
Data: a.Data,
}
switch a.Uplo {
default:
panic("blas64: bad BLAS uplo")
case blas.Upper:
dst.KU = t.K
src.KU = a.K
case blas.Lower:
dst.KL = t.K
src.KL = a.K
}
dst.From(src)
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, bandwidth and uplo as a and
// have adequate backing data storage.
func (t TriangularBand) From(a TriangularBandCols) {
if t.N != a.N {
panic("blas64: mismatched dimension")
}
if t.K != a.K {
panic("blas64: mismatched bandwidth")
}
if a.Stride < a.K+1 {
panic("blas64: short stride for source")
}
if t.Stride < t.K+1 {
panic("blas64: short stride for destination")
}
if t.Uplo != a.Uplo {
panic("blas64: mismatched BLAS uplo")
}
if t.Diag != a.Diag {
panic("blas64: mismatched BLAS diag")
}
dst := Band{
Rows: t.N, Cols: t.N,
Stride: t.Stride,
Data: t.Data,
}
src := BandCols{
Rows: a.N, Cols: a.N,
Stride: a.Stride,
Data: a.Data,
}
switch a.Uplo {
default:
panic("blas64: bad BLAS uplo")
case blas.Upper:
dst.KU = t.K
src.KU = a.K
case blas.Lower:
dst.KL = t.K
src.KL = a.K
}
dst.From(src)
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}

View File

@ -1,153 +0,0 @@
// 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
import "gonum.org/v1/gonum/blas"
// SymmetricCols represents a matrix using the conventional column-major storage scheme.
type SymmetricCols Symmetric
// From fills the receiver with elements from a. The receiver
// must have the same dimensions and uplo as a and have adequate
// backing data storage.
func (t SymmetricCols) From(a Symmetric) {
if t.N != a.N {
panic("blas64: mismatched dimension")
}
if t.Uplo != a.Uplo {
panic("blas64: mismatched BLAS uplo")
}
switch a.Uplo {
default:
panic("blas64: bad BLAS uplo")
case blas.Upper:
for i := 0; i < a.N; i++ {
for j := i; j < a.N; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
case blas.Lower:
for i := 0; i < a.N; i++ {
for j := 0; j <= i; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
}
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions and uplo as a and have adequate
// backing data storage.
func (t Symmetric) From(a SymmetricCols) {
if t.N != a.N {
panic("blas64: mismatched dimension")
}
if t.Uplo != a.Uplo {
panic("blas64: mismatched BLAS uplo")
}
switch a.Uplo {
default:
panic("blas64: bad BLAS uplo")
case blas.Upper:
for i := 0; i < a.N; i++ {
for j := i; j < a.N; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
case blas.Lower:
for i := 0; i < a.N; i++ {
for j := 0; j <= i; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
}
}
// SymmetricBandCols represents a symmetric matrix using the band column-major storage scheme.
type SymmetricBandCols SymmetricBand
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, bandwidth and uplo as a and
// have adequate backing data storage.
func (t SymmetricBandCols) From(a SymmetricBand) {
if t.N != a.N {
panic("blas64: mismatched dimension")
}
if t.K != a.K {
panic("blas64: mismatched bandwidth")
}
if a.Stride < a.K+1 {
panic("blas64: short stride for source")
}
if t.Stride < t.K+1 {
panic("blas64: short stride for destination")
}
if t.Uplo != a.Uplo {
panic("blas64: mismatched BLAS uplo")
}
dst := BandCols{
Rows: t.N, Cols: t.N,
Stride: t.Stride,
Data: t.Data,
}
src := Band{
Rows: a.N, Cols: a.N,
Stride: a.Stride,
Data: a.Data,
}
switch a.Uplo {
default:
panic("blas64: bad BLAS uplo")
case blas.Upper:
dst.KU = t.K
src.KU = a.K
case blas.Lower:
dst.KL = t.K
src.KL = a.K
}
dst.From(src)
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, bandwidth and uplo as a and
// have adequate backing data storage.
func (t SymmetricBand) From(a SymmetricBandCols) {
if t.N != a.N {
panic("blas64: mismatched dimension")
}
if t.K != a.K {
panic("blas64: mismatched bandwidth")
}
if a.Stride < a.K+1 {
panic("blas64: short stride for source")
}
if t.Stride < t.K+1 {
panic("blas64: short stride for destination")
}
if t.Uplo != a.Uplo {
panic("blas64: mismatched BLAS uplo")
}
dst := Band{
Rows: t.N, Cols: t.N,
Stride: t.Stride,
Data: t.Data,
}
src := BandCols{
Rows: a.N, Cols: a.N,
Stride: a.Stride,
Data: a.Data,
}
switch a.Uplo {
default:
panic("blas64: bad BLAS uplo")
case blas.Upper:
dst.KU = t.K
src.KU = a.K
case blas.Lower:
dst.KL = t.K
src.KL = a.K
}
dst.From(src)
}

View File

@ -1,6 +0,0 @@
// Copyright ©2017 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 "gonum.org/v1/gonum/blas/blas64"

View File

@ -1,532 +0,0 @@
// 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 cblas128
import (
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/blas/gonum"
)
var cblas128 blas.Complex128 = gonum.Implementation{}
// Use sets the BLAS complex128 implementation to be used by subsequent BLAS calls.
// The default implementation is
// gonum.org/v1/gonum/blas/gonum.Implementation.
func Use(b blas.Complex128) {
cblas128 = b
}
// Implementation returns the current BLAS complex128 implementation.
//
// Implementation allows direct calls to the current the BLAS complex128 implementation
// giving finer control of parameters.
func Implementation() blas.Complex128 {
return cblas128
}
// Vector represents a vector with an associated element increment.
type Vector struct {
N int
Inc int
Data []complex128
}
// General represents a matrix using the conventional storage scheme.
type General struct {
Rows, Cols int
Stride int
Data []complex128
}
// Band represents a band matrix using the band storage scheme.
type Band struct {
Rows, Cols int
KL, KU int
Stride int
Data []complex128
}
// Triangular represents a triangular matrix using the conventional storage scheme.
type Triangular struct {
N int
Stride int
Data []complex128
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 []complex128
Uplo blas.Uplo
Diag blas.Diag
}
// TriangularPacked represents a triangular matrix using the packed storage scheme.
type TriangularPacked struct {
N int
Data []complex128
Uplo blas.Uplo
Diag blas.Diag
}
// Symmetric represents a symmetric matrix using the conventional storage scheme.
type Symmetric struct {
N int
Stride int
Data []complex128
Uplo blas.Uplo
}
// SymmetricBand represents a symmetric matrix using the band storage scheme.
type SymmetricBand struct {
N, K int
Stride int
Data []complex128
Uplo blas.Uplo
}
// SymmetricPacked represents a symmetric matrix using the packed storage scheme.
type SymmetricPacked struct {
N int
Data []complex128
Uplo blas.Uplo
}
// Hermitian represents an Hermitian matrix using the conventional storage scheme.
type Hermitian Symmetric
// HermitianBand represents an Hermitian matrix using the band storage scheme.
type HermitianBand SymmetricBand
// HermitianPacked represents an Hermitian matrix using the packed storage scheme.
type HermitianPacked SymmetricPacked
// Level 1
const (
negInc = "cblas128: negative vector increment"
badLength = "cblas128: vector length mismatch"
)
// Dotu computes the dot product of the two vectors without
// complex conjugation:
// xᵀ * y.
// Dotu will panic if the lengths of x and y do not match.
func Dotu(x, y Vector) complex128 {
if x.N != y.N {
panic(badLength)
}
return cblas128.Zdotu(x.N, x.Data, x.Inc, y.Data, y.Inc)
}
// Dotc computes the dot product of the two vectors with
// complex conjugation:
// xᴴ * y.
// Dotc will panic if the lengths of x and y do not match.
func Dotc(x, y Vector) complex128 {
if x.N != y.N {
panic(badLength)
}
return cblas128.Zdotc(x.N, x.Data, x.Inc, y.Data, y.Inc)
}
// Nrm2 computes the Euclidean norm of the vector x:
// sqrt(\sum_i x[i] * x[i]).
//
// Nrm2 will panic if the vector increment is negative.
func Nrm2(x Vector) float64 {
if x.Inc < 0 {
panic(negInc)
}
return cblas128.Dznrm2(x.N, x.Data, x.Inc)
}
// Asum computes the sum of magnitudes of the real and imaginary parts of
// elements of the vector x:
// \sum_i (|Re x[i]| + |Im x[i]|).
//
// Asum will panic if the vector increment is negative.
func Asum(x Vector) float64 {
if x.Inc < 0 {
panic(negInc)
}
return cblas128.Dzasum(x.N, x.Data, x.Inc)
}
// Iamax returns the index of an element of x with the largest sum of
// magnitudes of the real and imaginary parts (|Re x[i]|+|Im x[i]|).
// 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(x Vector) int {
if x.Inc < 0 {
panic(negInc)
}
return cblas128.Izamax(x.N, x.Data, x.Inc)
}
// Swap exchanges the elements of two vectors:
// x[i], y[i] = y[i], x[i] for all i.
// Swap will panic if the lengths of x and y do not match.
func Swap(x, y Vector) {
if x.N != y.N {
panic(badLength)
}
cblas128.Zswap(x.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.
// Copy will panic if the lengths of x and y do not match.
func Copy(x, y Vector) {
if x.N != y.N {
panic(badLength)
}
cblas128.Zcopy(x.N, x.Data, x.Inc, y.Data, y.Inc)
}
// Axpy computes
// y = alpha * x + y,
// where x and y are vectors, and alpha is a scalar.
// Axpy will panic if the lengths of x and y do not match.
func Axpy(alpha complex128, x, y Vector) {
if x.N != y.N {
panic(badLength)
}
cblas128.Zaxpy(x.N, alpha, x.Data, x.Inc, y.Data, y.Inc)
}
// Scal computes
// x = alpha * x,
// where x is a vector, and alpha is a scalar.
//
// Scal will panic if the vector increment is negative.
func Scal(alpha complex128, x Vector) {
if x.Inc < 0 {
panic(negInc)
}
cblas128.Zscal(x.N, alpha, x.Data, x.Inc)
}
// Dscal computes
// x = alpha * x,
// where x is a vector, and alpha is a real scalar.
//
// Dscal will panic if the vector increment is negative.
func Dscal(alpha float64, x Vector) {
if x.Inc < 0 {
panic(negInc)
}
cblas128.Zdscal(x.N, alpha, x.Data, x.Inc)
}
// Level 2
// Gemv computes
// y = alpha * A * x + beta * y if t == blas.NoTrans,
// y = alpha * Aᵀ * x + beta * y if t == blas.Trans,
// y = alpha * Aᴴ * x + beta * y if t == blas.ConjTrans,
// where A is an m×n dense matrix, x and y are vectors, and alpha and beta are
// scalars.
func Gemv(t blas.Transpose, alpha complex128, a General, x Vector, beta complex128, y Vector) {
cblas128.Zgemv(t, 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 t == blas.NoTrans,
// y = alpha * Aᵀ * x + beta * y if t == blas.Trans,
// y = alpha * Aᴴ * x + beta * y if t == blas.ConjTrans,
// where A is an m×n band matrix, x and y are vectors, and alpha and beta are
// scalars.
func Gbmv(t blas.Transpose, alpha complex128, a Band, x Vector, beta complex128, y Vector) {
cblas128.Zgbmv(t, 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 t == blas.NoTrans,
// x = Aᵀ * x if t == blas.Trans,
// x = Aᴴ * x if t == blas.ConjTrans,
// where A is an n×n triangular matrix, and x is a vector.
func Trmv(t blas.Transpose, a Triangular, x Vector) {
cblas128.Ztrmv(a.Uplo, t, a.Diag, a.N, a.Data, a.Stride, x.Data, x.Inc)
}
// Tbmv computes
// x = A * x if t == blas.NoTrans,
// x = Aᵀ * x if t == blas.Trans,
// x = Aᴴ * x if t == blas.ConjTrans,
// where A is an n×n triangular band matrix, and x is a vector.
func Tbmv(t blas.Transpose, a TriangularBand, x Vector) {
cblas128.Ztbmv(a.Uplo, t, a.Diag, a.N, a.K, a.Data, a.Stride, x.Data, x.Inc)
}
// Tpmv computes
// x = A * x if t == blas.NoTrans,
// x = Aᵀ * x if t == blas.Trans,
// x = Aᴴ * x if t == blas.ConjTrans,
// where A is an n×n triangular matrix in packed format, and x is a vector.
func Tpmv(t blas.Transpose, a TriangularPacked, x Vector) {
cblas128.Ztpmv(a.Uplo, t, a.Diag, a.N, a.Data, x.Data, x.Inc)
}
// Trsv solves
// A * x = b if t == blas.NoTrans,
// Aᵀ * x = b if t == blas.Trans,
// Aᴴ * x = b if t == blas.ConjTrans,
// where 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(t blas.Transpose, a Triangular, x Vector) {
cblas128.Ztrsv(a.Uplo, t, a.Diag, a.N, a.Data, a.Stride, x.Data, x.Inc)
}
// Tbsv solves
// A * x = b if t == blas.NoTrans,
// Aᵀ * x = b if t == blas.Trans,
// Aᴴ * x = b if t == blas.ConjTrans,
// where A is an n×n triangular band 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 Tbsv(t blas.Transpose, a TriangularBand, x Vector) {
cblas128.Ztbsv(a.Uplo, t, a.Diag, a.N, a.K, a.Data, a.Stride, x.Data, x.Inc)
}
// Tpsv solves
// A * x = b if t == blas.NoTrans,
// Aᵀ * x = b if t == blas.Trans,
// Aᴴ * x = b if t == 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(t blas.Transpose, a TriangularPacked, x Vector) {
cblas128.Ztpsv(a.Uplo, t, a.Diag, a.N, a.Data, x.Data, x.Inc)
}
// Hemv computes
// y = alpha * A * x + beta * y,
// where A is an n×n Hermitian matrix, x and y are vectors, and alpha and
// beta are scalars.
func Hemv(alpha complex128, a Hermitian, x Vector, beta complex128, y Vector) {
cblas128.Zhemv(a.Uplo, a.N, alpha, a.Data, a.Stride, x.Data, x.Inc, beta, y.Data, y.Inc)
}
// Hbmv performs
// y = alpha * A * x + beta * y,
// where A is an n×n Hermitian band matrix, x and y are vectors, and alpha
// and beta are scalars.
func Hbmv(alpha complex128, a HermitianBand, x Vector, beta complex128, y Vector) {
cblas128.Zhbmv(a.Uplo, a.N, a.K, alpha, a.Data, a.Stride, x.Data, x.Inc, beta, y.Data, y.Inc)
}
// Hpmv performs
// y = alpha * A * x + beta * y,
// where A is an n×n Hermitian matrix in packed format, x and y are vectors,
// and alpha and beta are scalars.
func Hpmv(alpha complex128, a HermitianPacked, x Vector, beta complex128, y Vector) {
cblas128.Zhpmv(a.Uplo, a.N, alpha, a.Data, x.Data, x.Inc, beta, y.Data, y.Inc)
}
// Geru performs a rank-1 update
// A += alpha * x * yᵀ,
// where A is an m×n dense matrix, x and y are vectors, and alpha is a scalar.
func Geru(alpha complex128, x, y Vector, a General) {
cblas128.Zgeru(a.Rows, a.Cols, alpha, x.Data, x.Inc, y.Data, y.Inc, a.Data, a.Stride)
}
// Gerc performs a rank-1 update
// A += alpha * x * yᴴ,
// where A is an m×n dense matrix, x and y are vectors, and alpha is a scalar.
func Gerc(alpha complex128, x, y Vector, a General) {
cblas128.Zgerc(a.Rows, a.Cols, alpha, x.Data, x.Inc, y.Data, y.Inc, a.Data, a.Stride)
}
// Her performs a rank-1 update
// A += alpha * x * yᵀ,
// where A is an m×n Hermitian matrix, x and y are vectors, and alpha is a scalar.
func Her(alpha float64, x Vector, a Hermitian) {
cblas128.Zher(a.Uplo, a.N, alpha, x.Data, x.Inc, a.Data, a.Stride)
}
// Hpr performs a rank-1 update
// A += alpha * x * xᴴ,
// where A is an n×n Hermitian matrix in packed format, x is a vector, and
// alpha is a scalar.
func Hpr(alpha float64, x Vector, a HermitianPacked) {
cblas128.Zhpr(a.Uplo, a.N, alpha, x.Data, x.Inc, a.Data)
}
// Her2 performs a rank-2 update
// A += alpha * x * yᴴ + conj(alpha) * y * xᴴ,
// where A is an n×n Hermitian matrix, x and y are vectors, and alpha is a scalar.
func Her2(alpha complex128, x, y Vector, a Hermitian) {
cblas128.Zher2(a.Uplo, a.N, alpha, x.Data, x.Inc, y.Data, y.Inc, a.Data, a.Stride)
}
// Hpr2 performs a rank-2 update
// A += alpha * x * yᴴ + conj(alpha) * y * xᴴ,
// where A is an n×n Hermitian matrix in packed format, x and y are vectors,
// and alpha is a scalar.
func Hpr2(alpha complex128, x, y Vector, a HermitianPacked) {
cblas128.Zhpr2(a.Uplo, a.N, alpha, x.Data, x.Inc, y.Data, y.Inc, a.Data)
}
// Level 3
// Gemm computes
// C = alpha * A * B + beta * C,
// where A, B, and C are dense matrices, and alpha and beta are scalars.
// tA and tB specify whether A or B are transposed or conjugated.
func Gemm(tA, tB blas.Transpose, alpha complex128, a, b General, beta complex128, 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
}
cblas128.Zgemm(tA, tB, m, n, k, alpha, a.Data, a.Stride, b.Data, b.Stride, beta, c.Data, c.Stride)
}
// Symm performs
// C = alpha * A * B + beta * C if s == blas.Left,
// C = alpha * B * A + beta * C if s == blas.Right,
// where A is an n×n or m×m symmetric matrix, B and C are m×n matrices, and
// alpha and beta are scalars.
func Symm(s blas.Side, alpha complex128, a Symmetric, b General, beta complex128, c General) {
var m, n int
if s == blas.Left {
m, n = a.N, b.Cols
} else {
m, n = b.Rows, a.N
}
cblas128.Zsymm(s, a.Uplo, m, n, alpha, a.Data, a.Stride, b.Data, b.Stride, beta, c.Data, c.Stride)
}
// Syrk performs a symmetric rank-k update
// C = alpha * A * Aᵀ + beta * C if t == blas.NoTrans,
// C = alpha * Aᵀ * A + beta * C if t == blas.Trans,
// where C is an n×n symmetric matrix, A is an n×k matrix if t == blas.NoTrans
// and a k×n matrix otherwise, and alpha and beta are scalars.
func Syrk(t blas.Transpose, alpha complex128, a General, beta complex128, c Symmetric) {
var n, k int
if t == blas.NoTrans {
n, k = a.Rows, a.Cols
} else {
n, k = a.Cols, a.Rows
}
cblas128.Zsyrk(c.Uplo, t, n, k, alpha, a.Data, a.Stride, beta, c.Data, c.Stride)
}
// Syr2k performs a symmetric rank-2k update
// C = alpha * A * Bᵀ + alpha * B * Aᵀ + beta * C if t == blas.NoTrans,
// C = alpha * Aᵀ * B + alpha * Bᵀ * A + beta * C if t == blas.Trans,
// where C is an n×n symmetric matrix, A and B are n×k matrices if
// t == blas.NoTrans and k×n otherwise, and alpha and beta are scalars.
func Syr2k(t blas.Transpose, alpha complex128, a, b General, beta complex128, c Symmetric) {
var n, k int
if t == blas.NoTrans {
n, k = a.Rows, a.Cols
} else {
n, k = a.Cols, a.Rows
}
cblas128.Zsyr2k(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 s == blas.Left,
// B = alpha * Aᵀ * B if tA == blas.Trans and s == blas.Left,
// B = alpha * Aᴴ * B if tA == blas.ConjTrans and s == blas.Left,
// B = alpha * B * A if tA == blas.NoTrans and s == blas.Right,
// B = alpha * B * Aᵀ if tA == blas.Trans and s == blas.Right,
// B = alpha * B * Aᴴ if tA == blas.ConjTrans and s == blas.Right,
// where A is an n×n or m×m triangular matrix, B is an m×n matrix, and alpha is
// a scalar.
func Trmm(s blas.Side, tA blas.Transpose, alpha complex128, a Triangular, b General) {
cblas128.Ztrmm(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 and s == blas.Left,
// Aᵀ * X = alpha * B if tA == blas.Trans and s == blas.Left,
// Aᴴ * X = alpha * B if tA == blas.ConjTrans and s == blas.Left,
// X * A = alpha * B if tA == blas.NoTrans and s == blas.Right,
// X * Aᵀ = alpha * B if tA == blas.Trans and s == blas.Right,
// X * Aᴴ = alpha * B if tA == blas.ConjTrans and s == blas.Right,
// where A is an n×n or m×m triangular matrix, X and B are m×n matrices, and
// alpha is a scalar.
//
// At entry to the function, b contains the values of B, and the result is
// stored in-place into b.
//
// No check is made that A is invertible.
func Trsm(s blas.Side, tA blas.Transpose, alpha complex128, a Triangular, b General) {
cblas128.Ztrsm(s, a.Uplo, tA, a.Diag, b.Rows, b.Cols, alpha, a.Data, a.Stride, b.Data, b.Stride)
}
// Hemm performs
// C = alpha * A * B + beta * C if s == blas.Left,
// C = alpha * B * A + beta * C if s == blas.Right,
// where A is an n×n or m×m Hermitian matrix, B and C are m×n matrices, and
// alpha and beta are scalars.
func Hemm(s blas.Side, alpha complex128, a Hermitian, b General, beta complex128, c General) {
var m, n int
if s == blas.Left {
m, n = a.N, b.Cols
} else {
m, n = b.Rows, a.N
}
cblas128.Zhemm(s, a.Uplo, m, n, alpha, a.Data, a.Stride, b.Data, b.Stride, beta, c.Data, c.Stride)
}
// Herk performs the Hermitian rank-k update
// C = alpha * A * Aᴴ + beta*C if t == blas.NoTrans,
// C = alpha * Aᴴ * A + beta*C if t == blas.ConjTrans,
// where C is an n×n Hermitian matrix, A is an n×k matrix if t == blas.NoTrans
// and a k×n matrix otherwise, and alpha and beta are scalars.
func Herk(t blas.Transpose, alpha float64, a General, beta float64, c Hermitian) {
var n, k int
if t == blas.NoTrans {
n, k = a.Rows, a.Cols
} else {
n, k = a.Cols, a.Rows
}
cblas128.Zherk(c.Uplo, t, n, k, alpha, a.Data, a.Stride, beta, c.Data, c.Stride)
}
// Her2k performs the Hermitian rank-2k update
// C = alpha * A * Bᴴ + conj(alpha) * B * Aᴴ + beta * C if t == blas.NoTrans,
// C = alpha * Aᴴ * B + conj(alpha) * Bᴴ * A + beta * C if t == blas.ConjTrans,
// where C is an n×n Hermitian matrix, A and B are n×k matrices if t == NoTrans
// and k×n matrices otherwise, and alpha and beta are scalars.
func Her2k(t blas.Transpose, alpha complex128, a, b General, beta float64, c Hermitian) {
var n, k int
if t == blas.NoTrans {
n, k = a.Rows, a.Cols
} else {
n, k = a.Cols, a.Rows
}
cblas128.Zher2k(c.Uplo, t, n, k, alpha, a.Data, a.Stride, b.Data, b.Stride, beta, c.Data, c.Stride)
}

View File

@ -1,279 +0,0 @@
// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.
// 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 cblas128
import "gonum.org/v1/gonum/blas"
// GeneralCols represents a matrix using the conventional column-major storage scheme.
type GeneralCols General
// From fills the receiver with elements from a. The receiver
// must have the same dimensions as a and have adequate backing
// data storage.
func (t GeneralCols) From(a General) {
if t.Rows != a.Rows || t.Cols != a.Cols {
panic("cblas128: mismatched dimension")
}
if len(t.Data) < (t.Cols-1)*t.Stride+t.Rows {
panic("cblas128: short data slice")
}
for i := 0; i < a.Rows; i++ {
for j, v := range a.Data[i*a.Stride : i*a.Stride+a.Cols] {
t.Data[i+j*t.Stride] = v
}
}
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions as a and have adequate backing
// data storage.
func (t General) From(a GeneralCols) {
if t.Rows != a.Rows || t.Cols != a.Cols {
panic("cblas128: mismatched dimension")
}
if len(t.Data) < (t.Rows-1)*t.Stride+t.Cols {
panic("cblas128: short data slice")
}
for j := 0; j < a.Cols; j++ {
for i, v := range a.Data[j*a.Stride : j*a.Stride+a.Rows] {
t.Data[i*t.Stride+j] = v
}
}
}
// TriangularCols represents a matrix using the conventional column-major storage scheme.
type TriangularCols Triangular
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, uplo and diag as a and have
// adequate backing data storage.
func (t TriangularCols) From(a Triangular) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
if t.Diag != a.Diag {
panic("cblas128: mismatched BLAS diag")
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
for i := 0; i < a.N; i++ {
for j := i; j < a.N; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
case blas.Lower:
for i := 0; i < a.N; i++ {
for j := 0; j <= i; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
case blas.All:
for i := 0; i < a.N; i++ {
for j := 0; j < a.N; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
}
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, uplo and diag as a and have
// adequate backing data storage.
func (t Triangular) From(a TriangularCols) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
if t.Diag != a.Diag {
panic("cblas128: mismatched BLAS diag")
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
for i := 0; i < a.N; i++ {
for j := i; j < a.N; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
case blas.Lower:
for i := 0; i < a.N; i++ {
for j := 0; j <= i; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
case blas.All:
for i := 0; i < a.N; i++ {
for j := 0; j < a.N; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
}
}
// BandCols represents a matrix using the band column-major storage scheme.
type BandCols Band
// From fills the receiver with elements from a. The receiver
// must have the same dimensions and bandwidth as a and have
// adequate backing data storage.
func (t BandCols) From(a Band) {
if t.Rows != a.Rows || t.Cols != a.Cols {
panic("cblas128: mismatched dimension")
}
if t.KL != a.KL || t.KU != a.KU {
panic("cblas128: mismatched bandwidth")
}
if a.Stride < a.KL+a.KU+1 {
panic("cblas128: short stride for source")
}
if t.Stride < t.KL+t.KU+1 {
panic("cblas128: short stride for destination")
}
for i := 0; i < a.Rows; i++ {
for j := max(0, i-a.KL); j < min(i+a.KU+1, a.Cols); j++ {
t.Data[i+t.KU-j+j*t.Stride] = a.Data[j+a.KL-i+i*a.Stride]
}
}
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions and bandwidth as a and have
// adequate backing data storage.
func (t Band) From(a BandCols) {
if t.Rows != a.Rows || t.Cols != a.Cols {
panic("cblas128: mismatched dimension")
}
if t.KL != a.KL || t.KU != a.KU {
panic("cblas128: mismatched bandwidth")
}
if a.Stride < a.KL+a.KU+1 {
panic("cblas128: short stride for source")
}
if t.Stride < t.KL+t.KU+1 {
panic("cblas128: short stride for destination")
}
for j := 0; j < a.Cols; j++ {
for i := max(0, j-a.KU); i < min(j+a.KL+1, a.Rows); i++ {
t.Data[j+a.KL-i+i*a.Stride] = a.Data[i+t.KU-j+j*t.Stride]
}
}
}
// TriangularBandCols represents a triangular matrix using the band column-major storage scheme.
type TriangularBandCols TriangularBand
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, bandwidth and uplo as a and
// have adequate backing data storage.
func (t TriangularBandCols) From(a TriangularBand) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.K != a.K {
panic("cblas128: mismatched bandwidth")
}
if a.Stride < a.K+1 {
panic("cblas128: short stride for source")
}
if t.Stride < t.K+1 {
panic("cblas128: short stride for destination")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
if t.Diag != a.Diag {
panic("cblas128: mismatched BLAS diag")
}
dst := BandCols{
Rows: t.N, Cols: t.N,
Stride: t.Stride,
Data: t.Data,
}
src := Band{
Rows: a.N, Cols: a.N,
Stride: a.Stride,
Data: a.Data,
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
dst.KU = t.K
src.KU = a.K
case blas.Lower:
dst.KL = t.K
src.KL = a.K
}
dst.From(src)
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, bandwidth and uplo as a and
// have adequate backing data storage.
func (t TriangularBand) From(a TriangularBandCols) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.K != a.K {
panic("cblas128: mismatched bandwidth")
}
if a.Stride < a.K+1 {
panic("cblas128: short stride for source")
}
if t.Stride < t.K+1 {
panic("cblas128: short stride for destination")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
if t.Diag != a.Diag {
panic("cblas128: mismatched BLAS diag")
}
dst := Band{
Rows: t.N, Cols: t.N,
Stride: t.Stride,
Data: t.Data,
}
src := BandCols{
Rows: a.N, Cols: a.N,
Stride: a.Stride,
Data: a.Data,
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
dst.KU = t.K
src.KU = a.K
case blas.Lower:
dst.KL = t.K
src.KL = a.K
}
dst.From(src)
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}

View File

@ -1,155 +0,0 @@
// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.
// 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 cblas128
import "gonum.org/v1/gonum/blas"
// HermitianCols represents a matrix using the conventional column-major storage scheme.
type HermitianCols Hermitian
// From fills the receiver with elements from a. The receiver
// must have the same dimensions and uplo as a and have adequate
// backing data storage.
func (t HermitianCols) From(a Hermitian) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
for i := 0; i < a.N; i++ {
for j := i; j < a.N; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
case blas.Lower:
for i := 0; i < a.N; i++ {
for j := 0; j <= i; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
}
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions and uplo as a and have adequate
// backing data storage.
func (t Hermitian) From(a HermitianCols) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
for i := 0; i < a.N; i++ {
for j := i; j < a.N; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
case blas.Lower:
for i := 0; i < a.N; i++ {
for j := 0; j <= i; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
}
}
// HermitianBandCols represents an Hermitian matrix using the band column-major storage scheme.
type HermitianBandCols HermitianBand
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, bandwidth and uplo as a and
// have adequate backing data storage.
func (t HermitianBandCols) From(a HermitianBand) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.K != a.K {
panic("cblas128: mismatched bandwidth")
}
if a.Stride < a.K+1 {
panic("cblas128: short stride for source")
}
if t.Stride < t.K+1 {
panic("cblas128: short stride for destination")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
dst := BandCols{
Rows: t.N, Cols: t.N,
Stride: t.Stride,
Data: t.Data,
}
src := Band{
Rows: a.N, Cols: a.N,
Stride: a.Stride,
Data: a.Data,
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
dst.KU = t.K
src.KU = a.K
case blas.Lower:
dst.KL = t.K
src.KL = a.K
}
dst.From(src)
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, bandwidth and uplo as a and
// have adequate backing data storage.
func (t HermitianBand) From(a HermitianBandCols) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.K != a.K {
panic("cblas128: mismatched bandwidth")
}
if a.Stride < a.K+1 {
panic("cblas128: short stride for source")
}
if t.Stride < t.K+1 {
panic("cblas128: short stride for destination")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
dst := Band{
Rows: t.N, Cols: t.N,
Stride: t.Stride,
Data: t.Data,
}
src := BandCols{
Rows: a.N, Cols: a.N,
Stride: a.Stride,
Data: a.Data,
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
dst.KU = t.K
src.KU = a.K
case blas.Lower:
dst.KL = t.K
src.KL = a.K
}
dst.From(src)
}

View File

@ -1,155 +0,0 @@
// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.
// 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 cblas128
import "gonum.org/v1/gonum/blas"
// SymmetricCols represents a matrix using the conventional column-major storage scheme.
type SymmetricCols Symmetric
// From fills the receiver with elements from a. The receiver
// must have the same dimensions and uplo as a and have adequate
// backing data storage.
func (t SymmetricCols) From(a Symmetric) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
for i := 0; i < a.N; i++ {
for j := i; j < a.N; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
case blas.Lower:
for i := 0; i < a.N; i++ {
for j := 0; j <= i; j++ {
t.Data[i+j*t.Stride] = a.Data[i*a.Stride+j]
}
}
}
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions and uplo as a and have adequate
// backing data storage.
func (t Symmetric) From(a SymmetricCols) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
for i := 0; i < a.N; i++ {
for j := i; j < a.N; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
case blas.Lower:
for i := 0; i < a.N; i++ {
for j := 0; j <= i; j++ {
t.Data[i*t.Stride+j] = a.Data[i+j*a.Stride]
}
}
}
}
// SymmetricBandCols represents a symmetric matrix using the band column-major storage scheme.
type SymmetricBandCols SymmetricBand
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, bandwidth and uplo as a and
// have adequate backing data storage.
func (t SymmetricBandCols) From(a SymmetricBand) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.K != a.K {
panic("cblas128: mismatched bandwidth")
}
if a.Stride < a.K+1 {
panic("cblas128: short stride for source")
}
if t.Stride < t.K+1 {
panic("cblas128: short stride for destination")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
dst := BandCols{
Rows: t.N, Cols: t.N,
Stride: t.Stride,
Data: t.Data,
}
src := Band{
Rows: a.N, Cols: a.N,
Stride: a.Stride,
Data: a.Data,
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
dst.KU = t.K
src.KU = a.K
case blas.Lower:
dst.KL = t.K
src.KL = a.K
}
dst.From(src)
}
// From fills the receiver with elements from a. The receiver
// must have the same dimensions, bandwidth and uplo as a and
// have adequate backing data storage.
func (t SymmetricBand) From(a SymmetricBandCols) {
if t.N != a.N {
panic("cblas128: mismatched dimension")
}
if t.K != a.K {
panic("cblas128: mismatched bandwidth")
}
if a.Stride < a.K+1 {
panic("cblas128: short stride for source")
}
if t.Stride < t.K+1 {
panic("cblas128: short stride for destination")
}
if t.Uplo != a.Uplo {
panic("cblas128: mismatched BLAS uplo")
}
dst := Band{
Rows: t.N, Cols: t.N,
Stride: t.Stride,
Data: t.Data,
}
src := BandCols{
Rows: a.N, Cols: a.N,
Stride: a.Stride,
Data: a.Data,
}
switch a.Uplo {
default:
panic("cblas128: bad BLAS uplo")
case blas.Upper:
dst.KU = t.K
src.KU = a.K
case blas.Lower:
dst.KL = t.K
src.KL = a.K
}
dst.From(src)
}

View File

@ -1,6 +0,0 @@
// Copyright ©2017 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 cblas128 provides a simple interface to the complex128 BLAS API.
package cblas128 // import "gonum.org/v1/gonum/blas/cblas128"

View File

@ -1,159 +0,0 @@
#!/usr/bin/env bash
# Copyright ©2017 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.
# Generate code for blas32.
echo Generating blas32/conv.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > blas32/conv.go
cat blas64/conv.go \
| gofmt -r 'float64 -> float32' \
\
| sed -e 's/blas64/blas32/' \
\
>> blas32/conv.go
echo Generating blas32/conv_test.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > blas32/conv_test.go
cat blas64/conv_test.go \
| gofmt -r 'float64 -> float32' \
\
| sed -e 's/blas64/blas32/' \
-e 's_"math"_math "gonum.org/v1/gonum/internal/math32"_' \
\
>> blas32/conv_test.go
echo Generating blas32/conv_symmetric.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > blas32/conv_symmetric.go
cat blas64/conv_symmetric.go \
| gofmt -r 'float64 -> float32' \
\
| sed -e 's/blas64/blas32/' \
\
>> blas32/conv_symmetric.go
echo Generating blas32/conv_symmetric_test.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > blas32/conv_symmetric_test.go
cat blas64/conv_symmetric_test.go \
| gofmt -r 'float64 -> float32' \
\
| sed -e 's/blas64/blas32/' \
-e 's_"math"_math "gonum.org/v1/gonum/internal/math32"_' \
\
>> blas32/conv_symmetric_test.go
# Generate code for cblas128.
echo Generating cblas128/conv.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > cblas128/conv.go
cat blas64/conv.go \
| gofmt -r 'float64 -> complex128' \
\
| sed -e 's/blas64/cblas128/' \
\
>> cblas128/conv.go
echo Generating cblas128/conv_test.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > cblas128/conv_test.go
cat blas64/conv_test.go \
| gofmt -r 'float64 -> complex128' \
\
| sed -e 's/blas64/cblas128/' \
-e 's_"math"_math "math/cmplx"_' \
\
>> cblas128/conv_test.go
echo Generating cblas128/conv_symmetric.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > cblas128/conv_symmetric.go
cat blas64/conv_symmetric.go \
| gofmt -r 'float64 -> complex128' \
\
| sed -e 's/blas64/cblas128/' \
\
>> cblas128/conv_symmetric.go
echo Generating cblas128/conv_symmetric_test.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > cblas128/conv_symmetric_test.go
cat blas64/conv_symmetric_test.go \
| gofmt -r 'float64 -> complex128' \
\
| sed -e 's/blas64/cblas128/' \
-e 's_"math"_math "math/cmplx"_' \
\
>> cblas128/conv_symmetric_test.go
echo Generating cblas128/conv_hermitian.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > cblas128/conv_hermitian.go
cat blas64/conv_symmetric.go \
| gofmt -r 'float64 -> complex128' \
\
| sed -e 's/blas64/cblas128/' \
-e 's/Symmetric/Hermitian/g' \
-e 's/a symmetric/an Hermitian/g' \
-e 's/symmetric/hermitian/g' \
-e 's/Sym/Herm/g' \
\
>> cblas128/conv_hermitian.go
echo Generating cblas128/conv_hermitian_test.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > cblas128/conv_hermitian_test.go
cat blas64/conv_symmetric_test.go \
| gofmt -r 'float64 -> complex128' \
\
| sed -e 's/blas64/cblas128/' \
-e 's/Symmetric/Hermitian/g' \
-e 's/a symmetric/an Hermitian/g' \
-e 's/symmetric/hermitian/g' \
-e 's/Sym/Herm/g' \
-e 's_"math"_math "math/cmplx"_' \
\
>> cblas128/conv_hermitian_test.go
# Generate code for cblas64.
echo Generating cblas64/conv.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > cblas64/conv.go
cat blas64/conv.go \
| gofmt -r 'float64 -> complex64' \
\
| sed -e 's/blas64/cblas64/' \
\
>> cblas64/conv.go
echo Generating cblas64/conv_test.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > cblas64/conv_test.go
cat blas64/conv_test.go \
| gofmt -r 'float64 -> complex64' \
\
| sed -e 's/blas64/cblas64/' \
-e 's_"math"_math "gonum.org/v1/gonum/internal/cmplx64"_' \
\
>> cblas64/conv_test.go
echo Generating cblas64/conv_hermitian.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > cblas64/conv_hermitian.go
cat blas64/conv_symmetric.go \
| gofmt -r 'float64 -> complex64' \
\
| sed -e 's/blas64/cblas64/' \
-e 's/Symmetric/Hermitian/g' \
-e 's/a symmetric/an Hermitian/g' \
-e 's/symmetric/hermitian/g' \
-e 's/Sym/Herm/g' \
\
>> cblas64/conv_hermitian.go
echo Generating cblas64/conv_hermitian_test.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas”; DO NOT EDIT.\n' > cblas64/conv_hermitian_test.go
cat blas64/conv_symmetric_test.go \
| gofmt -r 'float64 -> complex64' \
\
| sed -e 's/blas64/cblas64/' \
-e 's/Symmetric/Hermitian/g' \
-e 's/a symmetric/an Hermitian/g' \
-e 's/symmetric/hermitian/g' \
-e 's/Sym/Herm/g' \
-e 's_"math"_math "gonum.org/v1/gonum/internal/cmplx64"_' \
\
>> cblas64/conv_hermitian_test.go

108
vendor/gonum.org/v1/gonum/blas/doc.go generated vendored
View File

@ -1,108 +0,0 @@
// Copyright ©2017 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 // import "gonum.org/v1/gonum/blas"

View File

@ -1,314 +0,0 @@
// 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 gonum
import (
"runtime"
"sync"
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/internal/asm/f64"
)
// Dgemm performs one of the matrix-matrix operations
// C = alpha * A * B + beta * C
// C = alpha * Aᵀ * B + beta * C
// C = alpha * A * Bᵀ + beta * C
// C = alpha * Aᵀ * Bᵀ + beta * C
// where A is an m×k or k×m dense matrix, B is an n×k or k×n dense matrix, C is
// an m×n matrix, and alpha and beta are scalars. tA and tB specify whether A or
// B are transposed.
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) {
switch tA {
default:
panic(badTranspose)
case blas.NoTrans, blas.Trans, blas.ConjTrans:
}
switch tB {
default:
panic(badTranspose)
case blas.NoTrans, blas.Trans, blas.ConjTrans:
}
if m < 0 {
panic(mLT0)
}
if n < 0 {
panic(nLT0)
}
if k < 0 {
panic(kLT0)
}
aTrans := tA == blas.Trans || tA == blas.ConjTrans
if aTrans {
if lda < max(1, m) {
panic(badLdA)
}
} else {
if lda < max(1, k) {
panic(badLdA)
}
}
bTrans := tB == blas.Trans || tB == blas.ConjTrans
if bTrans {
if ldb < max(1, k) {
panic(badLdB)
}
} else {
if ldb < max(1, n) {
panic(badLdB)
}
}
if ldc < max(1, n) {
panic(badLdC)
}
// Quick return if possible.
if m == 0 || n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if aTrans {
if len(a) < (k-1)*lda+m {
panic(shortA)
}
} else {
if len(a) < (m-1)*lda+k {
panic(shortA)
}
}
if bTrans {
if len(b) < (n-1)*ldb+k {
panic(shortB)
}
} else {
if len(b) < (k-1)*ldb+n {
panic(shortB)
}
}
if len(c) < (m-1)*ldc+n {
panic(shortC)
}
// Quick return if possible.
if (alpha == 0 || k == 0) && beta == 1 {
return
}
// scale c
if beta != 1 {
if beta == 0 {
for i := 0; i < m; i++ {
ctmp := c[i*ldc : i*ldc+n]
for j := range ctmp {
ctmp[j] = 0
}
}
} else {
for i := 0; i < m; i++ {
ctmp := c[i*ldc : i*ldc+n]
for j := range ctmp {
ctmp[j] *= beta
}
}
}
}
dgemmParallel(aTrans, bTrans, m, n, k, a, lda, b, ldb, c, ldc, alpha)
}
func dgemmParallel(aTrans, bTrans bool, m, n, k int, a []float64, lda int, b []float64, ldb int, c []float64, ldc int, 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ᵀ * B)
// Cij = \sum_k Aik Bjk, (A * Bᵀ)
// Cij = \sum_k Aki Bjk, (Aᵀ * Bᵀ)
//
// 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.
maxKLen := k
parBlocks := blocks(m, blockSize) * blocks(n, blockSize)
if parBlocks < minParBlock {
// The matrix multiplication is small in the dimensions where it can be
// computed concurrently. Just do it in serial.
dgemmSerial(aTrans, bTrans, m, n, k, a, lda, b, ldb, c, ldc, 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()
for sub := range sendChan {
i := sub.i
j := sub.j
leni := blockSize
if i+leni > m {
leni = m - i
}
lenj := blockSize
if j+lenj > n {
lenj = n - j
}
cSub := sliceView64(c, ldc, 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 []float64
if aTrans {
aSub = sliceView64(a, lda, k, i, lenk, leni)
} else {
aSub = sliceView64(a, lda, i, k, leni, lenk)
}
if bTrans {
bSub = sliceView64(b, ldb, j, k, lenj, lenk)
} else {
bSub = sliceView64(b, ldb, k, j, lenk, lenj)
}
dgemmSerial(aTrans, bTrans, leni, lenj, lenk, aSub, lda, bSub, ldb, cSub, ldc, alpha)
}
}
}()
}
// Send out all of the {i, j} subblocks for computation.
for i := 0; i < m; i += blockSize {
for j := 0; j < n; j += blockSize {
sendChan <- subMul{
i: i,
j: j,
}
}
}
close(sendChan)
wg.Wait()
}
// dgemmSerial is serial matrix multiply
func dgemmSerial(aTrans, bTrans bool, m, n, k int, a []float64, lda int, b []float64, ldb int, c []float64, ldc int, alpha float64) {
switch {
case !aTrans && !bTrans:
dgemmSerialNotNot(m, n, k, a, lda, b, ldb, c, ldc, alpha)
return
case aTrans && !bTrans:
dgemmSerialTransNot(m, n, k, a, lda, b, ldb, c, ldc, alpha)
return
case !aTrans && bTrans:
dgemmSerialNotTrans(m, n, k, a, lda, b, ldb, c, ldc, alpha)
return
case aTrans && bTrans:
dgemmSerialTransTrans(m, n, k, a, lda, b, ldb, c, ldc, alpha)
return
default:
panic("unreachable")
}
}
// dgemmSerial where neither a nor b are transposed
func dgemmSerialNotNot(m, n, k int, a []float64, lda int, b []float64, ldb int, c []float64, ldc int, alpha float64) {
// 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 < m; i++ {
ctmp := c[i*ldc : i*ldc+n]
for l, v := range a[i*lda : i*lda+k] {
tmp := alpha * v
if tmp != 0 {
f64.AxpyUnitary(tmp, b[l*ldb:l*ldb+n], ctmp)
}
}
}
}
// dgemmSerial where neither a is transposed and b is not
func dgemmSerialTransNot(m, n, k int, a []float64, lda int, b []float64, ldb int, c []float64, ldc int, alpha float64) {
// 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 < k; l++ {
btmp := b[l*ldb : l*ldb+n]
for i, v := range a[l*lda : l*lda+m] {
tmp := alpha * v
if tmp != 0 {
ctmp := c[i*ldc : i*ldc+n]
f64.AxpyUnitary(tmp, btmp, ctmp)
}
}
}
}
// dgemmSerial where neither a is not transposed and b is
func dgemmSerialNotTrans(m, n, k int, a []float64, lda int, b []float64, ldb int, c []float64, ldc int, alpha float64) {
// 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 < m; i++ {
atmp := a[i*lda : i*lda+k]
ctmp := c[i*ldc : i*ldc+n]
for j := 0; j < n; j++ {
ctmp[j] += alpha * f64.DotUnitary(atmp, b[j*ldb:j*ldb+k])
}
}
}
// dgemmSerial where both are transposed
func dgemmSerialTransTrans(m, n, k int, a []float64, lda int, b []float64, ldb int, c []float64, ldc int, alpha float64) {
// 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 < k; l++ {
for i, v := range a[l*lda : l*lda+m] {
tmp := alpha * v
if tmp != 0 {
ctmp := c[i*ldc : i*ldc+n]
f64.AxpyInc(tmp, b[l:], ctmp, uintptr(n), uintptr(ldb), 1, 0, 0)
}
}
}
}
func sliceView64(a []float64, lda, i, j, r, c int) []float64 {
return a[i*lda+j : (i+r-1)*lda+j+c]
}

View File

@ -1,88 +0,0 @@
// 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 gonum 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. Note that the treatment of NaN values
is not specified, and differs among the BLAS implementations.
gonum.org/v1/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.
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 gonum // import "gonum.org/v1/gonum/blas/gonum"

View File

@ -1,35 +0,0 @@
// 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 gonum
// Panic strings used during parameter checks.
// This list is duplicated in netlib/blas/netlib. Keep in sync.
const (
zeroIncX = "blas: zero x index increment"
zeroIncY = "blas: zero y index increment"
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"
badFlag = "blas: illegal rotm flag"
badLdA = "blas: bad leading dimension of A"
badLdB = "blas: bad leading dimension of B"
badLdC = "blas: bad leading dimension of C"
shortX = "blas: insufficient length of x"
shortY = "blas: insufficient length of y"
shortAP = "blas: insufficient length of ap"
shortA = "blas: insufficient length of a"
shortB = "blas: insufficient length of b"
shortC = "blas: insufficient length of c"
)

View File

@ -1,190 +0,0 @@
// Copyright ©2018 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 gonum
import (
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/internal/asm/f32"
"gonum.org/v1/gonum/internal/asm/f64"
)
// TODO(Kunde21): Merge these methods back into level2double/level2single when Sgemv assembly kernels are merged into f32.
// Dgemv computes
// y = alpha * A * x + beta * y if tA = blas.NoTrans
// y = alpha * Aᵀ * 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 and beta are scalars.
func (Implementation) Dgemv(tA blas.Transpose, m, n int, alpha float64, a []float64, lda int, x []float64, incX int, beta float64, y []float64, incY int) {
if tA != blas.NoTrans && tA != blas.Trans && tA != blas.ConjTrans {
panic(badTranspose)
}
if m < 0 {
panic(mLT0)
}
if n < 0 {
panic(nLT0)
}
if lda < max(1, n) {
panic(badLdA)
}
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
// Set up indexes
lenX := m
lenY := n
if tA == blas.NoTrans {
lenX = n
lenY = m
}
// Quick return if possible
if m == 0 || n == 0 {
return
}
if (incX > 0 && (lenX-1)*incX >= len(x)) || (incX < 0 && (1-lenX)*incX >= len(x)) {
panic(shortX)
}
if (incY > 0 && (lenY-1)*incY >= len(y)) || (incY < 0 && (1-lenY)*incY >= len(y)) {
panic(shortY)
}
if len(a) < lda*(m-1)+n {
panic(shortA)
}
// Quick return if possible
if alpha == 0 && beta == 1 {
return
}
if alpha == 0 {
// First form y = beta * y
if incY > 0 {
Implementation{}.Dscal(lenY, beta, y, incY)
} else {
Implementation{}.Dscal(lenY, beta, y, -incY)
}
return
}
// Form y = alpha * A * x + y
if tA == blas.NoTrans {
f64.GemvN(uintptr(m), uintptr(n), alpha, a, uintptr(lda), x, uintptr(incX), beta, y, uintptr(incY))
return
}
// Cases where a is transposed.
f64.GemvT(uintptr(m), uintptr(n), alpha, a, uintptr(lda), x, uintptr(incX), beta, y, uintptr(incY))
}
// Sgemv computes
// y = alpha * A * x + beta * y if tA = blas.NoTrans
// y = alpha * Aᵀ * 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 and beta are scalars.
//
// Float32 implementations are autogenerated and not directly tested.
func (Implementation) Sgemv(tA blas.Transpose, m, n int, alpha float32, a []float32, lda int, x []float32, incX int, beta float32, y []float32, incY int) {
if tA != blas.NoTrans && tA != blas.Trans && tA != blas.ConjTrans {
panic(badTranspose)
}
if m < 0 {
panic(mLT0)
}
if n < 0 {
panic(nLT0)
}
if lda < max(1, n) {
panic(badLdA)
}
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
// Quick return if possible.
if m == 0 || n == 0 {
return
}
// Set up indexes
lenX := m
lenY := n
if tA == blas.NoTrans {
lenX = n
lenY = m
}
if (incX > 0 && (lenX-1)*incX >= len(x)) || (incX < 0 && (1-lenX)*incX >= len(x)) {
panic(shortX)
}
if (incY > 0 && (lenY-1)*incY >= len(y)) || (incY < 0 && (1-lenY)*incY >= len(y)) {
panic(shortY)
}
if len(a) < lda*(m-1)+n {
panic(shortA)
}
// Quick return if possible.
if alpha == 0 && beta == 1 {
return
}
// First form y = beta * y
if incY > 0 {
Implementation{}.Sscal(lenY, beta, y, incY)
} else {
Implementation{}.Sscal(lenY, beta, y, -incY)
}
if alpha == 0 {
return
}
var kx, ky int
if incX < 0 {
kx = -(lenX - 1) * incX
}
if incY < 0 {
ky = -(lenY - 1) * incY
}
// Form y = alpha * A * x + y
if tA == blas.NoTrans {
if incX == 1 && incY == 1 {
for i := 0; i < m; i++ {
y[i] += alpha * f32.DotUnitary(a[lda*i:lda*i+n], x[:n])
}
return
}
iy := ky
for i := 0; i < m; i++ {
y[iy] += alpha * f32.DotInc(x, a[lda*i:lda*i+n], uintptr(n), uintptr(incX), 1, uintptr(kx), 0)
iy += incY
}
return
}
// Cases where a is transposed.
if incX == 1 && incY == 1 {
for i := 0; i < m; i++ {
tmp := alpha * x[i]
if tmp != 0 {
f32.AxpyUnitaryTo(y, tmp, a[lda*i:lda*i+n], y[:n])
}
}
return
}
ix := kx
for i := 0; i < m; i++ {
tmp := alpha * x[ix]
if tmp != 0 {
f32.AxpyInc(tmp, a[lda*i:lda*i+n], y, uintptr(n), 1, uintptr(incY), 0, uintptr(ky))
}
ix += incX
}
}

View File

@ -1,58 +0,0 @@
// 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.bash
package gonum
import (
"math"
"gonum.org/v1/gonum/internal/math32"
)
type Implementation struct{}
// [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
)
// 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
}
// blocks returns the number of divisions of the dimension length with the given
// block size.
func blocks(dim, bsize int) int {
return (dim + bsize - 1) / bsize
}
// dcabs1 returns |real(z)|+|imag(z)|.
func dcabs1(z complex128) float64 {
return math.Abs(real(z)) + math.Abs(imag(z))
}
// scabs1 returns |real(z)|+|imag(z)|.
func scabs1(z complex64) float32 {
return math32.Abs(real(z)) + math32.Abs(imag(z))
}

View File

@ -1,445 +0,0 @@
// Copyright ©2017 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 gonum
import (
"math"
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/internal/asm/c128"
)
var _ blas.Complex128Level1 = Implementation{}
// Dzasum returns the sum of the absolute values of the elements of x
// \sum_i |Re(x[i])| + |Im(x[i])|
// Dzasum returns 0 if incX is negative.
func (Implementation) Dzasum(n int, x []complex128, incX int) float64 {
if n < 0 {
panic(nLT0)
}
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return 0
}
var sum float64
if incX == 1 {
if len(x) < n {
panic(shortX)
}
for _, v := range x[:n] {
sum += dcabs1(v)
}
return sum
}
if (n-1)*incX >= len(x) {
panic(shortX)
}
for i := 0; i < n; i++ {
v := x[i*incX]
sum += dcabs1(v)
}
return sum
}
// Dznrm2 computes the Euclidean norm of the complex vector x,
// ‖x‖_2 = sqrt(\sum_i x[i] * conj(x[i])).
// This function returns 0 if incX is negative.
func (Implementation) Dznrm2(n int, x []complex128, incX int) float64 {
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return 0
}
if n < 1 {
if n == 0 {
return 0
}
panic(nLT0)
}
if (n-1)*incX >= len(x) {
panic(shortX)
}
var (
scale float64
ssq float64 = 1
)
if incX == 1 {
for _, v := range x[:n] {
re, im := math.Abs(real(v)), math.Abs(imag(v))
if re != 0 {
if re > scale {
ssq = 1 + ssq*(scale/re)*(scale/re)
scale = re
} else {
ssq += (re / scale) * (re / scale)
}
}
if im != 0 {
if im > scale {
ssq = 1 + ssq*(scale/im)*(scale/im)
scale = im
} else {
ssq += (im / scale) * (im / scale)
}
}
}
if math.IsInf(scale, 1) {
return math.Inf(1)
}
return scale * math.Sqrt(ssq)
}
for ix := 0; ix < n*incX; ix += incX {
re, im := math.Abs(real(x[ix])), math.Abs(imag(x[ix]))
if re != 0 {
if re > scale {
ssq = 1 + ssq*(scale/re)*(scale/re)
scale = re
} else {
ssq += (re / scale) * (re / scale)
}
}
if im != 0 {
if im > scale {
ssq = 1 + ssq*(scale/im)*(scale/im)
scale = im
} else {
ssq += (im / scale) * (im / scale)
}
}
}
if math.IsInf(scale, 1) {
return math.Inf(1)
}
return scale * math.Sqrt(ssq)
}
// Izamax returns the index of the first element of x having largest |Re(·)|+|Im(·)|.
// Izamax returns -1 if n is 0 or incX is negative.
func (Implementation) Izamax(n int, x []complex128, incX int) int {
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
// Return invalid index.
return -1
}
if n < 1 {
if n == 0 {
// Return invalid index.
return -1
}
panic(nLT0)
}
if len(x) <= (n-1)*incX {
panic(shortX)
}
idx := 0
max := dcabs1(x[0])
if incX == 1 {
for i, v := range x[1:n] {
absV := dcabs1(v)
if absV > max {
max = absV
idx = i + 1
}
}
return idx
}
ix := incX
for i := 1; i < n; i++ {
absV := dcabs1(x[ix])
if absV > max {
max = absV
idx = i
}
ix += incX
}
return idx
}
// Zaxpy adds alpha times x to y:
// y[i] += alpha * x[i] for all i
func (Implementation) Zaxpy(n int, alpha complex128, x []complex128, incX int, y []complex128, incY int) {
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
panic(shortX)
}
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
panic(shortY)
}
if alpha == 0 {
return
}
if incX == 1 && incY == 1 {
c128.AxpyUnitary(alpha, x[:n], y[:n])
return
}
var ix, iy int
if incX < 0 {
ix = (1 - n) * incX
}
if incY < 0 {
iy = (1 - n) * incY
}
c128.AxpyInc(alpha, x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
}
// Zcopy copies the vector x to vector y.
func (Implementation) Zcopy(n int, x []complex128, incX int, y []complex128, incY int) {
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
panic(shortX)
}
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
panic(shortY)
}
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
}
}
// Zdotc computes the dot product
// xᴴ · y
// of two complex vectors x and y.
func (Implementation) Zdotc(n int, x []complex128, incX int, y []complex128, incY int) complex128 {
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n <= 0 {
if n == 0 {
return 0
}
panic(nLT0)
}
if incX == 1 && incY == 1 {
if len(x) < n {
panic(shortX)
}
if len(y) < n {
panic(shortY)
}
return c128.DotcUnitary(x[:n], y[:n])
}
var ix, iy int
if incX < 0 {
ix = (-n + 1) * incX
}
if incY < 0 {
iy = (-n + 1) * incY
}
if ix >= len(x) || (n-1)*incX >= len(x) {
panic(shortX)
}
if iy >= len(y) || (n-1)*incY >= len(y) {
panic(shortY)
}
return c128.DotcInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
}
// Zdotu computes the dot product
// xᵀ · y
// of two complex vectors x and y.
func (Implementation) Zdotu(n int, x []complex128, incX int, y []complex128, incY int) complex128 {
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n <= 0 {
if n == 0 {
return 0
}
panic(nLT0)
}
if incX == 1 && incY == 1 {
if len(x) < n {
panic(shortX)
}
if len(y) < n {
panic(shortY)
}
return c128.DotuUnitary(x[:n], y[:n])
}
var ix, iy int
if incX < 0 {
ix = (-n + 1) * incX
}
if incY < 0 {
iy = (-n + 1) * incY
}
if ix >= len(x) || (n-1)*incX >= len(x) {
panic(shortX)
}
if iy >= len(y) || (n-1)*incY >= len(y) {
panic(shortY)
}
return c128.DotuInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
}
// Zdscal scales the vector x by a real scalar alpha.
// Zdscal has no effect if incX < 0.
func (Implementation) Zdscal(n int, alpha float64, x []complex128, incX int) {
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return
}
if (n-1)*incX >= len(x) {
panic(shortX)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if alpha == 0 {
if incX == 1 {
x = x[:n]
for i := range x {
x[i] = 0
}
return
}
for ix := 0; ix < n*incX; ix += incX {
x[ix] = 0
}
return
}
if incX == 1 {
x = x[:n]
for i, v := range x {
x[i] = complex(alpha*real(v), alpha*imag(v))
}
return
}
for ix := 0; ix < n*incX; ix += incX {
v := x[ix]
x[ix] = complex(alpha*real(v), alpha*imag(v))
}
}
// Zscal scales the vector x by a complex scalar alpha.
// Zscal has no effect if incX < 0.
func (Implementation) Zscal(n int, alpha complex128, x []complex128, incX int) {
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return
}
if (n-1)*incX >= len(x) {
panic(shortX)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if alpha == 0 {
if incX == 1 {
x = x[:n]
for i := range x {
x[i] = 0
}
return
}
for ix := 0; ix < n*incX; ix += incX {
x[ix] = 0
}
return
}
if incX == 1 {
c128.ScalUnitary(alpha, x[:n])
return
}
c128.ScalInc(alpha, x, uintptr(n), uintptr(incX))
}
// Zswap exchanges the elements of two complex vectors x and y.
func (Implementation) Zswap(n int, x []complex128, incX int, y []complex128, incY int) {
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
panic(shortX)
}
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
panic(shortY)
}
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
}
}

View File

@ -1,467 +0,0 @@
// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.
// Copyright ©2017 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 gonum
import (
math "gonum.org/v1/gonum/internal/math32"
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/internal/asm/c64"
)
var _ blas.Complex64Level1 = Implementation{}
// Scasum returns the sum of the absolute values of the elements of x
// \sum_i |Re(x[i])| + |Im(x[i])|
// Scasum returns 0 if incX is negative.
//
// Complex64 implementations are autogenerated and not directly tested.
func (Implementation) Scasum(n int, x []complex64, incX int) float32 {
if n < 0 {
panic(nLT0)
}
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return 0
}
var sum float32
if incX == 1 {
if len(x) < n {
panic(shortX)
}
for _, v := range x[:n] {
sum += scabs1(v)
}
return sum
}
if (n-1)*incX >= len(x) {
panic(shortX)
}
for i := 0; i < n; i++ {
v := x[i*incX]
sum += scabs1(v)
}
return sum
}
// Scnrm2 computes the Euclidean norm of the complex vector x,
// ‖x‖_2 = sqrt(\sum_i x[i] * conj(x[i])).
// This function returns 0 if incX is negative.
//
// Complex64 implementations are autogenerated and not directly tested.
func (Implementation) Scnrm2(n int, x []complex64, incX int) float32 {
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return 0
}
if n < 1 {
if n == 0 {
return 0
}
panic(nLT0)
}
if (n-1)*incX >= len(x) {
panic(shortX)
}
var (
scale float32
ssq float32 = 1
)
if incX == 1 {
for _, v := range x[:n] {
re, im := math.Abs(real(v)), math.Abs(imag(v))
if re != 0 {
if re > scale {
ssq = 1 + ssq*(scale/re)*(scale/re)
scale = re
} else {
ssq += (re / scale) * (re / scale)
}
}
if im != 0 {
if im > scale {
ssq = 1 + ssq*(scale/im)*(scale/im)
scale = im
} else {
ssq += (im / scale) * (im / scale)
}
}
}
if math.IsInf(scale, 1) {
return math.Inf(1)
}
return scale * math.Sqrt(ssq)
}
for ix := 0; ix < n*incX; ix += incX {
re, im := math.Abs(real(x[ix])), math.Abs(imag(x[ix]))
if re != 0 {
if re > scale {
ssq = 1 + ssq*(scale/re)*(scale/re)
scale = re
} else {
ssq += (re / scale) * (re / scale)
}
}
if im != 0 {
if im > scale {
ssq = 1 + ssq*(scale/im)*(scale/im)
scale = im
} else {
ssq += (im / scale) * (im / scale)
}
}
}
if math.IsInf(scale, 1) {
return math.Inf(1)
}
return scale * math.Sqrt(ssq)
}
// Icamax returns the index of the first element of x having largest |Re(·)|+|Im(·)|.
// Icamax returns -1 if n is 0 or incX is negative.
//
// Complex64 implementations are autogenerated and not directly tested.
func (Implementation) Icamax(n int, x []complex64, incX int) int {
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
// Return invalid index.
return -1
}
if n < 1 {
if n == 0 {
// Return invalid index.
return -1
}
panic(nLT0)
}
if len(x) <= (n-1)*incX {
panic(shortX)
}
idx := 0
max := scabs1(x[0])
if incX == 1 {
for i, v := range x[1:n] {
absV := scabs1(v)
if absV > max {
max = absV
idx = i + 1
}
}
return idx
}
ix := incX
for i := 1; i < n; i++ {
absV := scabs1(x[ix])
if absV > max {
max = absV
idx = i
}
ix += incX
}
return idx
}
// Caxpy adds alpha times x to y:
// y[i] += alpha * x[i] for all i
//
// Complex64 implementations are autogenerated and not directly tested.
func (Implementation) Caxpy(n int, alpha complex64, x []complex64, incX int, y []complex64, incY int) {
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
panic(shortX)
}
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
panic(shortY)
}
if alpha == 0 {
return
}
if incX == 1 && incY == 1 {
c64.AxpyUnitary(alpha, x[:n], y[:n])
return
}
var ix, iy int
if incX < 0 {
ix = (1 - n) * incX
}
if incY < 0 {
iy = (1 - n) * incY
}
c64.AxpyInc(alpha, x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
}
// Ccopy copies the vector x to vector y.
//
// Complex64 implementations are autogenerated and not directly tested.
func (Implementation) Ccopy(n int, x []complex64, incX int, y []complex64, incY int) {
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
panic(shortX)
}
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
panic(shortY)
}
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
}
}
// Cdotc computes the dot product
// xᴴ · y
// of two complex vectors x and y.
//
// Complex64 implementations are autogenerated and not directly tested.
func (Implementation) Cdotc(n int, x []complex64, incX int, y []complex64, incY int) complex64 {
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n <= 0 {
if n == 0 {
return 0
}
panic(nLT0)
}
if incX == 1 && incY == 1 {
if len(x) < n {
panic(shortX)
}
if len(y) < n {
panic(shortY)
}
return c64.DotcUnitary(x[:n], y[:n])
}
var ix, iy int
if incX < 0 {
ix = (-n + 1) * incX
}
if incY < 0 {
iy = (-n + 1) * incY
}
if ix >= len(x) || (n-1)*incX >= len(x) {
panic(shortX)
}
if iy >= len(y) || (n-1)*incY >= len(y) {
panic(shortY)
}
return c64.DotcInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
}
// Cdotu computes the dot product
// xᵀ · y
// of two complex vectors x and y.
//
// Complex64 implementations are autogenerated and not directly tested.
func (Implementation) Cdotu(n int, x []complex64, incX int, y []complex64, incY int) complex64 {
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n <= 0 {
if n == 0 {
return 0
}
panic(nLT0)
}
if incX == 1 && incY == 1 {
if len(x) < n {
panic(shortX)
}
if len(y) < n {
panic(shortY)
}
return c64.DotuUnitary(x[:n], y[:n])
}
var ix, iy int
if incX < 0 {
ix = (-n + 1) * incX
}
if incY < 0 {
iy = (-n + 1) * incY
}
if ix >= len(x) || (n-1)*incX >= len(x) {
panic(shortX)
}
if iy >= len(y) || (n-1)*incY >= len(y) {
panic(shortY)
}
return c64.DotuInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
}
// Csscal scales the vector x by a real scalar alpha.
// Csscal has no effect if incX < 0.
//
// Complex64 implementations are autogenerated and not directly tested.
func (Implementation) Csscal(n int, alpha float32, x []complex64, incX int) {
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return
}
if (n-1)*incX >= len(x) {
panic(shortX)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if alpha == 0 {
if incX == 1 {
x = x[:n]
for i := range x {
x[i] = 0
}
return
}
for ix := 0; ix < n*incX; ix += incX {
x[ix] = 0
}
return
}
if incX == 1 {
x = x[:n]
for i, v := range x {
x[i] = complex(alpha*real(v), alpha*imag(v))
}
return
}
for ix := 0; ix < n*incX; ix += incX {
v := x[ix]
x[ix] = complex(alpha*real(v), alpha*imag(v))
}
}
// Cscal scales the vector x by a complex scalar alpha.
// Cscal has no effect if incX < 0.
//
// Complex64 implementations are autogenerated and not directly tested.
func (Implementation) Cscal(n int, alpha complex64, x []complex64, incX int) {
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return
}
if (n-1)*incX >= len(x) {
panic(shortX)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if alpha == 0 {
if incX == 1 {
x = x[:n]
for i := range x {
x[i] = 0
}
return
}
for ix := 0; ix < n*incX; ix += incX {
x[ix] = 0
}
return
}
if incX == 1 {
c64.ScalUnitary(alpha, x[:n])
return
}
c64.ScalInc(alpha, x, uintptr(n), uintptr(incX))
}
// Cswap exchanges the elements of two complex vectors x and y.
//
// Complex64 implementations are autogenerated and not directly tested.
func (Implementation) Cswap(n int, x []complex64, incX int, y []complex64, incY int) {
if incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) {
panic(shortX)
}
if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) {
panic(shortY)
}
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
}
}

View File

@ -1,644 +0,0 @@
// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.
// 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 gonum
import (
math "gonum.org/v1/gonum/internal/math32"
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/internal/asm/f32"
)
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 len(x) <= (n-1)*incX {
panic(shortX)
}
if n < 2 {
if n == 1 {
return math.Abs(x[0])
}
if n == 0 {
return 0
}
panic(nLT0)
}
var (
scale float32 = 0
sumSquares float32 = 1
)
if incX == 1 {
x = x[:n]
for _, v := range x {
if v == 0 {
continue
}
absxi := math.Abs(v)
if math.IsNaN(absxi) {
return math.NaN()
}
if scale < absxi {
sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi)
scale = absxi
} else {
sumSquares = sumSquares + (absxi/scale)*(absxi/scale)
}
}
if math.IsInf(scale, 1) {
return math.Inf(1)
}
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 math.IsNaN(absxi) {
return math.NaN()
}
if scale < absxi {
sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi)
scale = absxi
} else {
sumSquares = sumSquares + (absxi/scale)*(absxi/scale)
}
}
if math.IsInf(scale, 1) {
return math.Inf(1)
}
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(nLT0)
}
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return 0
}
if len(x) <= (n-1)*incX {
panic(shortX)
}
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 an element of x with the largest absolute value.
// If there are multiple such indices the earliest is returned.
// Isamax returns -1 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 len(x) <= (n-1)*incX {
panic(shortX)
}
if n < 2 {
if n == 1 {
return 0
}
if n == 0 {
return -1 // Netlib returns invalid index when n == 0.
}
panic(nLT0)
}
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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
panic(shortX)
}
if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
panic(shortY)
}
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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
panic(shortX)
}
if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
panic(shortY)
}
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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
panic(shortX)
}
if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
panic(shortY)
}
if alpha == 0 {
return
}
if incX == 1 && incY == 1 {
f32.AxpyUnitary(alpha, x[:n], y[:n])
return
}
var ix, iy int
if incX < 0 {
ix = (-n + 1) * incX
}
if incY < 0 {
iy = (-n + 1) * incY
}
f32.AxpyInc(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 reference 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) {
// The implementation of Drotmg used here is taken from Hopkins 1997
// Appendix A: https://doi.org/10.1145/289251.289253
// with the exception of the gam constants below.
const (
gam = 4096.0
gamsq = gam * gam
rgamsq = 1.0 / gamsq
)
if d1 < 0 {
p.Flag = blas.Rescaling // Error state.
return p, 0, 0, 0
}
if d2 == 0 || y1 == 0 {
p.Flag = blas.Identity
return p, d1, d2, x1
}
var h11, h12, h21, h22 float32
if (d1 == 0 || x1 == 0) && d2 > 0 {
p.Flag = blas.Diagonal
h12 = 1
h21 = -1
x1 = y1
d1, d2 = d2, d1
} else {
p2 := d2 * y1
p1 := d1 * x1
q2 := p2 * y1
q1 := p1 * x1
if math.Abs(q1) > math.Abs(q2) {
p.Flag = blas.OffDiagonal
h11 = 1
h22 = 1
h21 = -y1 / x1
h12 = p2 / p1
u := 1 - h12*h21
if u <= 0 {
p.Flag = blas.Rescaling // Error state.
return p, 0, 0, 0
}
d1 /= u
d2 /= u
x1 *= u
} else {
if q2 < 0 {
p.Flag = blas.Rescaling // Error state.
return p, 0, 0, 0
}
p.Flag = blas.Diagonal
h21 = -1
h12 = 1
h11 = p1 / p2
h22 = x1 / y1
u := 1 + h11*h22
d1, d2 = d2/u, d1/u
x1 = y1 * u
}
}
for d1 <= rgamsq && d1 != 0 {
p.Flag = blas.Rescaling
d1 = (d1 * gam) * gam
x1 /= gam
h11 /= gam
h12 /= gam
}
for d1 > gamsq {
p.Flag = blas.Rescaling
d1 = (d1 / gam) / gam
x1 *= gam
h11 *= gam
h12 *= gam
}
for math.Abs(d2) <= rgamsq && d2 != 0 {
p.Flag = blas.Rescaling
d2 = (d2 * gam) * gam
h21 /= gam
h22 /= gam
}
for math.Abs(d2) > gamsq {
p.Flag = blas.Rescaling
d2 = (d2 / gam) / gam
h21 *= gam
h22 *= gam
}
switch p.Flag {
case blas.Diagonal:
p.H = [4]float32{0: h11, 3: h22}
case blas.OffDiagonal:
p.H = [4]float32{1: h21, 2: h12}
case blas.Rescaling:
p.H = [4]float32{h11, h21, h12, h22}
default:
panic(badFlag)
}
return p, d1, d2, x1
}
// 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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
panic(shortX)
}
if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
panic(shortY)
}
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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n <= 0 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
panic(shortX)
}
if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
panic(shortY)
}
if p.Flag == blas.Identity {
return
}
switch p.Flag {
case blas.Rescaling:
h11 := p.H[0]
h12 := p.H[2]
h21 := p.H[1]
h22 := p.H[3]
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
}
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] = vx*h11+vy*h12, vx*h21+vy*h22
ix += incX
iy += incY
}
case blas.OffDiagonal:
h12 := p.H[2]
h21 := p.H[1]
if incX == 1 && incY == 1 {
x = x[:n]
for i, vx := range x {
vy := y[i]
x[i], y[i] = vx+vy*h12, vx*h21+vy
}
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] = vx+vy*h12, vx*h21+vy
ix += incX
iy += incY
}
case blas.Diagonal:
h11 := p.H[0]
h22 := p.H[3]
if incX == 1 && incY == 1 {
x = x[:n]
for i, vx := range x {
vy := y[i]
x[i], y[i] = vx*h11+vy, -vx+vy*h22
}
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] = vx*h11+vy, -vx+vy*h22
ix += incX
iy += incY
}
}
}
// 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 n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (n-1)*incX >= len(x) {
panic(shortX)
}
if alpha == 0 {
if incX == 1 {
x = x[:n]
for i := range x {
x[i] = 0
}
return
}
for ix := 0; ix < n*incX; ix += incX {
x[ix] = 0
}
return
}
if incX == 1 {
f32.ScalUnitary(alpha, x[:n])
return
}
f32.ScalInc(alpha, x, uintptr(n), uintptr(incX))
}

View File

@ -1,53 +0,0 @@
// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.
// 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 gonum
import (
"gonum.org/v1/gonum/internal/asm/f32"
)
// 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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n <= 0 {
if n == 0 {
return 0
}
panic(nLT0)
}
if incX == 1 && incY == 1 {
if len(x) < n {
panic(shortX)
}
if len(y) < n {
panic(shortY)
}
return f32.DdotUnitary(x[:n], y[:n])
}
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(shortX)
}
if iy >= len(y) || iy+(n-1)*incY >= len(y) {
panic(shortY)
}
return f32.DdotInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
}

View File

@ -1,53 +0,0 @@
// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.
// 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 gonum
import (
"gonum.org/v1/gonum/internal/asm/f32"
)
// 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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n <= 0 {
if n == 0 {
return 0
}
panic(nLT0)
}
if incX == 1 && incY == 1 {
if len(x) < n {
panic(shortX)
}
if len(y) < n {
panic(shortY)
}
return f32.DotUnitary(x[:n], y[:n])
}
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(shortX)
}
if iy >= len(y) || iy+(n-1)*incY >= len(y) {
panic(shortY)
}
return f32.DotInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
}

View File

@ -1,53 +0,0 @@
// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.
// 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 gonum
import (
"gonum.org/v1/gonum/internal/asm/f32"
)
// 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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n <= 0 {
if n == 0 {
return 0
}
panic(nLT0)
}
if incX == 1 && incY == 1 {
if len(x) < n {
panic(shortX)
}
if len(y) < n {
panic(shortY)
}
return alpha + float32(f32.DdotUnitary(x[:n], y[:n]))
}
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(shortX)
}
if iy >= len(y) || iy+(n-1)*incY >= len(y) {
panic(shortY)
}
return alpha + float32(f32.DdotInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy)))
}

View File

@ -1,620 +0,0 @@
// 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 gonum
import (
"math"
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/internal/asm/f64"
)
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 len(x) <= (n-1)*incX {
panic(shortX)
}
if n < 2 {
if n == 1 {
return math.Abs(x[0])
}
if n == 0 {
return 0
}
panic(nLT0)
}
var (
scale float64 = 0
sumSquares float64 = 1
)
if incX == 1 {
x = x[:n]
for _, v := range x {
if v == 0 {
continue
}
absxi := math.Abs(v)
if math.IsNaN(absxi) {
return math.NaN()
}
if scale < absxi {
sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi)
scale = absxi
} else {
sumSquares = sumSquares + (absxi/scale)*(absxi/scale)
}
}
if math.IsInf(scale, 1) {
return math.Inf(1)
}
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 math.IsNaN(absxi) {
return math.NaN()
}
if scale < absxi {
sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi)
scale = absxi
} else {
sumSquares = sumSquares + (absxi/scale)*(absxi/scale)
}
}
if math.IsInf(scale, 1) {
return math.Inf(1)
}
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(nLT0)
}
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return 0
}
if len(x) <= (n-1)*incX {
panic(shortX)
}
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 an element of x with the largest absolute value.
// If there are multiple such indices the earliest is returned.
// Idamax returns -1 if n == 0.
func (Implementation) Idamax(n int, x []float64, incX int) int {
if incX < 1 {
if incX == 0 {
panic(zeroIncX)
}
return -1
}
if len(x) <= (n-1)*incX {
panic(shortX)
}
if n < 2 {
if n == 1 {
return 0
}
if n == 0 {
return -1 // Netlib returns invalid index when n == 0.
}
panic(nLT0)
}
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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
panic(shortX)
}
if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
panic(shortY)
}
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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
panic(shortX)
}
if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
panic(shortY)
}
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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
panic(shortX)
}
if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
panic(shortY)
}
if alpha == 0 {
return
}
if incX == 1 && incY == 1 {
f64.AxpyUnitary(alpha, x[:n], y[:n])
return
}
var ix, iy int
if incX < 0 {
ix = (-n + 1) * incX
}
if incY < 0 {
iy = (-n + 1) * incY
}
f64.AxpyInc(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 reference 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) {
// The implementation of Drotmg used here is taken from Hopkins 1997
// Appendix A: https://doi.org/10.1145/289251.289253
// with the exception of the gam constants below.
const (
gam = 4096.0
gamsq = gam * gam
rgamsq = 1.0 / gamsq
)
if d1 < 0 {
p.Flag = blas.Rescaling // Error state.
return p, 0, 0, 0
}
if d2 == 0 || y1 == 0 {
p.Flag = blas.Identity
return p, d1, d2, x1
}
var h11, h12, h21, h22 float64
if (d1 == 0 || x1 == 0) && d2 > 0 {
p.Flag = blas.Diagonal
h12 = 1
h21 = -1
x1 = y1
d1, d2 = d2, d1
} else {
p2 := d2 * y1
p1 := d1 * x1
q2 := p2 * y1
q1 := p1 * x1
if math.Abs(q1) > math.Abs(q2) {
p.Flag = blas.OffDiagonal
h11 = 1
h22 = 1
h21 = -y1 / x1
h12 = p2 / p1
u := 1 - h12*h21
if u <= 0 {
p.Flag = blas.Rescaling // Error state.
return p, 0, 0, 0
}
d1 /= u
d2 /= u
x1 *= u
} else {
if q2 < 0 {
p.Flag = blas.Rescaling // Error state.
return p, 0, 0, 0
}
p.Flag = blas.Diagonal
h21 = -1
h12 = 1
h11 = p1 / p2
h22 = x1 / y1
u := 1 + h11*h22
d1, d2 = d2/u, d1/u
x1 = y1 * u
}
}
for d1 <= rgamsq && d1 != 0 {
p.Flag = blas.Rescaling
d1 = (d1 * gam) * gam
x1 /= gam
h11 /= gam
h12 /= gam
}
for d1 > gamsq {
p.Flag = blas.Rescaling
d1 = (d1 / gam) / gam
x1 *= gam
h11 *= gam
h12 *= gam
}
for math.Abs(d2) <= rgamsq && d2 != 0 {
p.Flag = blas.Rescaling
d2 = (d2 * gam) * gam
h21 /= gam
h22 /= gam
}
for math.Abs(d2) > gamsq {
p.Flag = blas.Rescaling
d2 = (d2 / gam) / gam
h21 *= gam
h22 *= gam
}
switch p.Flag {
case blas.Diagonal:
p.H = [4]float64{0: h11, 3: h22}
case blas.OffDiagonal:
p.H = [4]float64{1: h21, 2: h12}
case blas.Rescaling:
p.H = [4]float64{h11, h21, h12, h22}
default:
panic(badFlag)
}
return p, d1, d2, x1
}
// 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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
panic(shortX)
}
if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
panic(shortY)
}
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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n <= 0 {
if n == 0 {
return
}
panic(nLT0)
}
if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
panic(shortX)
}
if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
panic(shortY)
}
if p.Flag == blas.Identity {
return
}
switch p.Flag {
case blas.Rescaling:
h11 := p.H[0]
h12 := p.H[2]
h21 := p.H[1]
h22 := p.H[3]
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
}
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] = vx*h11+vy*h12, vx*h21+vy*h22
ix += incX
iy += incY
}
case blas.OffDiagonal:
h12 := p.H[2]
h21 := p.H[1]
if incX == 1 && incY == 1 {
x = x[:n]
for i, vx := range x {
vy := y[i]
x[i], y[i] = vx+vy*h12, vx*h21+vy
}
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] = vx+vy*h12, vx*h21+vy
ix += incX
iy += incY
}
case blas.Diagonal:
h11 := p.H[0]
h22 := p.H[3]
if incX == 1 && incY == 1 {
x = x[:n]
for i, vx := range x {
vy := y[i]
x[i], y[i] = vx*h11+vy, -vx+vy*h22
}
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] = vx*h11+vy, -vx+vy*h22
ix += incX
iy += incY
}
}
}
// 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 n < 1 {
if n == 0 {
return
}
panic(nLT0)
}
if (n-1)*incX >= len(x) {
panic(shortX)
}
if alpha == 0 {
if incX == 1 {
x = x[:n]
for i := range x {
x[i] = 0
}
return
}
for ix := 0; ix < n*incX; ix += incX {
x[ix] = 0
}
return
}
if incX == 1 {
f64.ScalUnitary(alpha, x[:n])
return
}
f64.ScalInc(alpha, x, uintptr(n), uintptr(incX))
}

View File

@ -1,49 +0,0 @@
// 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 gonum
import (
"gonum.org/v1/gonum/internal/asm/f64"
)
// 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 incX == 0 {
panic(zeroIncX)
}
if incY == 0 {
panic(zeroIncY)
}
if n <= 0 {
if n == 0 {
return 0
}
panic(nLT0)
}
if incX == 1 && incY == 1 {
if len(x) < n {
panic(shortX)
}
if len(y) < n {
panic(shortY)
}
return f64.DotUnitary(x[:n], y[:n])
}
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(shortX)
}
if iy >= len(y) || iy+(n-1)*incY >= len(y) {
panic(shortY)
}
return f64.DotInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,876 +0,0 @@
// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.
// 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 gonum
import (
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/internal/asm/f32"
)
var _ blas.Float32Level3 = Implementation{}
// Strsm solves one of the matrix equations
// A * X = alpha * B if tA == blas.NoTrans and side == blas.Left
// Aᵀ * 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ᵀ = alpha * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Right
// where A is an n×n or m×m triangular matrix, X and B are m×n matrices, 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)
}
k := n
if s == blas.Left {
k = m
}
if lda < max(1, k) {
panic(badLdA)
}
if ldb < max(1, n) {
panic(badLdB)
}
// Quick return if possible.
if m == 0 || n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if len(a) < lda*(k-1)+k {
panic(shortA)
}
if len(b) < ldb*(m-1)+n {
panic(shortB)
}
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 {
f32.ScalUnitary(alpha, btmp)
}
for ka, va := range a[i*lda+i+1 : i*lda+m] {
if va != 0 {
k := ka + i + 1
f32.AxpyUnitary(-va, b[k*ldb:k*ldb+n], btmp)
}
}
if nonUnit {
tmp := 1 / a[i*lda+i]
f32.ScalUnitary(tmp, btmp)
}
}
return
}
for i := 0; i < m; i++ {
btmp := b[i*ldb : i*ldb+n]
if alpha != 1 {
f32.ScalUnitary(alpha, btmp)
}
for k, va := range a[i*lda : i*lda+i] {
if va != 0 {
f32.AxpyUnitary(-va, b[k*ldb:k*ldb+n], btmp)
}
}
if nonUnit {
tmp := 1 / a[i*lda+i]
f32.ScalUnitary(tmp, btmp)
}
}
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]
f32.ScalUnitary(tmp, btmpk)
}
for ia, va := range a[k*lda+k+1 : k*lda+m] {
if va != 0 {
i := ia + k + 1
f32.AxpyUnitary(-va, btmpk, b[i*ldb:i*ldb+n])
}
}
if alpha != 1 {
f32.ScalUnitary(alpha, btmpk)
}
}
return
}
for k := m - 1; k >= 0; k-- {
btmpk := b[k*ldb : k*ldb+n]
if nonUnit {
tmp := 1 / a[k*lda+k]
f32.ScalUnitary(tmp, btmpk)
}
for i, va := range a[k*lda : k*lda+k] {
if va != 0 {
f32.AxpyUnitary(-va, btmpk, b[i*ldb:i*ldb+n])
}
}
if alpha != 1 {
f32.ScalUnitary(alpha, btmpk)
}
}
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 {
f32.ScalUnitary(alpha, btmp)
}
for k, vb := range btmp {
if vb == 0 {
continue
}
if nonUnit {
btmp[k] /= a[k*lda+k]
}
f32.AxpyUnitary(-btmp[k], a[k*lda+k+1:k*lda+n], btmp[k+1:n])
}
}
return
}
for i := 0; i < m; i++ {
btmp := b[i*ldb : i*ldb+n]
if alpha != 1 {
f32.ScalUnitary(alpha, btmp)
}
for k := n - 1; k >= 0; k-- {
if btmp[k] == 0 {
continue
}
if nonUnit {
btmp[k] /= a[k*lda+k]
}
f32.AxpyUnitary(-btmp[k], a[k*lda:k*lda+k], btmp[:k])
}
}
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 := n - 1; j >= 0; j-- {
tmp := alpha*btmp[j] - f32.DotUnitary(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*ldb : i*ldb+n]
for j := 0; j < n; j++ {
tmp := alpha*btmp[j] - f32.DotUnitary(a[j*lda:j*lda+j], btmp[:j])
if nonUnit {
tmp /= a[j*lda+j]
}
btmp[j] = tmp
}
}
}
// Ssymm performs one of the matrix-matrix operations
// 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 or m×m 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(badSide)
}
if ul != blas.Lower && ul != blas.Upper {
panic(badUplo)
}
if m < 0 {
panic(mLT0)
}
if n < 0 {
panic(nLT0)
}
k := n
if s == blas.Left {
k = m
}
if lda < max(1, k) {
panic(badLdA)
}
if ldb < max(1, n) {
panic(badLdB)
}
if ldc < max(1, n) {
panic(badLdC)
}
// Quick return if possible.
if m == 0 || n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if len(a) < lda*(k-1)+k {
panic(shortA)
}
if len(b) < ldb*(m-1)+n {
panic(shortB)
}
if len(c) < ldc*(m-1)+n {
panic(shortC)
}
// Quick return if possible.
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
f32.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], 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
f32.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], 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 one of the symmetric rank-k operations
// C = alpha * A * Aᵀ + beta * C if tA == blas.NoTrans
// C = alpha * Aᵀ * A + beta * C if tA == blas.Trans or tA == blas.ConjTrans
// where A is an n×k or k×n matrix, C is an n×n symmetric matrix, and 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)
}
row, col := k, n
if tA == blas.NoTrans {
row, col = n, k
}
if lda < max(1, col) {
panic(badLdA)
}
if ldc < max(1, n) {
panic(badLdC)
}
// Quick return if possible.
if n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if len(a) < lda*(row-1)+col {
panic(shortA)
}
if len(c) < ldc*(n-1)+n {
panic(shortC)
}
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]
if beta == 0 {
for jc := range ctmp {
j := jc + i
ctmp[jc] = alpha * f32.DotUnitary(atmp, a[j*lda:j*lda+k])
}
} else {
for jc, vc := range ctmp {
j := jc + i
ctmp[jc] = vc*beta + alpha*f32.DotUnitary(atmp, a[j*lda:j*lda+k])
}
}
}
return
}
for i := 0; i < n; i++ {
ctmp := c[i*ldc : i*ldc+i+1]
atmp := a[i*lda : i*lda+k]
if beta == 0 {
for j := range ctmp {
ctmp[j] = alpha * f32.DotUnitary(a[j*lda:j*lda+k], atmp)
}
} else {
for j, vc := range ctmp {
ctmp[j] = vc*beta + alpha*f32.DotUnitary(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 == 0 {
for j := range ctmp {
ctmp[j] = 0
}
} else 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 {
f32.AxpyUnitary(tmp, a[l*lda+i:l*lda+n], ctmp)
}
}
}
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++ {
tmp := alpha * a[l*lda+i]
if tmp != 0 {
f32.AxpyUnitary(tmp, a[l*lda:l*lda+i+1], ctmp)
}
}
}
}
// Ssyr2k performs one of the symmetric rank 2k operations
// C = alpha * A * Bᵀ + alpha * B * Aᵀ + beta * C if tA == blas.NoTrans
// C = alpha * Aᵀ * B + alpha * Bᵀ * A + beta * C if tA == blas.Trans or tA == blas.ConjTrans
// where A and B are n×k or k×n matrices, C is an n×n symmetric matrix, and
// 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)
}
row, col := k, n
if tA == blas.NoTrans {
row, col = n, k
}
if lda < max(1, col) {
panic(badLdA)
}
if ldb < max(1, col) {
panic(badLdB)
}
if ldc < max(1, n) {
panic(badLdC)
}
// Quick return if possible.
if n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if len(a) < lda*(row-1)+col {
panic(shortA)
}
if len(b) < ldb*(row-1)+col {
panic(shortB)
}
if len(c) < ldc*(n-1)+n {
panic(shortC)
}
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*ldb : i*ldb+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*ldb : i*ldb+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*ldb+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*ldb+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 one of the matrix-matrix operations
// B = alpha * A * B if tA == blas.NoTrans and side == blas.Left
// B = alpha * Aᵀ * 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ᵀ if tA == blas.Trans or blas.ConjTrans, and side == blas.Right
// where A is an n×n or m×m triangular matrix, B is an m×n matrix, and alpha is a scalar.
//
// 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)
}
k := n
if s == blas.Left {
k = m
}
if lda < max(1, k) {
panic(badLdA)
}
if ldb < max(1, n) {
panic(badLdB)
}
// Quick return if possible.
if m == 0 || n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if len(a) < lda*(k-1)+k {
panic(shortA)
}
if len(b) < ldb*(m-1)+n {
panic(shortB)
}
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]
f32.ScalUnitary(tmp, btmp)
for ka, va := range a[i*lda+i+1 : i*lda+m] {
k := ka + i + 1
if va != 0 {
f32.AxpyUnitary(alpha*va, b[k*ldb:k*ldb+n], 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]
f32.ScalUnitary(tmp, btmp)
for k, va := range a[i*lda : i*lda+i] {
if va != 0 {
f32.AxpyUnitary(alpha*va, b[k*ldb:k*ldb+n], 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]
if va != 0 {
f32.AxpyUnitary(alpha*va, btmpk, btmp)
}
}
tmp := alpha
if nonUnit {
tmp *= a[k*lda+k]
}
if tmp != 1 {
f32.ScalUnitary(tmp, btmpk)
}
}
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]
if va != 0 {
f32.AxpyUnitary(alpha*va, btmpk, btmp)
}
}
tmp := alpha
if nonUnit {
tmp *= a[k*lda+k]
}
if tmp != 1 {
f32.ScalUnitary(tmp, btmpk)
}
}
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 {
continue
}
btmp[k] = tmp
if nonUnit {
btmp[k] *= a[k*lda+k]
}
f32.AxpyUnitary(tmp, a[k*lda+k+1:k*lda+n], btmp[k+1:n])
}
}
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 {
continue
}
btmp[k] = tmp
if nonUnit {
btmp[k] *= a[k*lda+k]
}
f32.AxpyUnitary(tmp, a[k*lda:k*lda+k], btmp[:k])
}
}
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 += f32.DotUnitary(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 += f32.DotUnitary(a[j*lda:j*lda+j], btmp[:j])
btmp[j] = alpha * tmp
}
}
}

View File

@ -1,864 +0,0 @@
// 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 gonum
import (
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/internal/asm/f64"
)
var _ blas.Float64Level3 = Implementation{}
// Dtrsm solves one of the matrix equations
// A * X = alpha * B if tA == blas.NoTrans and side == blas.Left
// Aᵀ * 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ᵀ = alpha * B if tA == blas.Trans or blas.ConjTrans, and side == blas.Right
// where A is an n×n or m×m triangular matrix, X and B are m×n matrices, 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)
}
k := n
if s == blas.Left {
k = m
}
if lda < max(1, k) {
panic(badLdA)
}
if ldb < max(1, n) {
panic(badLdB)
}
// Quick return if possible.
if m == 0 || n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if len(a) < lda*(k-1)+k {
panic(shortA)
}
if len(b) < ldb*(m-1)+n {
panic(shortB)
}
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 {
f64.ScalUnitary(alpha, btmp)
}
for ka, va := range a[i*lda+i+1 : i*lda+m] {
if va != 0 {
k := ka + i + 1
f64.AxpyUnitary(-va, b[k*ldb:k*ldb+n], btmp)
}
}
if nonUnit {
tmp := 1 / a[i*lda+i]
f64.ScalUnitary(tmp, btmp)
}
}
return
}
for i := 0; i < m; i++ {
btmp := b[i*ldb : i*ldb+n]
if alpha != 1 {
f64.ScalUnitary(alpha, btmp)
}
for k, va := range a[i*lda : i*lda+i] {
if va != 0 {
f64.AxpyUnitary(-va, b[k*ldb:k*ldb+n], btmp)
}
}
if nonUnit {
tmp := 1 / a[i*lda+i]
f64.ScalUnitary(tmp, btmp)
}
}
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]
f64.ScalUnitary(tmp, btmpk)
}
for ia, va := range a[k*lda+k+1 : k*lda+m] {
if va != 0 {
i := ia + k + 1
f64.AxpyUnitary(-va, btmpk, b[i*ldb:i*ldb+n])
}
}
if alpha != 1 {
f64.ScalUnitary(alpha, btmpk)
}
}
return
}
for k := m - 1; k >= 0; k-- {
btmpk := b[k*ldb : k*ldb+n]
if nonUnit {
tmp := 1 / a[k*lda+k]
f64.ScalUnitary(tmp, btmpk)
}
for i, va := range a[k*lda : k*lda+k] {
if va != 0 {
f64.AxpyUnitary(-va, btmpk, b[i*ldb:i*ldb+n])
}
}
if alpha != 1 {
f64.ScalUnitary(alpha, btmpk)
}
}
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 {
f64.ScalUnitary(alpha, btmp)
}
for k, vb := range btmp {
if vb == 0 {
continue
}
if nonUnit {
btmp[k] /= a[k*lda+k]
}
f64.AxpyUnitary(-btmp[k], a[k*lda+k+1:k*lda+n], btmp[k+1:n])
}
}
return
}
for i := 0; i < m; i++ {
btmp := b[i*ldb : i*ldb+n]
if alpha != 1 {
f64.ScalUnitary(alpha, btmp)
}
for k := n - 1; k >= 0; k-- {
if btmp[k] == 0 {
continue
}
if nonUnit {
btmp[k] /= a[k*lda+k]
}
f64.AxpyUnitary(-btmp[k], a[k*lda:k*lda+k], btmp[:k])
}
}
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 := n - 1; j >= 0; j-- {
tmp := alpha*btmp[j] - f64.DotUnitary(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*ldb : i*ldb+n]
for j := 0; j < n; j++ {
tmp := alpha*btmp[j] - f64.DotUnitary(a[j*lda:j*lda+j], btmp[:j])
if nonUnit {
tmp /= a[j*lda+j]
}
btmp[j] = tmp
}
}
}
// Dsymm performs one of the matrix-matrix operations
// 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 or m×m 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(badSide)
}
if ul != blas.Lower && ul != blas.Upper {
panic(badUplo)
}
if m < 0 {
panic(mLT0)
}
if n < 0 {
panic(nLT0)
}
k := n
if s == blas.Left {
k = m
}
if lda < max(1, k) {
panic(badLdA)
}
if ldb < max(1, n) {
panic(badLdB)
}
if ldc < max(1, n) {
panic(badLdC)
}
// Quick return if possible.
if m == 0 || n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if len(a) < lda*(k-1)+k {
panic(shortA)
}
if len(b) < ldb*(m-1)+n {
panic(shortB)
}
if len(c) < ldc*(m-1)+n {
panic(shortC)
}
// Quick return if possible.
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
f64.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], 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
f64.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], 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 one of the symmetric rank-k operations
// C = alpha * A * Aᵀ + beta * C if tA == blas.NoTrans
// C = alpha * Aᵀ * A + beta * C if tA == blas.Trans or tA == blas.ConjTrans
// where A is an n×k or k×n matrix, C is an n×n symmetric matrix, and 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)
}
row, col := k, n
if tA == blas.NoTrans {
row, col = n, k
}
if lda < max(1, col) {
panic(badLdA)
}
if ldc < max(1, n) {
panic(badLdC)
}
// Quick return if possible.
if n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if len(a) < lda*(row-1)+col {
panic(shortA)
}
if len(c) < ldc*(n-1)+n {
panic(shortC)
}
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]
if beta == 0 {
for jc := range ctmp {
j := jc + i
ctmp[jc] = alpha * f64.DotUnitary(atmp, a[j*lda:j*lda+k])
}
} else {
for jc, vc := range ctmp {
j := jc + i
ctmp[jc] = vc*beta + alpha*f64.DotUnitary(atmp, a[j*lda:j*lda+k])
}
}
}
return
}
for i := 0; i < n; i++ {
ctmp := c[i*ldc : i*ldc+i+1]
atmp := a[i*lda : i*lda+k]
if beta == 0 {
for j := range ctmp {
ctmp[j] = alpha * f64.DotUnitary(a[j*lda:j*lda+k], atmp)
}
} else {
for j, vc := range ctmp {
ctmp[j] = vc*beta + alpha*f64.DotUnitary(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 == 0 {
for j := range ctmp {
ctmp[j] = 0
}
} else 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 {
f64.AxpyUnitary(tmp, a[l*lda+i:l*lda+n], ctmp)
}
}
}
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++ {
tmp := alpha * a[l*lda+i]
if tmp != 0 {
f64.AxpyUnitary(tmp, a[l*lda:l*lda+i+1], ctmp)
}
}
}
}
// Dsyr2k performs one of the symmetric rank 2k operations
// C = alpha * A * Bᵀ + alpha * B * Aᵀ + beta * C if tA == blas.NoTrans
// C = alpha * Aᵀ * B + alpha * Bᵀ * A + beta * C if tA == blas.Trans or tA == blas.ConjTrans
// where A and B are n×k or k×n matrices, C is an n×n symmetric matrix, and
// 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)
}
row, col := k, n
if tA == blas.NoTrans {
row, col = n, k
}
if lda < max(1, col) {
panic(badLdA)
}
if ldb < max(1, col) {
panic(badLdB)
}
if ldc < max(1, n) {
panic(badLdC)
}
// Quick return if possible.
if n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if len(a) < lda*(row-1)+col {
panic(shortA)
}
if len(b) < ldb*(row-1)+col {
panic(shortB)
}
if len(c) < ldc*(n-1)+n {
panic(shortC)
}
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*ldb : i*ldb+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*ldb : i*ldb+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*ldb+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*ldb+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 one of the matrix-matrix operations
// B = alpha * A * B if tA == blas.NoTrans and side == blas.Left
// B = alpha * Aᵀ * 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ᵀ if tA == blas.Trans or blas.ConjTrans, and side == blas.Right
// where A is an n×n or m×m triangular matrix, B is an m×n matrix, and alpha is a scalar.
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)
}
k := n
if s == blas.Left {
k = m
}
if lda < max(1, k) {
panic(badLdA)
}
if ldb < max(1, n) {
panic(badLdB)
}
// Quick return if possible.
if m == 0 || n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if len(a) < lda*(k-1)+k {
panic(shortA)
}
if len(b) < ldb*(m-1)+n {
panic(shortB)
}
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]
f64.ScalUnitary(tmp, btmp)
for ka, va := range a[i*lda+i+1 : i*lda+m] {
k := ka + i + 1
if va != 0 {
f64.AxpyUnitary(alpha*va, b[k*ldb:k*ldb+n], 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]
f64.ScalUnitary(tmp, btmp)
for k, va := range a[i*lda : i*lda+i] {
if va != 0 {
f64.AxpyUnitary(alpha*va, b[k*ldb:k*ldb+n], 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]
if va != 0 {
f64.AxpyUnitary(alpha*va, btmpk, btmp)
}
}
tmp := alpha
if nonUnit {
tmp *= a[k*lda+k]
}
if tmp != 1 {
f64.ScalUnitary(tmp, btmpk)
}
}
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]
if va != 0 {
f64.AxpyUnitary(alpha*va, btmpk, btmp)
}
}
tmp := alpha
if nonUnit {
tmp *= a[k*lda+k]
}
if tmp != 1 {
f64.ScalUnitary(tmp, btmpk)
}
}
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 {
continue
}
btmp[k] = tmp
if nonUnit {
btmp[k] *= a[k*lda+k]
}
f64.AxpyUnitary(tmp, a[k*lda+k+1:k*lda+n], btmp[k+1:n])
}
}
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 {
continue
}
btmp[k] = tmp
if nonUnit {
btmp[k] *= a[k*lda+k]
}
f64.AxpyUnitary(tmp, a[k*lda:k*lda+k], btmp[:k])
}
}
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 += f64.DotUnitary(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 += f64.DotUnitary(a[j*lda:j*lda+j], btmp[:j])
btmp[j] = alpha * tmp
}
}
}

View File

@ -1,318 +0,0 @@
// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.
// 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 gonum
import (
"runtime"
"sync"
"gonum.org/v1/gonum/blas"
"gonum.org/v1/gonum/internal/asm/f32"
)
// Sgemm performs one of the matrix-matrix operations
// C = alpha * A * B + beta * C
// C = alpha * Aᵀ * B + beta * C
// C = alpha * A * Bᵀ + beta * C
// C = alpha * Aᵀ * Bᵀ + beta * C
// where A is an m×k or k×m dense matrix, B is an n×k or k×n dense matrix, C is
// an m×n matrix, and alpha and beta are scalars. tA and tB specify whether A or
// B are transposed.
//
// 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) {
switch tA {
default:
panic(badTranspose)
case blas.NoTrans, blas.Trans, blas.ConjTrans:
}
switch tB {
default:
panic(badTranspose)
case blas.NoTrans, blas.Trans, blas.ConjTrans:
}
if m < 0 {
panic(mLT0)
}
if n < 0 {
panic(nLT0)
}
if k < 0 {
panic(kLT0)
}
aTrans := tA == blas.Trans || tA == blas.ConjTrans
if aTrans {
if lda < max(1, m) {
panic(badLdA)
}
} else {
if lda < max(1, k) {
panic(badLdA)
}
}
bTrans := tB == blas.Trans || tB == blas.ConjTrans
if bTrans {
if ldb < max(1, k) {
panic(badLdB)
}
} else {
if ldb < max(1, n) {
panic(badLdB)
}
}
if ldc < max(1, n) {
panic(badLdC)
}
// Quick return if possible.
if m == 0 || n == 0 {
return
}
// For zero matrix size the following slice length checks are trivially satisfied.
if aTrans {
if len(a) < (k-1)*lda+m {
panic(shortA)
}
} else {
if len(a) < (m-1)*lda+k {
panic(shortA)
}
}
if bTrans {
if len(b) < (n-1)*ldb+k {
panic(shortB)
}
} else {
if len(b) < (k-1)*ldb+n {
panic(shortB)
}
}
if len(c) < (m-1)*ldc+n {
panic(shortC)
}
// Quick return if possible.
if (alpha == 0 || k == 0) && beta == 1 {
return
}
// scale c
if beta != 1 {
if beta == 0 {
for i := 0; i < m; i++ {
ctmp := c[i*ldc : i*ldc+n]
for j := range ctmp {
ctmp[j] = 0
}
}
} else {
for i := 0; i < m; i++ {
ctmp := c[i*ldc : i*ldc+n]
for j := range ctmp {
ctmp[j] *= beta
}
}
}
}
sgemmParallel(aTrans, bTrans, m, n, k, a, lda, b, ldb, c, ldc, alpha)
}
func sgemmParallel(aTrans, bTrans bool, m, n, k int, a []float32, lda int, b []float32, ldb int, c []float32, ldc int, 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ᵀ * B)
// Cij = \sum_k Aik Bjk, (A * Bᵀ)
// Cij = \sum_k Aki Bjk, (Aᵀ * Bᵀ)
//
// 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.
maxKLen := k
parBlocks := blocks(m, blockSize) * blocks(n, blockSize)
if parBlocks < minParBlock {
// The matrix multiplication is small in the dimensions where it can be
// computed concurrently. Just do it in serial.
sgemmSerial(aTrans, bTrans, m, n, k, a, lda, b, ldb, c, ldc, 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()
for sub := range sendChan {
i := sub.i
j := sub.j
leni := blockSize
if i+leni > m {
leni = m - i
}
lenj := blockSize
if j+lenj > n {
lenj = n - j
}
cSub := sliceView32(c, ldc, 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 []float32
if aTrans {
aSub = sliceView32(a, lda, k, i, lenk, leni)
} else {
aSub = sliceView32(a, lda, i, k, leni, lenk)
}
if bTrans {
bSub = sliceView32(b, ldb, j, k, lenj, lenk)
} else {
bSub = sliceView32(b, ldb, k, j, lenk, lenj)
}
sgemmSerial(aTrans, bTrans, leni, lenj, lenk, aSub, lda, bSub, ldb, cSub, ldc, alpha)
}
}
}()
}
// Send out all of the {i, j} subblocks for computation.
for i := 0; i < m; i += blockSize {
for j := 0; j < n; j += blockSize {
sendChan <- subMul{
i: i,
j: j,
}
}
}
close(sendChan)
wg.Wait()
}
// sgemmSerial is serial matrix multiply
func sgemmSerial(aTrans, bTrans bool, m, n, k int, a []float32, lda int, b []float32, ldb int, c []float32, ldc int, alpha float32) {
switch {
case !aTrans && !bTrans:
sgemmSerialNotNot(m, n, k, a, lda, b, ldb, c, ldc, alpha)
return
case aTrans && !bTrans:
sgemmSerialTransNot(m, n, k, a, lda, b, ldb, c, ldc, alpha)
return
case !aTrans && bTrans:
sgemmSerialNotTrans(m, n, k, a, lda, b, ldb, c, ldc, alpha)
return
case aTrans && bTrans:
sgemmSerialTransTrans(m, n, k, a, lda, b, ldb, c, ldc, alpha)
return
default:
panic("unreachable")
}
}
// sgemmSerial where neither a nor b are transposed
func sgemmSerialNotNot(m, n, k int, a []float32, lda int, b []float32, ldb int, c []float32, ldc int, alpha float32) {
// 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 < m; i++ {
ctmp := c[i*ldc : i*ldc+n]
for l, v := range a[i*lda : i*lda+k] {
tmp := alpha * v
if tmp != 0 {
f32.AxpyUnitary(tmp, b[l*ldb:l*ldb+n], ctmp)
}
}
}
}
// sgemmSerial where neither a is transposed and b is not
func sgemmSerialTransNot(m, n, k int, a []float32, lda int, b []float32, ldb int, c []float32, ldc int, alpha float32) {
// 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 < k; l++ {
btmp := b[l*ldb : l*ldb+n]
for i, v := range a[l*lda : l*lda+m] {
tmp := alpha * v
if tmp != 0 {
ctmp := c[i*ldc : i*ldc+n]
f32.AxpyUnitary(tmp, btmp, ctmp)
}
}
}
}
// sgemmSerial where neither a is not transposed and b is
func sgemmSerialNotTrans(m, n, k int, a []float32, lda int, b []float32, ldb int, c []float32, ldc int, alpha float32) {
// 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 < m; i++ {
atmp := a[i*lda : i*lda+k]
ctmp := c[i*ldc : i*ldc+n]
for j := 0; j < n; j++ {
ctmp[j] += alpha * f32.DotUnitary(atmp, b[j*ldb:j*ldb+k])
}
}
}
// sgemmSerial where both are transposed
func sgemmSerialTransTrans(m, n, k int, a []float32, lda int, b []float32, ldb int, c []float32, ldc int, alpha float32) {
// 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 < k; l++ {
for i, v := range a[l*lda : l*lda+m] {
tmp := alpha * v
if tmp != 0 {
ctmp := c[i*ldc : i*ldc+n]
f32.AxpyInc(tmp, b[l:], ctmp, uintptr(n), uintptr(ldb), 1, 0, 0)
}
}
}
}
func sliceView32(a []float32, lda, i, j, r, c int) []float32 {
return a[i*lda+j : (i+r-1)*lda+j+c]
}

View File

@ -1,218 +0,0 @@
#!/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.
WARNINGF32='//\
// Float32 implementations are autogenerated and not directly tested.\
'
WARNINGC64='//\
// Complex64 implementations are autogenerated and not directly tested.\
'
# Level1 routines.
echo Generating level1float32.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.\n' > level1float32.go
cat level1float64.go \
| gofmt -r 'blas.Float64Level1 -> blas.Float32Level1' \
\
| gofmt -r 'float64 -> float32' \
| gofmt -r 'blas.DrotmParams -> blas.SrotmParams' \
\
| gofmt -r 'f64.AxpyInc -> f32.AxpyInc' \
| gofmt -r 'f64.AxpyUnitary -> f32.AxpyUnitary' \
| gofmt -r 'f64.DotUnitary -> f32.DotUnitary' \
| gofmt -r 'f64.ScalInc -> f32.ScalInc' \
| gofmt -r 'f64.ScalUnitary -> f32.ScalUnitary' \
\
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNINGF32\1S\2_" \
-e 's_^// D_// S_' \
-e "s_^\(func (Implementation) \)Id\(.*\)\$_$WARNINGF32\1Is\2_" \
-e 's_^// Id_// Is_' \
-e 's_"gonum.org/v1/gonum/internal/asm/f64"_"gonum.org/v1/gonum/internal/asm/f32"_' \
-e 's_"math"_math "gonum.org/v1/gonum/internal/math32"_' \
>> level1float32.go
echo Generating level1cmplx64.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.\n' > level1cmplx64.go
cat level1cmplx128.go \
| gofmt -r 'blas.Complex128Level1 -> blas.Complex64Level1' \
\
| gofmt -r 'float64 -> float32' \
| gofmt -r 'complex128 -> complex64' \
\
| gofmt -r 'c128.AxpyInc -> c64.AxpyInc' \
| gofmt -r 'c128.AxpyUnitary -> c64.AxpyUnitary' \
| gofmt -r 'c128.DotcInc -> c64.DotcInc' \
| gofmt -r 'c128.DotcUnitary -> c64.DotcUnitary' \
| gofmt -r 'c128.DotuInc -> c64.DotuInc' \
| gofmt -r 'c128.DotuUnitary -> c64.DotuUnitary' \
| gofmt -r 'c128.ScalInc -> c64.ScalInc' \
| gofmt -r 'c128.ScalUnitary -> c64.ScalUnitary' \
| gofmt -r 'dcabs1 -> scabs1' \
\
| sed -e "s_^\(func (Implementation) \)Zdot\(.*\)\$_$WARNINGC64\1Cdot\2_" \
-e 's_^// Zdot_// Cdot_' \
-e "s_^\(func (Implementation) \)Zdscal\(.*\)\$_$WARNINGC64\1Csscal\2_" \
-e 's_^// Zdscal_// Csscal_' \
-e "s_^\(func (Implementation) \)Z\(.*\)\$_$WARNINGC64\1C\2_" \
-e 's_^// Z_// C_' \
-e "s_^\(func (Implementation) \)Iz\(.*\)\$_$WARNINGC64\1Ic\2_" \
-e 's_^// Iz_// Ic_' \
-e "s_^\(func (Implementation) \)Dz\(.*\)\$_$WARNINGC64\1Sc\2_" \
-e 's_^// Dz_// Sc_' \
-e 's_"gonum.org/v1/gonum/internal/asm/c128"_"gonum.org/v1/gonum/internal/asm/c64"_' \
-e 's_"math"_math "gonum.org/v1/gonum/internal/math32"_' \
>> level1cmplx64.go
echo Generating level1float32_sdot.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.\n' > level1float32_sdot.go
cat level1float64_ddot.go \
| gofmt -r 'float64 -> float32' \
\
| gofmt -r 'f64.DotInc -> f32.DotInc' \
| gofmt -r 'f64.DotUnitary -> f32.DotUnitary' \
\
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNINGF32\1S\2_" \
-e 's_^// D_// S_' \
-e 's_"gonum.org/v1/gonum/internal/asm/f64"_"gonum.org/v1/gonum/internal/asm/f32"_' \
>> level1float32_sdot.go
echo Generating level1float32_dsdot.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.\n' > level1float32_dsdot.go
cat level1float64_ddot.go \
| gofmt -r '[]float64 -> []float32' \
\
| gofmt -r 'f64.DotInc -> f32.DdotInc' \
| gofmt -r 'f64.DotUnitary -> f32.DdotUnitary' \
\
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNINGF32\1Ds\2_" \
-e 's_^// D_// Ds_' \
-e 's_"gonum.org/v1/gonum/internal/asm/f64"_"gonum.org/v1/gonum/internal/asm/f32"_' \
>> level1float32_dsdot.go
echo Generating level1float32_sdsdot.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.\n' > level1float32_sdsdot.go
cat level1float64_ddot.go \
| gofmt -r 'float64 -> float32' \
\
| gofmt -r 'f64.DotInc(x, y, f(n), f(incX), f(incY), f(ix), f(iy)) -> alpha + float32(f32.DdotInc(x, y, f(n), f(incX), f(incY), f(ix), f(iy)))' \
| gofmt -r 'f64.DotUnitary(a, b) -> alpha + float32(f32.DdotUnitary(a, b))' \
\
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNINGF32\1Sds\2_" \
-e 's_^// D\(.*\)$_// Sds\1 plus a constant_' \
-e 's_\\sum_alpha + \\sum_' \
-e 's/n int/n int, alpha float32/' \
-e 's_"gonum.org/v1/gonum/internal/asm/f64"_"gonum.org/v1/gonum/internal/asm/f32"_' \
>> level1float32_sdsdot.go
# Level2 routines.
echo Generating level2float32.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.\n' > level2float32.go
cat level2float64.go \
| gofmt -r 'blas.Float64Level2 -> blas.Float32Level2' \
\
| gofmt -r 'float64 -> float32' \
\
| gofmt -r 'f64.AxpyInc -> f32.AxpyInc' \
| gofmt -r 'f64.AxpyIncTo -> f32.AxpyIncTo' \
| gofmt -r 'f64.AxpyUnitary -> f32.AxpyUnitary' \
| gofmt -r 'f64.AxpyUnitaryTo -> f32.AxpyUnitaryTo' \
| gofmt -r 'f64.DotInc -> f32.DotInc' \
| gofmt -r 'f64.DotUnitary -> f32.DotUnitary' \
| gofmt -r 'f64.ScalInc -> f32.ScalInc' \
| gofmt -r 'f64.ScalUnitary -> f32.ScalUnitary' \
| gofmt -r 'f64.Ger -> f32.Ger' \
\
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNINGF32\1S\2_" \
-e 's_^// D_// S_' \
-e 's_"gonum.org/v1/gonum/internal/asm/f64"_"gonum.org/v1/gonum/internal/asm/f32"_' \
>> level2float32.go
echo Generating level2cmplx64.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.\n' > level2cmplx64.go
cat level2cmplx128.go \
| gofmt -r 'blas.Complex128Level2 -> blas.Complex64Level2' \
\
| gofmt -r 'complex128 -> complex64' \
| gofmt -r 'float64 -> float32' \
\
| gofmt -r 'c128.AxpyInc -> c64.AxpyInc' \
| gofmt -r 'c128.AxpyUnitary -> c64.AxpyUnitary' \
| gofmt -r 'c128.DotuInc -> c64.DotuInc' \
| gofmt -r 'c128.DotuUnitary -> c64.DotuUnitary' \
| gofmt -r 'c128.ScalInc -> c64.ScalInc' \
| gofmt -r 'c128.ScalUnitary -> c64.ScalUnitary' \
\
| sed -e "s_^\(func (Implementation) \)Z\(.*\)\$_$WARNINGC64\1C\2_" \
-e 's_^// Z_// C_' \
-e 's_"gonum.org/v1/gonum/internal/asm/c128"_"gonum.org/v1/gonum/internal/asm/c64"_' \
-e 's_"math/cmplx"_cmplx "gonum.org/v1/gonum/internal/cmplx64"_' \
>> level2cmplx64.go
# Level3 routines.
echo Generating level3float32.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.\n' > level3float32.go
cat level3float64.go \
| gofmt -r 'blas.Float64Level3 -> blas.Float32Level3' \
\
| gofmt -r 'float64 -> float32' \
\
| gofmt -r 'f64.AxpyUnitaryTo -> f32.AxpyUnitaryTo' \
| gofmt -r 'f64.AxpyUnitary -> f32.AxpyUnitary' \
| gofmt -r 'f64.DotUnitary -> f32.DotUnitary' \
| gofmt -r 'f64.ScalUnitary -> f32.ScalUnitary' \
\
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNINGF32\1S\2_" \
-e 's_^// D_// S_' \
-e 's_"gonum.org/v1/gonum/internal/asm/f64"_"gonum.org/v1/gonum/internal/asm/f32"_' \
>> level3float32.go
echo Generating sgemm.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.\n' > sgemm.go
cat dgemm.go \
| gofmt -r 'float64 -> float32' \
| gofmt -r 'sliceView64 -> sliceView32' \
\
| 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 'f64.AxpyInc -> f32.AxpyInc' \
| gofmt -r 'f64.AxpyUnitary -> f32.AxpyUnitary' \
| gofmt -r 'f64.DotUnitary -> f32.DotUnitary' \
\
| sed -e "s_^\(func (Implementation) \)D\(.*\)\$_$WARNINGF32\1S\2_" \
-e 's_^// D_// S_' \
-e 's_^// d_// s_' \
-e 's_"gonum.org/v1/gonum/internal/asm/f64"_"gonum.org/v1/gonum/internal/asm/f32"_' \
>> sgemm.go
echo Generating level3cmplx64.go
echo -e '// Code generated by "go generate gonum.org/v1/gonum/blas/gonum”; DO NOT EDIT.\n' > level3cmplx64.go
cat level3cmplx128.go \
| gofmt -r 'blas.Complex128Level3 -> blas.Complex64Level3' \
\
| gofmt -r 'float64 -> float32' \
| gofmt -r 'complex128 -> complex64' \
\
| gofmt -r 'c128.ScalUnitary -> c64.ScalUnitary' \
| gofmt -r 'c128.DscalUnitary -> c64.SscalUnitary' \
| gofmt -r 'c128.DotcUnitary -> c64.DotcUnitary' \
| gofmt -r 'c128.AxpyUnitary -> c64.AxpyUnitary' \
| gofmt -r 'c128.DotuUnitary -> c64.DotuUnitary' \
\
| sed -e "s_^\(func (Implementation) \)Z\(.*\)\$_$WARNINGC64\1C\2_" \
-e 's_^// Z_// C_' \
-e 's_"gonum.org/v1/gonum/internal/asm/c128"_"gonum.org/v1/gonum/internal/asm/c64"_' \
-e 's_"math/cmplx"_cmplx "gonum.org/v1/gonum/internal/cmplx64"_' \
>> level3cmplx64.go

View File

@ -1,4 +0,0 @@
# Gonum floats [![GoDoc](https://godoc.org/gonum.org/v1/gonum/floats?status.svg)](https://godoc.org/gonum.org/v1/gonum/floats)
Package floats provides a set of helper routines for dealing with slices of float64.
The functions avoid allocations to allow for use within tight loops without garbage collection overhead.

View File

@ -1,11 +0,0 @@
// Copyright ©2017 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 floats provides a set of helper routines for dealing with slices
// of float64. The functions avoid allocations to allow for use within tight
// loops without garbage collection overhead.
//
// The convention used is that when a slice is being modified in place, it has
// the name dst.
package floats // import "gonum.org/v1/gonum/floats"

View File

@ -1,933 +0,0 @@
// Copyright ©2013 The Gonum Authors. All rights reserved.
// Use of this code is governed by a BSD-style
// license that can be found in the LICENSE file
package floats
import (
"errors"
"math"
"sort"
"strconv"
"gonum.org/v1/gonum/internal/asm/f64"
)
// Add adds, element-wise, the elements of s and dst, and stores in dst.
// Panics if the lengths of dst and s do not match.
func Add(dst, s []float64) {
if len(dst) != len(s) {
panic("floats: length of the slices do not match")
}
f64.AxpyUnitaryTo(dst, 1, s, dst)
}
// AddTo adds, element-wise, the elements of s and t and
// stores the result in dst. Panics if the lengths of s, t and dst do not match.
func AddTo(dst, s, t []float64) []float64 {
if len(s) != len(t) {
panic("floats: length of adders do not match")
}
if len(dst) != len(s) {
panic("floats: length of destination does not match length of adder")
}
f64.AxpyUnitaryTo(dst, 1, s, t)
return dst
}
// AddConst adds the scalar c to all of the values in dst.
func AddConst(c float64, dst []float64) {
f64.AddConst(c, dst)
}
// AddScaled performs dst = dst + alpha * s.
// It panics if the lengths of dst and s are not equal.
func AddScaled(dst []float64, alpha float64, s []float64) {
if len(dst) != len(s) {
panic("floats: length of destination and source to not match")
}
f64.AxpyUnitaryTo(dst, alpha, s, dst)
}
// AddScaledTo performs dst = y + alpha * s, where alpha is a scalar,
// and dst, y and s are all slices.
// It panics if the lengths of dst, y, and s are not equal.
//
// At the return of the function, dst[i] = y[i] + alpha * s[i]
func AddScaledTo(dst, y []float64, alpha float64, s []float64) []float64 {
if len(dst) != len(s) || len(dst) != len(y) {
panic("floats: lengths of slices do not match")
}
f64.AxpyUnitaryTo(dst, alpha, s, y)
return dst
}
// argsort is a helper that implements sort.Interface, as used by
// Argsort.
type argsort struct {
s []float64
inds []int
}
func (a argsort) Len() int {
return len(a.s)
}
func (a argsort) Less(i, j int) bool {
return a.s[i] < a.s[j]
}
func (a argsort) Swap(i, j int) {
a.s[i], a.s[j] = a.s[j], a.s[i]
a.inds[i], a.inds[j] = a.inds[j], a.inds[i]
}
// Argsort sorts the elements of dst while tracking their original order.
// At the conclusion of Argsort, dst will contain the original elements of dst
// but sorted in increasing order, and inds will contain the original position
// of the elements in the slice such that dst[i] = origDst[inds[i]].
// It panics if the lengths of dst and inds do not match.
func Argsort(dst []float64, inds []int) {
if len(dst) != len(inds) {
panic("floats: length of inds does not match length of slice")
}
for i := range dst {
inds[i] = i
}
a := argsort{s: dst, inds: inds}
sort.Sort(a)
}
// Count applies the function f to every element of s and returns the number
// of times the function returned true.
func Count(f func(float64) bool, s []float64) int {
var n int
for _, val := range s {
if f(val) {
n++
}
}
return n
}
// CumProd finds the cumulative product of the first i elements in
// s and puts them in place into the ith element of the
// destination dst. A panic will occur if the lengths of arguments
// do not match.
//
// At the return of the function, dst[i] = s[i] * s[i-1] * s[i-2] * ...
func CumProd(dst, s []float64) []float64 {
if len(dst) != len(s) {
panic("floats: length of destination does not match length of the source")
}
if len(dst) == 0 {
return dst
}
return f64.CumProd(dst, s)
}
// CumSum finds the cumulative sum of the first i elements in
// s and puts them in place into the ith element of the
// destination dst. A panic will occur if the lengths of arguments
// do not match.
//
// At the return of the function, dst[i] = s[i] + s[i-1] + s[i-2] + ...
func CumSum(dst, s []float64) []float64 {
if len(dst) != len(s) {
panic("floats: length of destination does not match length of the source")
}
if len(dst) == 0 {
return dst
}
return f64.CumSum(dst, s)
}
// Distance computes the L-norm of s - t. See Norm for special cases.
// A panic will occur if the lengths of s and t do not match.
func Distance(s, t []float64, L float64) float64 {
if len(s) != len(t) {
panic("floats: slice lengths do not match")
}
if len(s) == 0 {
return 0
}
var norm float64
if L == 2 {
for i, v := range s {
diff := t[i] - v
norm = math.Hypot(norm, diff)
}
return norm
}
if L == 1 {
for i, v := range s {
norm += math.Abs(t[i] - v)
}
return norm
}
if math.IsInf(L, 1) {
for i, v := range s {
absDiff := math.Abs(t[i] - v)
if absDiff > norm {
norm = absDiff
}
}
return norm
}
for i, v := range s {
norm += math.Pow(math.Abs(t[i]-v), L)
}
return math.Pow(norm, 1/L)
}
// Div performs element-wise division dst / s
// and stores the value in dst. It panics if the
// lengths of s and t are not equal.
func Div(dst, s []float64) {
if len(dst) != len(s) {
panic("floats: slice lengths do not match")
}
f64.Div(dst, s)
}
// DivTo performs element-wise division s / t
// and stores the value in dst. It panics if the
// lengths of s, t, and dst are not equal.
func DivTo(dst, s, t []float64) []float64 {
if len(s) != len(t) || len(dst) != len(t) {
panic("floats: slice lengths do not match")
}
return f64.DivTo(dst, s, t)
}
// Dot computes the dot product of s1 and s2, i.e.
// sum_{i = 1}^N s1[i]*s2[i].
// A panic will occur if lengths of arguments do not match.
func Dot(s1, s2 []float64) float64 {
if len(s1) != len(s2) {
panic("floats: lengths of the slices do not match")
}
return f64.DotUnitary(s1, s2)
}
// Equal returns true if the slices have equal lengths and
// all elements are numerically identical.
func Equal(s1, s2 []float64) bool {
if len(s1) != len(s2) {
return false
}
for i, val := range s1 {
if s2[i] != val {
return false
}
}
return true
}
// EqualApprox returns true if the slices have equal lengths and
// all element pairs have an absolute tolerance less than tol or a
// relative tolerance less than tol.
func EqualApprox(s1, s2 []float64, tol float64) bool {
if len(s1) != len(s2) {
return false
}
for i, a := range s1 {
if !EqualWithinAbsOrRel(a, s2[i], tol, tol) {
return false
}
}
return true
}
// EqualFunc returns true if the slices have the same lengths
// and the function returns true for all element pairs.
func EqualFunc(s1, s2 []float64, f func(float64, float64) bool) bool {
if len(s1) != len(s2) {
return false
}
for i, val := range s1 {
if !f(val, s2[i]) {
return false
}
}
return true
}
// EqualWithinAbs returns true if a and b have an absolute
// difference of less than tol.
func EqualWithinAbs(a, b, tol float64) bool {
return a == b || math.Abs(a-b) <= tol
}
const minNormalFloat64 = 2.2250738585072014e-308
// EqualWithinRel returns true if the difference between a and b
// is not greater than tol times the greater value.
func EqualWithinRel(a, b, tol float64) bool {
if a == b {
return true
}
delta := math.Abs(a - b)
if delta <= minNormalFloat64 {
return delta <= tol*minNormalFloat64
}
// We depend on the division in this relationship to identify
// infinities (we rely on the NaN to fail the test) otherwise
// we compare Infs of the same sign and evaluate Infs as equal
// independent of sign.
return delta/math.Max(math.Abs(a), math.Abs(b)) <= tol
}
// EqualWithinAbsOrRel returns true if a and b are equal to within
// the absolute tolerance.
func EqualWithinAbsOrRel(a, b, absTol, relTol float64) bool {
if EqualWithinAbs(a, b, absTol) {
return true
}
return EqualWithinRel(a, b, relTol)
}
// EqualWithinULP returns true if a and b are equal to within
// the specified number of floating point units in the last place.
func EqualWithinULP(a, b float64, ulp uint) bool {
if a == b {
return true
}
if math.IsNaN(a) || math.IsNaN(b) {
return false
}
if math.Signbit(a) != math.Signbit(b) {
return math.Float64bits(math.Abs(a))+math.Float64bits(math.Abs(b)) <= uint64(ulp)
}
return ulpDiff(math.Float64bits(a), math.Float64bits(b)) <= uint64(ulp)
}
func ulpDiff(a, b uint64) uint64 {
if a > b {
return a - b
}
return b - a
}
// EqualLengths returns true if all of the slices have equal length,
// and false otherwise. Returns true if there are no input slices.
func EqualLengths(slices ...[]float64) bool {
// This length check is needed: http://play.golang.org/p/sdty6YiLhM
if len(slices) == 0 {
return true
}
l := len(slices[0])
for i := 1; i < len(slices); i++ {
if len(slices[i]) != l {
return false
}
}
return true
}
// Find applies f to every element of s and returns the indices of the first
// k elements for which the f returns true, or all such elements
// if k < 0.
// Find will reslice inds to have 0 length, and will append
// found indices to inds.
// If k > 0 and there are fewer than k elements in s satisfying f,
// all of the found elements will be returned along with an error.
// At the return of the function, the input inds will be in an undetermined state.
func Find(inds []int, f func(float64) bool, s []float64, k int) ([]int, error) {
// inds is also returned to allow for calling with nil
// Reslice inds to have zero length
inds = inds[:0]
// If zero elements requested, can just return
if k == 0 {
return inds, nil
}
// If k < 0, return all of the found indices
if k < 0 {
for i, val := range s {
if f(val) {
inds = append(inds, i)
}
}
return inds, nil
}
// Otherwise, find the first k elements
nFound := 0
for i, val := range s {
if f(val) {
inds = append(inds, i)
nFound++
if nFound == k {
return inds, nil
}
}
}
// Finished iterating over the loop, which means k elements were not found
return inds, errors.New("floats: insufficient elements found")
}
// HasNaN returns true if the slice s has any values that are NaN and false
// otherwise.
func HasNaN(s []float64) bool {
for _, v := range s {
if math.IsNaN(v) {
return true
}
}
return false
}
// LogSpan returns a set of n equally spaced points in log space between,
// l and u where N is equal to len(dst). The first element of the
// resulting dst will be l and the final element of dst will be u.
// Panics if len(dst) < 2
// Note that this call will return NaNs if either l or u are negative, and
// will return all zeros if l or u is zero.
// Also returns the mutated slice dst, so that it can be used in range, like:
//
// for i, x := range LogSpan(dst, l, u) { ... }
func LogSpan(dst []float64, l, u float64) []float64 {
Span(dst, math.Log(l), math.Log(u))
for i := range dst {
dst[i] = math.Exp(dst[i])
}
return dst
}
// LogSumExp returns the log of the sum of the exponentials of the values in s.
// Panics if s is an empty slice.
func LogSumExp(s []float64) float64 {
// Want to do this in a numerically stable way which avoids
// overflow and underflow
// First, find the maximum value in the slice.
maxval := Max(s)
if math.IsInf(maxval, 0) {
// If it's infinity either way, the logsumexp will be infinity as well
// returning now avoids NaNs
return maxval
}
var lse float64
// Compute the sumexp part
for _, val := range s {
lse += math.Exp(val - maxval)
}
// Take the log and add back on the constant taken out
return math.Log(lse) + maxval
}
// Max returns the maximum value in the input slice. If the slice is empty, Max will panic.
func Max(s []float64) float64 {
return s[MaxIdx(s)]
}
// MaxIdx returns the index of the maximum value in the input slice. If several
// entries have the maximum value, the first such index is returned. If the slice
// is empty, MaxIdx will panic.
func MaxIdx(s []float64) int {
if len(s) == 0 {
panic("floats: zero slice length")
}
max := math.NaN()
var ind int
for i, v := range s {
if math.IsNaN(v) {
continue
}
if v > max || math.IsNaN(max) {
max = v
ind = i
}
}
return ind
}
// Min returns the maximum value in the input slice. If the slice is empty, Min will panic.
func Min(s []float64) float64 {
return s[MinIdx(s)]
}
// MinIdx returns the index of the minimum value in the input slice. If several
// entries have the maximum value, the first such index is returned. If the slice
// is empty, MinIdx will panic.
func MinIdx(s []float64) int {
if len(s) == 0 {
panic("floats: zero slice length")
}
min := math.NaN()
var ind int
for i, v := range s {
if math.IsNaN(v) {
continue
}
if v < min || math.IsNaN(min) {
min = v
ind = i
}
}
return ind
}
// Mul performs element-wise multiplication between dst
// and s and stores the value in dst. Panics if the
// lengths of s and t are not equal.
func Mul(dst, s []float64) {
if len(dst) != len(s) {
panic("floats: slice lengths do not match")
}
for i, val := range s {
dst[i] *= val
}
}
// MulTo performs element-wise multiplication between s
// and t and stores the value in dst. Panics if the
// lengths of s, t, and dst are not equal.
func MulTo(dst, s, t []float64) []float64 {
if len(s) != len(t) || len(dst) != len(t) {
panic("floats: slice lengths do not match")
}
for i, val := range t {
dst[i] = val * s[i]
}
return dst
}
const (
nanBits = 0x7ff8000000000000
nanMask = 0xfff8000000000000
)
// NaNWith returns an IEEE 754 "quiet not-a-number" value with the
// payload specified in the low 51 bits of payload.
// The NaN returned by math.NaN has a bit pattern equal to NaNWith(1).
func NaNWith(payload uint64) float64 {
return math.Float64frombits(nanBits | (payload &^ nanMask))
}
// NaNPayload returns the lowest 51 bits payload of an IEEE 754 "quiet
// not-a-number". For values of f other than quiet-NaN, NaNPayload
// returns zero and false.
func NaNPayload(f float64) (payload uint64, ok bool) {
b := math.Float64bits(f)
if b&nanBits != nanBits {
return 0, false
}
return b &^ nanMask, true
}
// NearestIdx returns the index of the element in s
// whose value is nearest to v. If several such
// elements exist, the lowest index is returned.
// NearestIdx panics if len(s) == 0.
func NearestIdx(s []float64, v float64) int {
if len(s) == 0 {
panic("floats: zero length slice")
}
switch {
case math.IsNaN(v):
return 0
case math.IsInf(v, 1):
return MaxIdx(s)
case math.IsInf(v, -1):
return MinIdx(s)
}
var ind int
dist := math.NaN()
for i, val := range s {
newDist := math.Abs(v - val)
// A NaN distance will not be closer.
if math.IsNaN(newDist) {
continue
}
if newDist < dist || math.IsNaN(dist) {
dist = newDist
ind = i
}
}
return ind
}
// NearestIdxForSpan return the index of a hypothetical vector created
// by Span with length n and bounds l and u whose value is closest
// to v. That is, NearestIdxForSpan(n, l, u, v) is equivalent to
// Nearest(Span(make([]float64, n),l,u),v) without an allocation.
// NearestIdxForSpan panics if n is less than two.
func NearestIdxForSpan(n int, l, u float64, v float64) int {
if n <= 1 {
panic("floats: span must have length >1")
}
if math.IsNaN(v) {
return 0
}
// Special cases for Inf and NaN.
switch {
case math.IsNaN(l) && !math.IsNaN(u):
return n - 1
case math.IsNaN(u):
return 0
case math.IsInf(l, 0) && math.IsInf(u, 0):
if l == u {
return 0
}
if n%2 == 1 {
if !math.IsInf(v, 0) {
return n / 2
}
if math.Copysign(1, v) == math.Copysign(1, l) {
return 0
}
return n/2 + 1
}
if math.Copysign(1, v) == math.Copysign(1, l) {
return 0
}
return n / 2
case math.IsInf(l, 0):
if v == l {
return 0
}
return n - 1
case math.IsInf(u, 0):
if v == u {
return n - 1
}
return 0
case math.IsInf(v, -1):
if l <= u {
return 0
}
return n - 1
case math.IsInf(v, 1):
if u <= l {
return 0
}
return n - 1
}
// Special cases for v outside (l, u) and (u, l).
switch {
case l < u:
if v <= l {
return 0
}
if v >= u {
return n - 1
}
case l > u:
if v >= l {
return 0
}
if v <= u {
return n - 1
}
default:
return 0
}
// Can't guarantee anything about exactly halfway between
// because of floating point weirdness.
return int((float64(n)-1)/(u-l)*(v-l) + 0.5)
}
// Norm returns the L norm of the slice S, defined as
// (sum_{i=1}^N s[i]^L)^{1/L}
// Special cases:
// L = math.Inf(1) gives the maximum absolute value.
// Does not correctly compute the zero norm (use Count).
func Norm(s []float64, L float64) float64 {
// Should this complain if L is not positive?
// Should this be done in log space for better numerical stability?
// would be more cost
// maybe only if L is high?
if len(s) == 0 {
return 0
}
if L == 2 {
twoNorm := math.Abs(s[0])
for i := 1; i < len(s); i++ {
twoNorm = math.Hypot(twoNorm, s[i])
}
return twoNorm
}
var norm float64
if L == 1 {
for _, val := range s {
norm += math.Abs(val)
}
return norm
}
if math.IsInf(L, 1) {
for _, val := range s {
norm = math.Max(norm, math.Abs(val))
}
return norm
}
for _, val := range s {
norm += math.Pow(math.Abs(val), L)
}
return math.Pow(norm, 1/L)
}
// ParseWithNA converts the string s to a float64 in v.
// If s equals missing, w is returned as 0, otherwise 1.
func ParseWithNA(s, missing string) (v, w float64, err error) {
if s == missing {
return 0, 0, nil
}
v, err = strconv.ParseFloat(s, 64)
if err == nil {
w = 1
}
return v, w, err
}
// Prod returns the product of the elements of the slice.
// Returns 1 if len(s) = 0.
func Prod(s []float64) float64 {
prod := 1.0
for _, val := range s {
prod *= val
}
return prod
}
// Reverse reverses the order of elements in the slice.
func Reverse(s []float64) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
// Round returns the half away from zero rounded value of x with prec precision.
//
// Special cases are:
// Round(±0) = +0
// Round(±Inf) = ±Inf
// Round(NaN) = NaN
func Round(x float64, prec int) float64 {
if x == 0 {
// Make sure zero is returned
// without the negative bit set.
return 0
}
// Fast path for positive precision on integers.
if prec >= 0 && x == math.Trunc(x) {
return x
}
pow := math.Pow10(prec)
intermed := x * pow
if math.IsInf(intermed, 0) {
return x
}
if x < 0 {
x = math.Ceil(intermed - 0.5)
} else {
x = math.Floor(intermed + 0.5)
}
if x == 0 {
return 0
}
return x / pow
}
// RoundEven returns the half even rounded value of x with prec precision.
//
// Special cases are:
// RoundEven(±0) = +0
// RoundEven(±Inf) = ±Inf
// RoundEven(NaN) = NaN
func RoundEven(x float64, prec int) float64 {
if x == 0 {
// Make sure zero is returned
// without the negative bit set.
return 0
}
// Fast path for positive precision on integers.
if prec >= 0 && x == math.Trunc(x) {
return x
}
pow := math.Pow10(prec)
intermed := x * pow
if math.IsInf(intermed, 0) {
return x
}
if isHalfway(intermed) {
correction, _ := math.Modf(math.Mod(intermed, 2))
intermed += correction
if intermed > 0 {
x = math.Floor(intermed)
} else {
x = math.Ceil(intermed)
}
} else {
if x < 0 {
x = math.Ceil(intermed - 0.5)
} else {
x = math.Floor(intermed + 0.5)
}
}
if x == 0 {
return 0
}
return x / pow
}
func isHalfway(x float64) bool {
_, frac := math.Modf(x)
frac = math.Abs(frac)
return frac == 0.5 || (math.Nextafter(frac, math.Inf(-1)) < 0.5 && math.Nextafter(frac, math.Inf(1)) > 0.5)
}
// Same returns true if the input slices have the same length and the all elements
// have the same value with NaN treated as the same.
func Same(s, t []float64) bool {
if len(s) != len(t) {
return false
}
for i, v := range s {
w := t[i]
if v != w && !(math.IsNaN(v) && math.IsNaN(w)) {
return false
}
}
return true
}
// Scale multiplies every element in dst by the scalar c.
func Scale(c float64, dst []float64) {
if len(dst) > 0 {
f64.ScalUnitary(c, dst)
}
}
// ScaleTo multiplies the elements in s by c and stores the result in dst.
func ScaleTo(dst []float64, c float64, s []float64) []float64 {
if len(dst) != len(s) {
panic("floats: lengths of slices do not match")
}
if len(dst) > 0 {
f64.ScalUnitaryTo(dst, c, s)
}
return dst
}
// Span returns a set of N equally spaced points between l and u, where N
// is equal to the length of the destination. The first element of the destination
// is l, the final element of the destination is u.
//
// Panics if len(dst) < 2.
//
// Span also returns the mutated slice dst, so that it can be used in range expressions,
// like:
//
// for i, x := range Span(dst, l, u) { ... }
func Span(dst []float64, l, u float64) []float64 {
n := len(dst)
if n < 2 {
panic("floats: destination must have length >1")
}
// Special cases for Inf and NaN.
switch {
case math.IsNaN(l):
for i := range dst[:len(dst)-1] {
dst[i] = math.NaN()
}
dst[len(dst)-1] = u
return dst
case math.IsNaN(u):
for i := range dst[1:] {
dst[i+1] = math.NaN()
}
dst[0] = l
return dst
case math.IsInf(l, 0) && math.IsInf(u, 0):
for i := range dst[:len(dst)/2] {
dst[i] = l
dst[len(dst)-i-1] = u
}
if len(dst)%2 == 1 {
if l != u {
dst[len(dst)/2] = 0
} else {
dst[len(dst)/2] = l
}
}
return dst
case math.IsInf(l, 0):
for i := range dst[:len(dst)-1] {
dst[i] = l
}
dst[len(dst)-1] = u
return dst
case math.IsInf(u, 0):
for i := range dst[1:] {
dst[i+1] = u
}
dst[0] = l
return dst
}
step := (u - l) / float64(n-1)
for i := range dst {
dst[i] = l + step*float64(i)
}
return dst
}
// Sub subtracts, element-wise, the elements of s from dst. Panics if
// the lengths of dst and s do not match.
func Sub(dst, s []float64) {
if len(dst) != len(s) {
panic("floats: length of the slices do not match")
}
f64.AxpyUnitaryTo(dst, -1, s, dst)
}
// SubTo subtracts, element-wise, the elements of t from s and
// stores the result in dst. Panics if the lengths of s, t and dst do not match.
func SubTo(dst, s, t []float64) []float64 {
if len(s) != len(t) {
panic("floats: length of subtractor and subtractee do not match")
}
if len(dst) != len(s) {
panic("floats: length of destination does not match length of subtractor")
}
f64.AxpyUnitaryTo(dst, -1, t, s)
return dst
}
// Sum returns the sum of the elements of the slice.
func Sum(s []float64) float64 {
return f64.Sum(s)
}
// Within returns the first index i where s[i] <= v < s[i+1]. Within panics if:
// - len(s) < 2
// - s is not sorted
func Within(s []float64, v float64) int {
if len(s) < 2 {
panic("floats: slice length less than 2")
}
if !sort.Float64sAreSorted(s) {
panic("floats: input slice not sorted")
}
if v < s[0] || v >= s[len(s)-1] || math.IsNaN(v) {
return -1
}
for i, f := range s[1:] {
if v < f {
return i
}
}
return -1
}

View File

@ -1 +0,0 @@
test.out

View File

@ -1,3 +0,0 @@
# Gonum graph [![GoDoc](https://godoc.org/gonum.org/v1/gonum/graph?status.svg)](https://godoc.org/gonum.org/v1/gonum/graph)
This is a generalized graph package for the Go language.

View File

@ -1,9 +0,0 @@
// 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 defines graph interfaces.
//
// Routines to test contract compliance by user implemented graph types
// are available in gonum.org/v1/gonum/graph/testgraph.
package graph // import "gonum.org/v1/gonum/graph"

View File

@ -1,6 +0,0 @@
// Copyright ©2017 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 encoding provides a common graph encoding API.
package encoding // import "gonum.org/v1/gonum/graph/encoding"

View File

@ -1,527 +0,0 @@
// Copyright ©2017 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
import (
"fmt"
"strconv"
"strings"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/encoding"
"gonum.org/v1/gonum/graph/formats/dot"
"gonum.org/v1/gonum/graph/formats/dot/ast"
"gonum.org/v1/gonum/graph/internal/set"
)
// AttributeSetters is implemented by graph values that can set global
// DOT attributes.
type AttributeSetters interface {
// DOTAttributeSetters returns the global attribute setters.
DOTAttributeSetters() (graph, node, edge encoding.AttributeSetter)
}
// DOTIDSetter is implemented by types that can set a DOT ID.
type DOTIDSetter interface {
SetDOTID(id string)
}
// PortSetter is implemented by graph.Edge and graph.Line that can set
// the DOT port and compass directions of an edge.
type PortSetter interface {
// SetFromPort sets the From port and
// compass direction of the receiver.
SetFromPort(port, compass string) error
// SetToPort sets the To port and compass
// direction of the receiver.
SetToPort(port, compass string) error
}
// Unmarshal parses the Graphviz DOT-encoded data and stores the result in dst.
// If the number of graphs encoded in data is not one, an error is returned and
// dst will hold the first graph in data.
//
// Attributes and IDs are unquoted during unmarshalling if appropriate.
func Unmarshal(data []byte, dst encoding.Builder) error {
file, err := dot.ParseBytes(data)
if err != nil {
return err
}
err = copyGraph(dst, file.Graphs[0])
if err == nil && len(file.Graphs) != 1 {
err = fmt.Errorf("invalid number of graphs; expected 1, got %d", len(file.Graphs))
}
return err
}
// UnmarshalMulti parses the Graphviz DOT-encoded data as a multigraph and
// stores the result in dst.
// If the number of graphs encoded in data is not one, an error is returned and
// dst will hold the first graph in data.
//
// Attributes and IDs are unquoted during unmarshalling if appropriate.
func UnmarshalMulti(data []byte, dst encoding.MultiBuilder) error {
file, err := dot.ParseBytes(data)
if err != nil {
return err
}
err = copyMultigraph(dst, file.Graphs[0])
if err == nil && len(file.Graphs) != 1 {
err = fmt.Errorf("invalid number of graphs; expected 1, got %d", len(file.Graphs))
}
return err
}
// copyGraph copies the nodes and edges from the Graphviz AST source graph to
// the destination graph. Edge direction is maintained if present.
func copyGraph(dst encoding.Builder, src *ast.Graph) (err error) {
defer func() {
switch e := recover().(type) {
case nil:
case error:
err = e
default:
panic(e)
}
}()
gen := &simpleGraph{
generator: generator{
directed: src.Directed,
ids: make(map[string]graph.Node),
},
}
if dst, ok := dst.(DOTIDSetter); ok {
dst.SetDOTID(unquoteID(src.ID))
}
if a, ok := dst.(AttributeSetters); ok {
gen.graphAttr, gen.nodeAttr, gen.edgeAttr = a.DOTAttributeSetters()
}
for _, stmt := range src.Stmts {
gen.addStmt(dst, stmt)
}
return err
}
// copyMultigraph copies the nodes and edges from the Graphviz AST source graph to
// the destination graph. Edge direction is maintained if present.
func copyMultigraph(dst encoding.MultiBuilder, src *ast.Graph) (err error) {
defer func() {
switch e := recover().(type) {
case nil:
case error:
err = e
default:
panic(e)
}
}()
gen := &multiGraph{
generator: generator{
directed: src.Directed,
ids: make(map[string]graph.Node),
},
}
if dst, ok := dst.(DOTIDSetter); ok {
dst.SetDOTID(unquoteID(src.ID))
}
if a, ok := dst.(AttributeSetters); ok {
gen.graphAttr, gen.nodeAttr, gen.edgeAttr = a.DOTAttributeSetters()
}
for _, stmt := range src.Stmts {
gen.addStmt(dst, stmt)
}
return err
}
// A generator keeps track of the information required for generating a gonum
// graph from a dot AST graph.
type generator struct {
// Directed graph.
directed bool
// Map from dot AST node ID to gonum node.
ids map[string]graph.Node
// Nodes processed within the context of a subgraph, that is to be used as a
// vertex of an edge.
subNodes []graph.Node
// Stack of start indices into the subgraph node slice. The top element
// corresponds to the start index of the active (or inner-most) subgraph.
subStart []int
// graphAttr, nodeAttr and edgeAttr are global graph attributes.
graphAttr, nodeAttr, edgeAttr encoding.AttributeSetter
}
// node returns the gonum node corresponding to the given dot AST node ID,
// generating a new such node if none exist.
func (gen *generator) node(dst graph.NodeAdder, id string) graph.Node {
if n, ok := gen.ids[id]; ok {
return n
}
n := dst.NewNode()
if n, ok := n.(DOTIDSetter); ok {
n.SetDOTID(unquoteID(id))
}
dst.AddNode(n)
gen.ids[id] = n
// Check if within the context of a subgraph, that is to be used as a vertex
// of an edge.
if gen.isInSubgraph() {
// Append node processed within the context of a subgraph, that is to be
// used as a vertex of an edge
gen.appendSubgraphNode(n)
}
return n
}
type simpleGraph struct{ generator }
// addStmt adds the given statement to the graph.
func (gen *simpleGraph) addStmt(dst encoding.Builder, stmt ast.Stmt) {
switch stmt := stmt.(type) {
case *ast.NodeStmt:
n, ok := gen.node(dst, stmt.Node.ID).(encoding.AttributeSetter)
if !ok {
return
}
for _, attr := range stmt.Attrs {
a := encoding.Attribute{
Key: unquoteID(attr.Key),
Value: unquoteID(attr.Val),
}
if err := n.SetAttribute(a); err != nil {
panic(fmt.Errorf("unable to unmarshal node DOT attribute (%s=%s): %v", a.Key, a.Value, err))
}
}
case *ast.EdgeStmt:
gen.addEdgeStmt(dst, stmt)
case *ast.AttrStmt:
var n encoding.AttributeSetter
var dst string
switch stmt.Kind {
case ast.GraphKind:
if gen.graphAttr == nil {
return
}
n = gen.graphAttr
dst = "graph"
case ast.NodeKind:
if gen.nodeAttr == nil {
return
}
n = gen.nodeAttr
dst = "node"
case ast.EdgeKind:
if gen.edgeAttr == nil {
return
}
n = gen.edgeAttr
dst = "edge"
default:
panic("unreachable")
}
for _, attr := range stmt.Attrs {
a := encoding.Attribute{
Key: unquoteID(attr.Key),
Value: unquoteID(attr.Val),
}
if err := n.SetAttribute(a); err != nil {
panic(fmt.Errorf("unable to unmarshal global %s DOT attribute (%s=%s): %v", dst, a.Key, a.Value, err))
}
}
case *ast.Attr:
// ignore.
case *ast.Subgraph:
for _, stmt := range stmt.Stmts {
gen.addStmt(dst, stmt)
}
default:
panic(fmt.Sprintf("unknown statement type %T", stmt))
}
}
// basicEdge is an edge without the Reverse method to
// allow satisfaction by both graph.Edge and graph.Line.
type basicEdge interface {
From() graph.Node
To() graph.Node
}
// applyPortsToEdge applies the available port metadata from an ast.Edge
// to a graph.Edge
func applyPortsToEdge(from ast.Vertex, to *ast.Edge, edge basicEdge) {
if ps, isPortSetter := edge.(PortSetter); isPortSetter {
if n, vertexIsNode := from.(*ast.Node); vertexIsNode {
if n.Port != nil {
err := ps.SetFromPort(unquoteID(n.Port.ID), n.Port.CompassPoint.String())
if err != nil {
panic(fmt.Errorf("unable to unmarshal edge port (:%s:%s)", n.Port.ID, n.Port.CompassPoint.String()))
}
}
}
if n, vertexIsNode := to.Vertex.(*ast.Node); vertexIsNode {
if n.Port != nil {
err := ps.SetToPort(unquoteID(n.Port.ID), n.Port.CompassPoint.String())
if err != nil {
panic(fmt.Errorf("unable to unmarshal edge DOT port (:%s:%s)", n.Port.ID, n.Port.CompassPoint.String()))
}
}
}
}
}
// addEdgeStmt adds the given edge statement to the graph.
func (gen *simpleGraph) addEdgeStmt(dst encoding.Builder, stmt *ast.EdgeStmt) {
fs := gen.addVertex(dst, stmt.From)
ts := gen.addEdge(dst, stmt.To, stmt.Attrs)
for _, f := range fs {
for _, t := range ts {
edge := dst.NewEdge(f, t)
dst.SetEdge(edge)
applyPortsToEdge(stmt.From, stmt.To, edge)
addEdgeAttrs(edge, stmt.Attrs)
}
}
}
// addVertex adds the given vertex to the graph, and returns its set of nodes.
func (gen *simpleGraph) addVertex(dst encoding.Builder, v ast.Vertex) []graph.Node {
switch v := v.(type) {
case *ast.Node:
n := gen.node(dst, v.ID)
return []graph.Node{n}
case *ast.Subgraph:
gen.pushSubgraph()
for _, stmt := range v.Stmts {
gen.addStmt(dst, stmt)
}
return gen.popSubgraph()
default:
panic(fmt.Sprintf("unknown vertex type %T", v))
}
}
// addEdge adds the given edge to the graph, and returns its set of nodes.
func (gen *simpleGraph) addEdge(dst encoding.Builder, to *ast.Edge, attrs []*ast.Attr) []graph.Node {
if !gen.directed && to.Directed {
panic(fmt.Errorf("directed edge to %v in undirected graph", to.Vertex))
}
fs := gen.addVertex(dst, to.Vertex)
if to.To != nil {
ts := gen.addEdge(dst, to.To, attrs)
for _, f := range fs {
for _, t := range ts {
edge := dst.NewEdge(f, t)
dst.SetEdge(edge)
applyPortsToEdge(to.Vertex, to.To, edge)
addEdgeAttrs(edge, attrs)
}
}
}
return fs
}
// pushSubgraph pushes the node start index of the active subgraph onto the
// stack.
func (gen *generator) pushSubgraph() {
gen.subStart = append(gen.subStart, len(gen.subNodes))
}
// popSubgraph pops the node start index of the active subgraph from the stack,
// and returns the nodes processed since.
func (gen *generator) popSubgraph() []graph.Node {
// Get nodes processed since the subgraph became active.
start := gen.subStart[len(gen.subStart)-1]
// TODO: Figure out a better way to store subgraph nodes, so that duplicates
// may not occur.
nodes := unique(gen.subNodes[start:])
// Remove subgraph from stack.
gen.subStart = gen.subStart[:len(gen.subStart)-1]
if len(gen.subStart) == 0 {
// Remove subgraph nodes when the bottom-most subgraph has been processed.
gen.subNodes = gen.subNodes[:0]
}
return nodes
}
// unique returns the set of unique nodes contained within ns.
func unique(ns []graph.Node) []graph.Node {
var nodes []graph.Node
seen := make(set.Int64s)
for _, n := range ns {
id := n.ID()
if seen.Has(id) {
// skip duplicate node
continue
}
seen.Add(id)
nodes = append(nodes, n)
}
return nodes
}
// isInSubgraph reports whether the active context is within a subgraph, that is
// to be used as a vertex of an edge.
func (gen *generator) isInSubgraph() bool {
return len(gen.subStart) > 0
}
// appendSubgraphNode appends the given node to the slice of nodes processed
// within the context of a subgraph.
func (gen *generator) appendSubgraphNode(n graph.Node) {
gen.subNodes = append(gen.subNodes, n)
}
type multiGraph struct{ generator }
// addStmt adds the given statement to the multigraph.
func (gen *multiGraph) addStmt(dst encoding.MultiBuilder, stmt ast.Stmt) {
switch stmt := stmt.(type) {
case *ast.NodeStmt:
n, ok := gen.node(dst, stmt.Node.ID).(encoding.AttributeSetter)
if !ok {
return
}
for _, attr := range stmt.Attrs {
a := encoding.Attribute{
Key: unquoteID(attr.Key),
Value: unquoteID(attr.Val),
}
if err := n.SetAttribute(a); err != nil {
panic(fmt.Errorf("unable to unmarshal node DOT attribute (%s=%s): %v", a.Key, a.Value, err))
}
}
case *ast.EdgeStmt:
gen.addEdgeStmt(dst, stmt)
case *ast.AttrStmt:
var n encoding.AttributeSetter
var dst string
switch stmt.Kind {
case ast.GraphKind:
if gen.graphAttr == nil {
return
}
n = gen.graphAttr
dst = "graph"
case ast.NodeKind:
if gen.nodeAttr == nil {
return
}
n = gen.nodeAttr
dst = "node"
case ast.EdgeKind:
if gen.edgeAttr == nil {
return
}
n = gen.edgeAttr
dst = "edge"
default:
panic("unreachable")
}
for _, attr := range stmt.Attrs {
a := encoding.Attribute{
Key: unquoteID(attr.Key),
Value: unquoteID(attr.Val),
}
if err := n.SetAttribute(a); err != nil {
panic(fmt.Errorf("unable to unmarshal global %s DOT attribute (%s=%s): %v", dst, a.Key, a.Value, err))
}
}
case *ast.Attr:
// ignore.
case *ast.Subgraph:
for _, stmt := range stmt.Stmts {
gen.addStmt(dst, stmt)
}
default:
panic(fmt.Sprintf("unknown statement type %T", stmt))
}
}
// addEdgeStmt adds the given edge statement to the multigraph.
func (gen *multiGraph) addEdgeStmt(dst encoding.MultiBuilder, stmt *ast.EdgeStmt) {
fs := gen.addVertex(dst, stmt.From)
ts := gen.addLine(dst, stmt.To, stmt.Attrs)
for _, f := range fs {
for _, t := range ts {
edge := dst.NewLine(f, t)
dst.SetLine(edge)
applyPortsToEdge(stmt.From, stmt.To, edge)
addEdgeAttrs(edge, stmt.Attrs)
}
}
}
// addVertex adds the given vertex to the multigraph, and returns its set of nodes.
func (gen *multiGraph) addVertex(dst encoding.MultiBuilder, v ast.Vertex) []graph.Node {
switch v := v.(type) {
case *ast.Node:
n := gen.node(dst, v.ID)
return []graph.Node{n}
case *ast.Subgraph:
gen.pushSubgraph()
for _, stmt := range v.Stmts {
gen.addStmt(dst, stmt)
}
return gen.popSubgraph()
default:
panic(fmt.Sprintf("unknown vertex type %T", v))
}
}
// addLine adds the given edge to the multigraph, and returns its set of nodes.
func (gen *multiGraph) addLine(dst encoding.MultiBuilder, to *ast.Edge, attrs []*ast.Attr) []graph.Node {
if !gen.directed && to.Directed {
panic(fmt.Errorf("directed edge to %v in undirected graph", to.Vertex))
}
fs := gen.addVertex(dst, to.Vertex)
if to.To != nil {
ts := gen.addLine(dst, to.To, attrs)
for _, f := range fs {
for _, t := range ts {
edge := dst.NewLine(f, t)
dst.SetLine(edge)
applyPortsToEdge(to.Vertex, to.To, edge)
addEdgeAttrs(edge, attrs)
}
}
}
return fs
}
// addEdgeAttrs adds the attributes to the given edge.
func addEdgeAttrs(edge basicEdge, attrs []*ast.Attr) {
e, ok := edge.(encoding.AttributeSetter)
if !ok {
return
}
for _, attr := range attrs {
a := encoding.Attribute{
Key: unquoteID(attr.Key),
Value: unquoteID(attr.Val),
}
if err := e.SetAttribute(a); err != nil {
panic(fmt.Errorf("unable to unmarshal edge DOT attribute (%s=%s): %v", a.Key, a.Value, err))
}
}
}
// unquoteID unquotes the given string if needed in the context of an ID. If s
// is not already quoted the original string is returned.
func unquoteID(s string) string {
// To make round-trips idempotent, don't unquote quoted HTML-like strings
//
// /^"<.*>"$/
if len(s) >= 4 && strings.HasPrefix(s, `"<`) && strings.HasSuffix(s, `>"`) {
return s
}
// Unquote quoted string if possible.
if t, err := strconv.Unquote(s); err == nil {
return t
}
// On error, either s is not quoted or s is quoted but contains invalid
// characters, in both cases we return the original string rather than
// panicking.
return s
}

View File

@ -1,21 +0,0 @@
// Copyright ©2017 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 and unmarshaling of graphs.
//
// See the GraphViz DOT Guide and the DOT grammar for more information
// on using specific aspects of the DOT language:
//
// DOT Guide: https://www.graphviz.org/pdf/dotguide.pdf
//
// DOT grammar: http://www.graphviz.org/doc/info/lang.html
//
// Attribute quoting
//
// Attributes and IDs are quoted if needed during marshalling, to conform with
// valid DOT syntax. Quoted IDs and attributes are unquoted during unmarshaling,
// so the data is kept in raw form. As an exception, quoted text with a leading
// `"<` and a trailing `>"` is not unquoted to ensure preservation of the string
// during a round-trip.
package dot // import "gonum.org/v1/gonum/graph/encoding/dot"

View File

@ -1,654 +0,0 @@
// 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
import (
"bytes"
"errors"
"fmt"
"regexp"
"sort"
"strconv"
"strings"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/encoding"
"gonum.org/v1/gonum/graph/internal/ordered"
)
// 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 encoding.Attributer)
}
// Porter defines the behavior of graph.Edge values that can specify
// connection ports for their end points. The returned port corresponds
// to 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 returns the port and compass for
// the From node of a graph.Edge.
FromPort() (port, compass string)
// ToPort returns the port and compass for
// the To node of a graph.Edge.
ToPort() (port, compass string)
}
// Structurer represents a graph.Graph that can define subgraphs.
type Structurer interface {
Structure() []Graph
}
// MultiStructurer represents a graph.Multigraph that can define subgraphs.
type MultiStructurer interface {
Structure() []Multigraph
}
// Graph wraps named graph.Graph values.
type Graph interface {
graph.Graph
DOTID() string
}
// Multigraph wraps named graph.Multigraph values.
type Multigraph interface {
graph.Multigraph
DOTID() string
}
// Subgrapher wraps graph.Node values that represent subgraphs.
type Subgrapher interface {
Subgraph() graph.Graph
}
// MultiSubgrapher wraps graph.Node values that represent subgraphs.
type MultiSubgrapher interface {
Subgraph() graph.Multigraph
}
// 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.
//
// 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.
//
// Attributes and IDs are quoted if needed during marshalling.
func Marshal(g graph.Graph, name, prefix, indent string) ([]byte, error) {
var p simpleGraphPrinter
p.indent = indent
p.prefix = prefix
p.visited = make(map[edge]bool)
err := p.print(g, name, false, false)
if err != nil {
return nil, err
}
return p.buf.Bytes(), nil
}
// MarshalMulti returns the DOT encoding for the multigraph 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.
//
// Graph serialization will work for a graph.Multigraph without modification,
// however, advanced GraphViz DOT features provided by Marshal depend on
// implementation of the Node, Attributer, Porter, Attributers, Structurer,
// MultiSubgrapher and Multigraph interfaces.
//
// Attributes and IDs are quoted if needed during marshalling.
func MarshalMulti(g graph.Multigraph, name, prefix, indent string) ([]byte, error) {
var p multiGraphPrinter
p.indent = indent
p.prefix = prefix
p.visited = make(map[line]bool)
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
}
type edge struct {
inGraph string
from, to int64
}
func (p *simpleGraphPrinter) print(g graph.Graph, name string, needsIndent, isSubgraph bool) error {
if name == "" {
if g, ok := g.(Graph); ok {
name = g.DOTID()
}
}
_, isDirected := g.(graph.Directed)
p.printFrontMatter(name, needsIndent, isSubgraph, isDirected, true)
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)
}
}
nodes := graph.NodesOf(g.Nodes())
sort.Sort(ordered.ByID(nodes))
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 g.From(n.ID()).Len() == 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.(encoding.Attributer); ok {
p.writeAttributeList(a)
}
p.buf.WriteByte(';')
}
havePrintedEdgeHeader := false
for _, n := range nodes {
nid := n.ID()
to := graph.NodesOf(g.From(nid))
sort.Sort(ordered.ByID(to))
for _, t := range to {
tid := t.ID()
if isDirected {
if p.visited[edge{inGraph: name, from: nid, to: tid}] {
continue
}
p.visited[edge{inGraph: name, from: nid, to: tid}] = true
} else {
if p.visited[edge{inGraph: name, from: nid, to: tid}] {
continue
}
p.visited[edge{inGraph: name, from: nid, to: tid}] = true
p.visited[edge{inGraph: name, from: tid, to: n.ID()}] = true
}
if !havePrintedEdgeHeader {
p.buf.WriteByte('\n')
p.buf.WriteString(strings.TrimRight(p.prefix, " \t\n")) // 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 := g.Edge(nid, tid)
porter, edgeIsPorter := e.(Porter)
if edgeIsPorter {
if e.From().ID() == nid {
p.writePorts(porter.FromPort())
} else {
p.writePorts(porter.ToPort())
}
}
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 {
if e.From().ID() == nid {
p.writePorts(porter.ToPort())
} else {
p.writePorts(porter.FromPort())
}
}
if a, ok := g.Edge(nid, tid).(encoding.Attributer); ok {
p.writeAttributeList(a)
}
p.buf.WriteByte(';')
}
}
p.closeBlock("}")
return nil
}
func (p *printer) printFrontMatter(name string, needsIndent, isSubgraph, isDirected, isStrict bool) {
p.buf.WriteString(p.prefix)
if needsIndent {
for i := 0; i < p.depth; i++ {
p.buf.WriteString(p.indent)
}
}
if !isSubgraph && isStrict {
p.buf.WriteString("strict ")
}
if isSubgraph {
p.buf.WriteString("sub")
} else if isDirected {
p.buf.WriteString("di")
}
p.buf.WriteString("graph")
if name != "" {
p.buf.WriteByte(' ')
p.buf.WriteString(quoteID(name))
}
p.openBlock(" {")
}
func (p *printer) writeNode(n graph.Node) {
p.buf.WriteString(quoteID(nodeID(n)))
}
func (p *printer) writePorts(port, cp string) {
if port != "" {
p.buf.WriteByte(':')
p.buf.WriteString(quoteID(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 interface{}, n graph.Node) string {
switch g := g.(type) {
case Node:
return g.DOTID()
default:
return nodeID(n)
}
}
func (p *printer) writeAttributeList(a encoding.Attributer) {
attributes := a.Attributes()
switch len(attributes) {
case 0:
case 1:
p.buf.WriteString(" [")
p.buf.WriteString(quoteID(attributes[0].Key))
p.buf.WriteByte('=')
p.buf.WriteString(quoteID(attributes[0].Value))
p.buf.WriteString("]")
default:
p.openBlock(" [")
for _, att := range attributes {
p.newline()
p.buf.WriteString(quoteID(att.Key))
p.buf.WriteByte('=')
p.buf.WriteString(quoteID(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 []encoding.Attributer{g, n, e} {
attributes := a.Attributes()
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(quoteID(att.Key))
p.buf.WriteByte('=')
p.buf.WriteString(quoteID(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 simpleGraphPrinter struct {
printer
visited map[edge]bool
}
type multiGraphPrinter struct {
printer
visited map[line]bool
}
type line struct {
inGraph string
id int64
}
func (p *multiGraphPrinter) print(g graph.Multigraph, name string, needsIndent, isSubgraph bool) error {
if name == "" {
if g, ok := g.(Multigraph); ok {
name = g.DOTID()
}
}
_, isDirected := g.(graph.Directed)
p.printFrontMatter(name, needsIndent, isSubgraph, isDirected, false)
if a, ok := g.(Attributers); ok {
p.writeAttributeComplex(a)
}
if s, ok := g.(MultiStructurer); 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)
}
}
nodes := graph.NodesOf(g.Nodes())
sort.Sort(ordered.ByID(nodes))
havePrintedNodeHeader := false
for _, n := range nodes {
if s, ok := n.(MultiSubgrapher); ok {
// If the node is not linked to any other node
// the graph needs to be written now.
if g.From(n.ID()).Len() == 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.(encoding.Attributer); ok {
p.writeAttributeList(a)
}
p.buf.WriteByte(';')
}
havePrintedEdgeHeader := false
for _, n := range nodes {
nid := n.ID()
to := graph.NodesOf(g.From(nid))
sort.Sort(ordered.ByID(to))
for _, t := range to {
tid := t.ID()
lines := graph.LinesOf(g.Lines(nid, tid))
sort.Sort(ordered.LinesByIDs(lines))
for _, l := range lines {
lid := l.ID()
if p.visited[line{inGraph: name, id: lid}] {
continue
}
p.visited[line{inGraph: name, id: lid}] = true
if !havePrintedEdgeHeader {
p.buf.WriteByte('\n')
p.buf.WriteString(strings.TrimRight(p.prefix, " \t\n")) // Trim whitespace suffix.
p.newline()
p.buf.WriteString("// Edge definitions.")
havePrintedEdgeHeader = true
}
p.newline()
if s, ok := n.(MultiSubgrapher); 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)
}
porter, edgeIsPorter := l.(Porter)
if edgeIsPorter {
if l.From().ID() == nid {
p.writePorts(porter.FromPort())
} else {
p.writePorts(porter.ToPort())
}
}
if isDirected {
p.buf.WriteString(" -> ")
} else {
p.buf.WriteString(" -- ")
}
if s, ok := t.(MultiSubgrapher); 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 {
if l.From().ID() == nid {
p.writePorts(porter.ToPort())
} else {
p.writePorts(porter.FromPort())
}
}
if a, ok := l.(encoding.Attributer); ok {
p.writeAttributeList(a)
}
p.buf.WriteByte(';')
}
}
}
p.closeBlock("}")
return nil
}
// quoteID quotes the given string if needed in the context of an ID. If s is
// already quoted, or if s does not contain any spaces or special characters
// that need escaping, the original string is returned.
func quoteID(s string) string {
// To use a keyword as an ID, it must be quoted.
if isKeyword(s) {
return strconv.Quote(s)
}
// Quote if s is not an ID. This includes strings containing spaces, except
// if those spaces are used within HTML string IDs (e.g. <foo >).
if !isID(s) {
return strconv.Quote(s)
}
return s
}
// isKeyword reports whether the given string is a keyword in the DOT language.
func isKeyword(s string) bool {
// ref: https://www.graphviz.org/doc/info/lang.html
keywords := []string{"node", "edge", "graph", "digraph", "subgraph", "strict"}
for _, keyword := range keywords {
if strings.EqualFold(s, keyword) {
return true
}
}
return false
}
// FIXME: see if we rewrite this in another way to remove our regexp dependency.
// Regular expression to match identifier and numeral IDs.
var (
reIdent = regexp.MustCompile(`^[a-zA-Z\200-\377_][0-9a-zA-Z\200-\377_]*$`)
reNumeral = regexp.MustCompile(`^[-]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)$`)
)
// isID reports whether the given string is an ID.
//
// An ID is one of the following:
//
// 1. Any string of alphabetic ([a-zA-Z\200-\377]) characters, underscores ('_')
// or digits ([0-9]), not beginning with a digit;
// 2. a numeral [-]?(.[0-9]+ | [0-9]+(.[0-9]*)? );
// 3. any double-quoted string ("...") possibly containing escaped quotes (\");
// 4. an HTML string (<...>).
func isID(s string) bool {
// 1. an identifier.
if reIdent.MatchString(s) {
return true
}
// 2. a numeral.
if reNumeral.MatchString(s) {
return true
}
// 3. double-quote string ID.
if len(s) >= 2 && strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) {
// Check that escape sequences within the double-quotes are valid.
if _, err := strconv.Unquote(s); err == nil {
return true
}
}
// 4. HTML ID.
return isHTMLID(s)
}
// isHTMLID reports whether the given string an HTML ID.
func isHTMLID(s string) bool {
// HTML IDs have the format /^<.*>$/
return len(s) >= 2 && strings.HasPrefix(s, "<") && strings.HasSuffix(s, ">")
}

View File

@ -1,36 +0,0 @@
// Copyright ©2017 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 encoding
import "gonum.org/v1/gonum/graph"
// Builder is a graph that can have user-defined nodes and edges added.
type Builder interface {
graph.Graph
graph.Builder
}
// MultiBuilder is a graph that can have user-defined nodes and edges added.
type MultiBuilder interface {
graph.Multigraph
graph.MultigraphBuilder
}
// AttributeSetter is implemented by types that can set an encoded graph
// attribute.
type AttributeSetter interface {
SetAttribute(Attribute) error
}
// Attributer defines graph.Node or graph.Edge values that can
// specify graph attributes.
type Attributer interface {
Attributes() []Attribute
}
// Attribute is an encoded key value attribute pair use in graph encoding.
type Attribute struct {
Key, Value string
}

View File

@ -1,9 +0,0 @@
# formats/dot
## License
The source code and any original content of the formats/dot directory is released under [Public Domain Dedication](https://creativecommons.org/publicdomain/zero/1.0/).
The source code is also licensed under the gonum license, and users are free to choose the license which suits their needs.
Please see gonum.org/v1/gonum for general license information, contributors, authors, etc on the Gonum suite of packages.

View File

@ -1,409 +0,0 @@
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
package ast
import (
"bytes"
"fmt"
)
// === [ File ] ================================================================
// A File represents a DOT file.
//
// Examples.
//
// digraph G {
// A -> B
// }
// graph H {
// C - D
// }
type File struct {
// Graphs.
Graphs []*Graph
}
// String returns the string representation of the file.
func (f *File) String() string {
buf := new(bytes.Buffer)
for i, graph := range f.Graphs {
if i != 0 {
buf.WriteString("\n")
}
buf.WriteString(graph.String())
}
return buf.String()
}
// === [ Graphs ] ==============================================================
// A Graph represents a directed or an undirected graph.
//
// Examples.
//
// digraph G {
// A -> {B C}
// B -> C
// }
type Graph struct {
// Strict graph; multi-edges forbidden.
Strict bool
// Directed graph.
Directed bool
// Graph ID; or empty if anonymous.
ID string
// Graph statements.
Stmts []Stmt
}
// String returns the string representation of the graph.
func (g *Graph) String() string {
buf := new(bytes.Buffer)
if g.Strict {
buf.WriteString("strict ")
}
if g.Directed {
buf.WriteString("digraph ")
} else {
buf.WriteString("graph ")
}
if len(g.ID) > 0 {
fmt.Fprintf(buf, "%s ", g.ID)
}
buf.WriteString("{\n")
for _, stmt := range g.Stmts {
fmt.Fprintf(buf, "\t%s\n", stmt)
}
buf.WriteString("}")
return buf.String()
}
// === [ Statements ] ==========================================================
// A Stmt represents a statement, and has one of the following underlying types.
//
// *NodeStmt
// *EdgeStmt
// *AttrStmt
// *Attr
// *Subgraph
type Stmt interface {
fmt.Stringer
// isStmt ensures that only statements can be assigned to the Stmt interface.
isStmt()
}
// --- [ Node statement ] ------------------------------------------------------
// A NodeStmt represents a node statement.
//
// Examples.
//
// A [color=blue]
type NodeStmt struct {
// Node.
Node *Node
// Node attributes.
Attrs []*Attr
}
// String returns the string representation of the node statement.
func (e *NodeStmt) String() string {
buf := new(bytes.Buffer)
buf.WriteString(e.Node.String())
if len(e.Attrs) > 0 {
buf.WriteString(" [")
for i, attr := range e.Attrs {
if i != 0 {
buf.WriteString(" ")
}
buf.WriteString(attr.String())
}
buf.WriteString("]")
}
return buf.String()
}
// --- [ Edge statement ] ------------------------------------------------------
// An EdgeStmt represents an edge statement.
//
// Examples.
//
// A -> B
// A -> {B C}
// A -> B -> C
type EdgeStmt struct {
// Source vertex.
From Vertex
// Outgoing edge.
To *Edge
// Edge attributes.
Attrs []*Attr
}
// String returns the string representation of the edge statement.
func (e *EdgeStmt) String() string {
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "%s %s", e.From, e.To)
if len(e.Attrs) > 0 {
buf.WriteString(" [")
for i, attr := range e.Attrs {
if i != 0 {
buf.WriteString(" ")
}
buf.WriteString(attr.String())
}
buf.WriteString("]")
}
return buf.String()
}
// An Edge represents an edge between two vertices.
type Edge struct {
// Directed edge.
Directed bool
// Destination vertex.
Vertex Vertex
// Outgoing edge; or nil if none.
To *Edge
}
// String returns the string representation of the edge.
func (e *Edge) String() string {
op := "--"
if e.Directed {
op = "->"
}
if e.To != nil {
return fmt.Sprintf("%s %s %s", op, e.Vertex, e.To)
}
return fmt.Sprintf("%s %s", op, e.Vertex)
}
// --- [ Attribute statement ] -------------------------------------------------
// An AttrStmt represents an attribute statement.
//
// Examples.
//
// graph [rankdir=LR]
// node [color=blue fillcolor=red]
// edge [minlen=1]
type AttrStmt struct {
// Graph component kind to which the attributes are assigned.
Kind Kind
// Attributes.
Attrs []*Attr
}
// String returns the string representation of the attribute statement.
func (a *AttrStmt) String() string {
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "%s [", a.Kind)
for i, attr := range a.Attrs {
if i != 0 {
buf.WriteString(" ")
}
buf.WriteString(attr.String())
}
buf.WriteString("]")
return buf.String()
}
// Kind specifies the set of graph components to which attribute statements may
// be assigned.
type Kind uint
// Graph component kinds.
const (
GraphKind Kind = iota // graph
NodeKind // node
EdgeKind // edge
)
// String returns the string representation of the graph component kind.
func (k Kind) String() string {
switch k {
case GraphKind:
return "graph"
case NodeKind:
return "node"
case EdgeKind:
return "edge"
}
panic(fmt.Sprintf("invalid graph component kind (%d)", k))
}
// --- [ Attribute ] -----------------------------------------------------------
// An Attr represents an attribute.
//
// Examples.
//
// rank=same
type Attr struct {
// Attribute key.
Key string
// Attribute value.
Val string
}
// String returns the string representation of the attribute.
func (a *Attr) String() string {
return fmt.Sprintf("%s=%s", a.Key, a.Val)
}
// --- [ Subgraph ] ------------------------------------------------------------
// A Subgraph represents a subgraph vertex.
//
// Examples.
//
// subgraph S {A B C}
type Subgraph struct {
// Subgraph ID; or empty if none.
ID string
// Subgraph statements.
Stmts []Stmt
}
// String returns the string representation of the subgraph.
func (s *Subgraph) String() string {
buf := new(bytes.Buffer)
if len(s.ID) > 0 {
fmt.Fprintf(buf, "subgraph %s ", s.ID)
}
buf.WriteString("{")
for i, stmt := range s.Stmts {
if i != 0 {
buf.WriteString(" ")
}
buf.WriteString(stmt.String())
}
buf.WriteString("}")
return buf.String()
}
// isStmt ensures that only statements can be assigned to the Stmt interface.
func (*NodeStmt) isStmt() {}
func (*EdgeStmt) isStmt() {}
func (*AttrStmt) isStmt() {}
func (*Attr) isStmt() {}
func (*Subgraph) isStmt() {}
// === [ Vertices ] ============================================================
// A Vertex represents a vertex, and has one of the following underlying types.
//
// *Node
// *Subgraph
type Vertex interface {
fmt.Stringer
// isVertex ensures that only vertices can be assigned to the Vertex
// interface.
isVertex()
}
// --- [ Node identifier ] -----------------------------------------------------
// A Node represents a node vertex.
//
// Examples.
//
// A
// A:nw
type Node struct {
// Node ID.
ID string
// Node port; or nil if none.
Port *Port
}
// String returns the string representation of the node.
func (n *Node) String() string {
if n.Port != nil {
return fmt.Sprintf("%s%s", n.ID, n.Port)
}
return n.ID
}
// A Port specifies where on a node an edge should be aimed.
type Port struct {
// Port ID; or empty if none.
ID string
// Compass point.
CompassPoint CompassPoint
}
// String returns the string representation of the port.
func (p *Port) String() string {
buf := new(bytes.Buffer)
if len(p.ID) > 0 {
fmt.Fprintf(buf, ":%s", p.ID)
}
if p.CompassPoint != CompassPointNone {
fmt.Fprintf(buf, ":%s", p.CompassPoint)
}
return buf.String()
}
// CompassPoint specifies the set of compass points.
type CompassPoint uint
// Compass points.
const (
CompassPointNone CompassPoint = iota //
CompassPointNorth // n
CompassPointNorthEast // ne
CompassPointEast // e
CompassPointSouthEast // se
CompassPointSouth // s
CompassPointSouthWest // sw
CompassPointWest // w
CompassPointNorthWest // nw
CompassPointCenter // c
CompassPointDefault // _
)
// String returns the string representation of the compass point.
func (c CompassPoint) String() string {
switch c {
case CompassPointNone:
return ""
case CompassPointNorth:
return "n"
case CompassPointNorthEast:
return "ne"
case CompassPointEast:
return "e"
case CompassPointSouthEast:
return "se"
case CompassPointSouth:
return "s"
case CompassPointSouthWest:
return "sw"
case CompassPointWest:
return "w"
case CompassPointNorthWest:
return "nw"
case CompassPointCenter:
return "c"
case CompassPointDefault:
return "_"
}
panic(fmt.Sprintf("invalid compass point (%d)", uint(c)))
}
// isVertex ensures that only vertices can be assigned to the Vertex interface.
func (*Node) isVertex() {}
func (*Subgraph) isVertex() {}

View File

@ -1,7 +0,0 @@
// Copyright ©2017 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 ast declares the types used to represent abstract syntax trees of
// Graphviz DOT graphs.
package ast // import "gonum.org/v1/gonum/graph/formats/dot/ast"

View File

@ -1,6 +0,0 @@
// Copyright ©2017 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 a parser for Graphviz DOT files.
package dot // import "gonum.org/v1/gonum/graph/formats/dot"

View File

@ -1,64 +0,0 @@
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
//go:generate ./makeinternal.bash
package dot
import (
"fmt"
"io"
"io/ioutil"
"gonum.org/v1/gonum/graph/formats/dot/ast"
"gonum.org/v1/gonum/graph/formats/dot/internal/lexer"
"gonum.org/v1/gonum/graph/formats/dot/internal/parser"
)
// ParseFile parses the given Graphviz DOT file into an AST.
func ParseFile(path string) (*ast.File, error) {
buf, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return ParseBytes(buf)
}
// Parse parses the given Graphviz DOT file into an AST, reading from r.
func Parse(r io.Reader) (*ast.File, error) {
buf, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
return ParseBytes(buf)
}
// ParseBytes parses the given Graphviz DOT file into an AST, reading from b.
func ParseBytes(b []byte) (*ast.File, error) {
l := lexer.NewLexer(b)
p := parser.NewParser()
file, err := p.Parse(l)
if err != nil {
return nil, err
}
f, ok := file.(*ast.File)
if !ok {
return nil, fmt.Errorf("invalid file type; expected *ast.File, got %T", file)
}
if err := check(f); err != nil {
return nil, err
}
return f, nil
}
// ParseString parses the given Graphviz DOT file into an AST, reading from s.
func ParseString(s string) (*ast.File, error) {
return ParseBytes([]byte(s))
}

View File

@ -1,326 +0,0 @@
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
package astx
import (
"fmt"
"strings"
"gonum.org/v1/gonum/graph/formats/dot/ast"
"gonum.org/v1/gonum/graph/formats/dot/internal/token"
)
// === [ File ] ================================================================
// NewFile returns a new file based on the given graph.
func NewFile(graph interface{}) (*ast.File, error) {
g, ok := graph.(*ast.Graph)
if !ok {
return nil, fmt.Errorf("invalid graph type; expected *ast.Graph, got %T", graph)
}
return &ast.File{Graphs: []*ast.Graph{g}}, nil
}
// AppendGraph appends graph to the given file.
func AppendGraph(file, graph interface{}) (*ast.File, error) {
f, ok := file.(*ast.File)
if !ok {
return nil, fmt.Errorf("invalid file type; expected *ast.File, got %T", file)
}
g, ok := graph.(*ast.Graph)
if !ok {
return nil, fmt.Errorf("invalid graph type; expected *ast.Graph, got %T", graph)
}
f.Graphs = append(f.Graphs, g)
return f, nil
}
// === [ Graphs ] ==============================================================
// NewGraph returns a new graph based on the given graph strictness, direction,
// optional ID and optional statements.
func NewGraph(strict, directed, optID, optStmts interface{}) (*ast.Graph, error) {
s, ok := strict.(bool)
if !ok {
return nil, fmt.Errorf("invalid strictness type; expected bool, got %T", strict)
}
d, ok := directed.(bool)
if !ok {
return nil, fmt.Errorf("invalid direction type; expected bool, got %T", directed)
}
id, ok := optID.(string)
if optID != nil && !ok {
return nil, fmt.Errorf("invalid ID type; expected string or nil, got %T", optID)
}
stmts, ok := optStmts.([]ast.Stmt)
if optStmts != nil && !ok {
return nil, fmt.Errorf("invalid statements type; expected []ast.Stmt or nil, got %T", optStmts)
}
return &ast.Graph{Strict: s, Directed: d, ID: id, Stmts: stmts}, nil
}
// === [ Statements ] ==========================================================
// NewStmtList returns a new statement list based on the given statement.
func NewStmtList(stmt interface{}) ([]ast.Stmt, error) {
s, ok := stmt.(ast.Stmt)
if !ok {
return nil, fmt.Errorf("invalid statement type; expected ast.Stmt, got %T", stmt)
}
return []ast.Stmt{s}, nil
}
// AppendStmt appends stmt to the given statement list.
func AppendStmt(list, stmt interface{}) ([]ast.Stmt, error) {
l, ok := list.([]ast.Stmt)
if !ok {
return nil, fmt.Errorf("invalid statement list type; expected []ast.Stmt, got %T", list)
}
s, ok := stmt.(ast.Stmt)
if !ok {
return nil, fmt.Errorf("invalid statement type; expected ast.Stmt, got %T", stmt)
}
return append(l, s), nil
}
// --- [ Node statement ] ------------------------------------------------------
// NewNodeStmt returns a new node statement based on the given node and optional
// attributes.
func NewNodeStmt(node, optAttrs interface{}) (*ast.NodeStmt, error) {
n, ok := node.(*ast.Node)
if !ok {
return nil, fmt.Errorf("invalid node type; expected *ast.Node, got %T", node)
}
attrs, ok := optAttrs.([]*ast.Attr)
if optAttrs != nil && !ok {
return nil, fmt.Errorf("invalid attributes type; expected []*ast.Attr or nil, got %T", optAttrs)
}
return &ast.NodeStmt{Node: n, Attrs: attrs}, nil
}
// --- [ Edge statement ] ------------------------------------------------------
// NewEdgeStmt returns a new edge statement based on the given source vertex,
// outgoing edge and optional attributes.
func NewEdgeStmt(from, to, optAttrs interface{}) (*ast.EdgeStmt, error) {
f, ok := from.(ast.Vertex)
if !ok {
return nil, fmt.Errorf("invalid source vertex type; expected ast.Vertex, got %T", from)
}
t, ok := to.(*ast.Edge)
if !ok {
return nil, fmt.Errorf("invalid outgoing edge type; expected *ast.Edge, got %T", to)
}
attrs, ok := optAttrs.([]*ast.Attr)
if optAttrs != nil && !ok {
return nil, fmt.Errorf("invalid attributes type; expected []*ast.Attr or nil, got %T", optAttrs)
}
return &ast.EdgeStmt{From: f, To: t, Attrs: attrs}, nil
}
// NewEdge returns a new edge based on the given edge direction, destination
// vertex and optional outgoing edge.
func NewEdge(directed, vertex, optTo interface{}) (*ast.Edge, error) {
d, ok := directed.(bool)
if !ok {
return nil, fmt.Errorf("invalid direction type; expected bool, got %T", directed)
}
v, ok := vertex.(ast.Vertex)
if !ok {
return nil, fmt.Errorf("invalid destination vertex type; expected ast.Vertex, got %T", vertex)
}
to, ok := optTo.(*ast.Edge)
if optTo != nil && !ok {
return nil, fmt.Errorf("invalid outgoing edge type; expected *ast.Edge or nil, got %T", optTo)
}
return &ast.Edge{Directed: d, Vertex: v, To: to}, nil
}
// --- [ Attribute statement ] -------------------------------------------------
// NewAttrStmt returns a new attribute statement based on the given graph
// component kind and attributes.
func NewAttrStmt(kind, optAttrs interface{}) (*ast.AttrStmt, error) {
k, ok := kind.(ast.Kind)
if !ok {
return nil, fmt.Errorf("invalid graph component kind type; expected ast.Kind, got %T", kind)
}
attrs, ok := optAttrs.([]*ast.Attr)
if optAttrs != nil && !ok {
return nil, fmt.Errorf("invalid attributes type; expected []*ast.Attr or nil, got %T", optAttrs)
}
return &ast.AttrStmt{Kind: k, Attrs: attrs}, nil
}
// NewAttrList returns a new attribute list based on the given attribute.
func NewAttrList(attr interface{}) ([]*ast.Attr, error) {
a, ok := attr.(*ast.Attr)
if !ok {
return nil, fmt.Errorf("invalid attribute type; expected *ast.Attr, got %T", attr)
}
return []*ast.Attr{a}, nil
}
// AppendAttr appends attr to the given attribute list.
func AppendAttr(list, attr interface{}) ([]*ast.Attr, error) {
l, ok := list.([]*ast.Attr)
if !ok {
return nil, fmt.Errorf("invalid attribute list type; expected []*ast.Attr, got %T", list)
}
a, ok := attr.(*ast.Attr)
if !ok {
return nil, fmt.Errorf("invalid attribute type; expected *ast.Attr, got %T", attr)
}
return append(l, a), nil
}
// AppendAttrList appends the optional attrs to the given optional attribute
// list.
func AppendAttrList(optList, optAttrs interface{}) ([]*ast.Attr, error) {
list, ok := optList.([]*ast.Attr)
if optList != nil && !ok {
return nil, fmt.Errorf("invalid attribute list type; expected []*ast.Attr or nil, got %T", optList)
}
attrs, ok := optAttrs.([]*ast.Attr)
if optAttrs != nil && !ok {
return nil, fmt.Errorf("invalid attributes type; expected []*ast.Attr or nil, got %T", optAttrs)
}
return append(list, attrs...), nil
}
// --- [ Attribute ] -----------------------------------------------------------
// NewAttr returns a new attribute based on the given key-value pair.
func NewAttr(key, val interface{}) (*ast.Attr, error) {
k, ok := key.(string)
if !ok {
return nil, fmt.Errorf("invalid key type; expected string, got %T", key)
}
v, ok := val.(string)
if !ok {
return nil, fmt.Errorf("invalid value type; expected string, got %T", val)
}
return &ast.Attr{Key: k, Val: v}, nil
}
// --- [ Subgraph ] ------------------------------------------------------------
// NewSubgraph returns a new subgraph based on the given optional subgraph ID
// and optional statements.
func NewSubgraph(optID, optStmts interface{}) (*ast.Subgraph, error) {
id, ok := optID.(string)
if optID != nil && !ok {
return nil, fmt.Errorf("invalid ID type; expected string or nil, got %T", optID)
}
stmts, ok := optStmts.([]ast.Stmt)
if optStmts != nil && !ok {
return nil, fmt.Errorf("invalid statements type; expected []ast.Stmt or nil, got %T", optStmts)
}
return &ast.Subgraph{ID: id, Stmts: stmts}, nil
}
// === [ Vertices ] ============================================================
// --- [ Node identifier ] -----------------------------------------------------
// NewNode returns a new node based on the given node id and optional port.
func NewNode(id, optPort interface{}) (*ast.Node, error) {
i, ok := id.(string)
if !ok {
return nil, fmt.Errorf("invalid ID type; expected string, got %T", id)
}
port, ok := optPort.(*ast.Port)
if optPort != nil && !ok {
return nil, fmt.Errorf("invalid port type; expected *ast.Port or nil, got %T", optPort)
}
return &ast.Node{ID: i, Port: port}, nil
}
// NewPort returns a new port based on the given id and optional compass point.
func NewPort(id, optCompassPoint interface{}) (*ast.Port, error) {
// Note, if optCompassPoint is nil, id may be either an identifier or a
// compass point.
//
// The following strings are valid compass points:
//
// "n", "ne", "e", "se", "s", "sw", "w", "nw", "c" and "_"
i, ok := id.(string)
if !ok {
return nil, fmt.Errorf("invalid ID type; expected string, got %T", id)
}
// Early return if optional compass point is absent and ID is a valid compass
// point.
if optCompassPoint == nil {
if compassPoint, ok := getCompassPoint(i); ok {
return &ast.Port{CompassPoint: compassPoint}, nil
}
}
c, ok := optCompassPoint.(string)
if optCompassPoint != nil && !ok {
return nil, fmt.Errorf("invalid compass point type; expected string or nil, got %T", optCompassPoint)
}
compassPoint, _ := getCompassPoint(c)
return &ast.Port{ID: i, CompassPoint: compassPoint}, nil
}
// getCompassPoint returns the corresponding compass point to the given string,
// and a boolean value indicating if such a compass point exists.
func getCompassPoint(s string) (ast.CompassPoint, bool) {
switch s {
case "_":
return ast.CompassPointDefault, true
case "n":
return ast.CompassPointNorth, true
case "ne":
return ast.CompassPointNorthEast, true
case "e":
return ast.CompassPointEast, true
case "se":
return ast.CompassPointSouthEast, true
case "s":
return ast.CompassPointSouth, true
case "sw":
return ast.CompassPointSouthWest, true
case "w":
return ast.CompassPointWest, true
case "nw":
return ast.CompassPointNorthWest, true
case "c":
return ast.CompassPointCenter, true
}
return ast.CompassPointNone, false
}
// === [ Identifiers ] =========================================================
// NewID returns a new identifier based on the given ID token.
func NewID(id interface{}) (string, error) {
i, ok := id.(*token.Token)
if !ok {
return "", fmt.Errorf("invalid identifier type; expected *token.Token, got %T", id)
}
s := string(i.Lit)
// As another aid for readability, dot allows double-quoted strings to span
// multiple physical lines using the standard C convention of a backslash
// immediately preceding a newline character.
if strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) {
// Strip "\\\n" sequences.
s = strings.Replace(s, "\\\n", "", -1)
}
// TODO: Add support for concatenated using a '+' operator.
return s, nil
}

View File

@ -1,7 +0,0 @@
// Copyright ©2017 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 astx implements utility functions for generating abstract syntax
// trees of Graphviz DOT graphs.
package astx // import "gonum.org/v1/gonum/graph/formats/dot/internal/astx"

View File

@ -1,6 +0,0 @@
// Copyright ©2018 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 error provides generated internal error functions for DOT parsing.
package errors // import "gonum.org/v1/gonum/graph/formats/dot/internal/errors"

View File

@ -1,66 +0,0 @@
// Code generated by gocc; DO NOT EDIT.
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
package errors
import (
"fmt"
"strings"
"gonum.org/v1/gonum/graph/formats/dot/internal/token"
)
type ErrorSymbol interface {
}
type Error struct {
Err error
ErrorToken *token.Token
ErrorSymbols []ErrorSymbol
ExpectedTokens []string
StackTop int
}
func (e *Error) String() string {
w := new(strings.Builder)
fmt.Fprintf(w, "Error")
if e.Err != nil {
fmt.Fprintf(w, " %s\n", e.Err)
} else {
fmt.Fprintf(w, "\n")
}
fmt.Fprintf(w, "Token: type=%d, lit=%s\n", e.ErrorToken.Type, e.ErrorToken.Lit)
fmt.Fprintf(w, "Pos: offset=%d, line=%d, column=%d\n", e.ErrorToken.Pos.Offset, e.ErrorToken.Pos.Line, e.ErrorToken.Pos.Column)
fmt.Fprintf(w, "Expected one of: ")
for _, sym := range e.ExpectedTokens {
fmt.Fprintf(w, "%s ", sym)
}
fmt.Fprintf(w, "ErrorSymbol:\n")
for _, sym := range e.ErrorSymbols {
fmt.Fprintf(w, "%v\n", sym)
}
return w.String()
}
func (e *Error) Error() string {
w := new(strings.Builder)
fmt.Fprintf(w, "Error in S%d: %s, %s", e.StackTop, token.TokMap.TokenString(e.ErrorToken), e.ErrorToken.Pos.String())
if e.Err != nil {
fmt.Fprintf(w, ": %+v", e.Err)
} else {
fmt.Fprintf(w, ", expected one of: ")
for _, expected := range e.ExpectedTokens {
fmt.Fprintf(w, "%s ", expected)
}
}
return w.String()
}

View File

@ -1,605 +0,0 @@
// Code generated by gocc; DO NOT EDIT.
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
package lexer
import (
"fmt"
"gonum.org/v1/gonum/graph/formats/dot/internal/token"
)
type ActionTable [NumStates]ActionRow
type ActionRow struct {
Accept token.Type
Ignore string
}
func (a ActionRow) String() string {
return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore)
}
var ActTab = ActionTable{
ActionRow{ // S0
Accept: 0,
Ignore: "",
},
ActionRow{ // S1
Accept: -1,
Ignore: "!whitespace",
},
ActionRow{ // S2
Accept: 0,
Ignore: "",
},
ActionRow{ // S3
Accept: 0,
Ignore: "",
},
ActionRow{ // S4
Accept: 15,
Ignore: "",
},
ActionRow{ // S5
Accept: 0,
Ignore: "",
},
ActionRow{ // S6
Accept: 0,
Ignore: "",
},
ActionRow{ // S7
Accept: 0,
Ignore: "",
},
ActionRow{ // S8
Accept: 19,
Ignore: "",
},
ActionRow{ // S9
Accept: 18,
Ignore: "",
},
ActionRow{ // S10
Accept: 8,
Ignore: "",
},
ActionRow{ // S11
Accept: 0,
Ignore: "",
},
ActionRow{ // S12
Accept: 16,
Ignore: "",
},
ActionRow{ // S13
Accept: 19,
Ignore: "",
},
ActionRow{ // S14
Accept: 19,
Ignore: "",
},
ActionRow{ // S15
Accept: 19,
Ignore: "",
},
ActionRow{ // S16
Accept: 19,
Ignore: "",
},
ActionRow{ // S17
Accept: 19,
Ignore: "",
},
ActionRow{ // S18
Accept: 19,
Ignore: "",
},
ActionRow{ // S19
Accept: 13,
Ignore: "",
},
ActionRow{ // S20
Accept: 14,
Ignore: "",
},
ActionRow{ // S21
Accept: 19,
Ignore: "",
},
ActionRow{ // S22
Accept: 19,
Ignore: "",
},
ActionRow{ // S23
Accept: 19,
Ignore: "",
},
ActionRow{ // S24
Accept: 19,
Ignore: "",
},
ActionRow{ // S25
Accept: 19,
Ignore: "",
},
ActionRow{ // S26
Accept: 19,
Ignore: "",
},
ActionRow{ // S27
Accept: 2,
Ignore: "",
},
ActionRow{ // S28
Accept: 3,
Ignore: "",
},
ActionRow{ // S29
Accept: 19,
Ignore: "",
},
ActionRow{ // S30
Accept: 0,
Ignore: "",
},
ActionRow{ // S31
Accept: 19,
Ignore: "",
},
ActionRow{ // S32
Accept: 0,
Ignore: "",
},
ActionRow{ // S33
Accept: 0,
Ignore: "",
},
ActionRow{ // S34
Accept: -1,
Ignore: "!comment",
},
ActionRow{ // S35
Accept: 9,
Ignore: "",
},
ActionRow{ // S36
Accept: 10,
Ignore: "",
},
ActionRow{ // S37
Accept: 19,
Ignore: "",
},
ActionRow{ // S38
Accept: 0,
Ignore: "",
},
ActionRow{ // S39
Accept: 0,
Ignore: "",
},
ActionRow{ // S40
Accept: 19,
Ignore: "",
},
ActionRow{ // S41
Accept: 0,
Ignore: "",
},
ActionRow{ // S42
Accept: 0,
Ignore: "",
},
ActionRow{ // S43
Accept: 19,
Ignore: "",
},
ActionRow{ // S44
Accept: 0,
Ignore: "",
},
ActionRow{ // S45
Accept: 19,
Ignore: "",
},
ActionRow{ // S46
Accept: 19,
Ignore: "",
},
ActionRow{ // S47
Accept: 19,
Ignore: "",
},
ActionRow{ // S48
Accept: 19,
Ignore: "",
},
ActionRow{ // S49
Accept: 19,
Ignore: "",
},
ActionRow{ // S50
Accept: 19,
Ignore: "",
},
ActionRow{ // S51
Accept: 19,
Ignore: "",
},
ActionRow{ // S52
Accept: 19,
Ignore: "",
},
ActionRow{ // S53
Accept: 19,
Ignore: "",
},
ActionRow{ // S54
Accept: 19,
Ignore: "",
},
ActionRow{ // S55
Accept: 19,
Ignore: "",
},
ActionRow{ // S56
Accept: 19,
Ignore: "",
},
ActionRow{ // S57
Accept: 19,
Ignore: "",
},
ActionRow{ // S58
Accept: 19,
Ignore: "",
},
ActionRow{ // S59
Accept: 19,
Ignore: "",
},
ActionRow{ // S60
Accept: 19,
Ignore: "",
},
ActionRow{ // S61
Accept: 19,
Ignore: "",
},
ActionRow{ // S62
Accept: 19,
Ignore: "",
},
ActionRow{ // S63
Accept: 19,
Ignore: "",
},
ActionRow{ // S64
Accept: 0,
Ignore: "",
},
ActionRow{ // S65
Accept: 0,
Ignore: "",
},
ActionRow{ // S66
Accept: 0,
Ignore: "",
},
ActionRow{ // S67
Accept: 0,
Ignore: "",
},
ActionRow{ // S68
Accept: 19,
Ignore: "",
},
ActionRow{ // S69
Accept: 0,
Ignore: "",
},
ActionRow{ // S70
Accept: 0,
Ignore: "",
},
ActionRow{ // S71
Accept: 19,
Ignore: "",
},
ActionRow{ // S72
Accept: 19,
Ignore: "",
},
ActionRow{ // S73
Accept: 19,
Ignore: "",
},
ActionRow{ // S74
Accept: 19,
Ignore: "",
},
ActionRow{ // S75
Accept: 19,
Ignore: "",
},
ActionRow{ // S76
Accept: 19,
Ignore: "",
},
ActionRow{ // S77
Accept: 19,
Ignore: "",
},
ActionRow{ // S78
Accept: 19,
Ignore: "",
},
ActionRow{ // S79
Accept: 19,
Ignore: "",
},
ActionRow{ // S80
Accept: 19,
Ignore: "",
},
ActionRow{ // S81
Accept: 19,
Ignore: "",
},
ActionRow{ // S82
Accept: 19,
Ignore: "",
},
ActionRow{ // S83
Accept: 19,
Ignore: "",
},
ActionRow{ // S84
Accept: 19,
Ignore: "",
},
ActionRow{ // S85
Accept: 19,
Ignore: "",
},
ActionRow{ // S86
Accept: 19,
Ignore: "",
},
ActionRow{ // S87
Accept: 19,
Ignore: "",
},
ActionRow{ // S88
Accept: 19,
Ignore: "",
},
ActionRow{ // S89
Accept: 19,
Ignore: "",
},
ActionRow{ // S90
Accept: 19,
Ignore: "",
},
ActionRow{ // S91
Accept: -1,
Ignore: "!comment",
},
ActionRow{ // S92
Accept: 0,
Ignore: "",
},
ActionRow{ // S93
Accept: 19,
Ignore: "",
},
ActionRow{ // S94
Accept: 19,
Ignore: "",
},
ActionRow{ // S95
Accept: 19,
Ignore: "",
},
ActionRow{ // S96
Accept: 12,
Ignore: "",
},
ActionRow{ // S97
Accept: 19,
Ignore: "",
},
ActionRow{ // S98
Accept: 19,
Ignore: "",
},
ActionRow{ // S99
Accept: 11,
Ignore: "",
},
ActionRow{ // S100
Accept: 19,
Ignore: "",
},
ActionRow{ // S101
Accept: 19,
Ignore: "",
},
ActionRow{ // S102
Accept: 19,
Ignore: "",
},
ActionRow{ // S103
Accept: 19,
Ignore: "",
},
ActionRow{ // S104
Accept: 19,
Ignore: "",
},
ActionRow{ // S105
Accept: 19,
Ignore: "",
},
ActionRow{ // S106
Accept: 19,
Ignore: "",
},
ActionRow{ // S107
Accept: 19,
Ignore: "",
},
ActionRow{ // S108
Accept: 19,
Ignore: "",
},
ActionRow{ // S109
Accept: 19,
Ignore: "",
},
ActionRow{ // S110
Accept: 19,
Ignore: "",
},
ActionRow{ // S111
Accept: 19,
Ignore: "",
},
ActionRow{ // S112
Accept: 19,
Ignore: "",
},
ActionRow{ // S113
Accept: 19,
Ignore: "",
},
ActionRow{ // S114
Accept: 6,
Ignore: "",
},
ActionRow{ // S115
Accept: 19,
Ignore: "",
},
ActionRow{ // S116
Accept: 19,
Ignore: "",
},
ActionRow{ // S117
Accept: 19,
Ignore: "",
},
ActionRow{ // S118
Accept: 19,
Ignore: "",
},
ActionRow{ // S119
Accept: 19,
Ignore: "",
},
ActionRow{ // S120
Accept: 19,
Ignore: "",
},
ActionRow{ // S121
Accept: 19,
Ignore: "",
},
ActionRow{ // S122
Accept: 19,
Ignore: "",
},
ActionRow{ // S123
Accept: 19,
Ignore: "",
},
ActionRow{ // S124
Accept: 19,
Ignore: "",
},
ActionRow{ // S125
Accept: 19,
Ignore: "",
},
ActionRow{ // S126
Accept: 19,
Ignore: "",
},
ActionRow{ // S127
Accept: 19,
Ignore: "",
},
ActionRow{ // S128
Accept: 5,
Ignore: "",
},
ActionRow{ // S129
Accept: 19,
Ignore: "",
},
ActionRow{ // S130
Accept: 19,
Ignore: "",
},
ActionRow{ // S131
Accept: 19,
Ignore: "",
},
ActionRow{ // S132
Accept: 19,
Ignore: "",
},
ActionRow{ // S133
Accept: 19,
Ignore: "",
},
ActionRow{ // S134
Accept: 19,
Ignore: "",
},
ActionRow{ // S135
Accept: 19,
Ignore: "",
},
ActionRow{ // S136
Accept: 7,
Ignore: "",
},
ActionRow{ // S137
Accept: 19,
Ignore: "",
},
ActionRow{ // S138
Accept: 19,
Ignore: "",
},
ActionRow{ // S139
Accept: 19,
Ignore: "",
},
ActionRow{ // S140
Accept: 19,
Ignore: "",
},
ActionRow{ // S141
Accept: 19,
Ignore: "",
},
ActionRow{ // S142
Accept: 17,
Ignore: "",
},
}

View File

@ -1,6 +0,0 @@
// Copyright ©2018 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 lexer provides generated internal lexer functions for DOT parsing.
package lexer // import "gonum.org/v1/gonum/graph/formats/dot/internal/lexer"

View File

@ -1,310 +0,0 @@
// Code generated by gocc; DO NOT EDIT.
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
package lexer
import (
"io/ioutil"
"unicode/utf8"
"gonum.org/v1/gonum/graph/formats/dot/internal/token"
)
const (
NoState = -1
NumStates = 143
NumSymbols = 184
)
type Lexer struct {
src []byte
pos int
line int
column int
}
func NewLexer(src []byte) *Lexer {
lexer := &Lexer{
src: src,
pos: 0,
line: 1,
column: 1,
}
return lexer
}
func NewLexerFile(fpath string) (*Lexer, error) {
src, err := ioutil.ReadFile(fpath)
if err != nil {
return nil, err
}
return NewLexer(src), nil
}
func (l *Lexer) Scan() (tok *token.Token) {
tok = new(token.Token)
if l.pos >= len(l.src) {
tok.Type = token.EOF
tok.Pos.Offset, tok.Pos.Line, tok.Pos.Column = l.pos, l.line, l.column
return
}
start, startLine, startColumn, end := l.pos, l.line, l.column, 0
tok.Type = token.INVALID
state, rune1, size := 0, rune(-1), 0
for state != -1 {
if l.pos >= len(l.src) {
rune1 = -1
} else {
rune1, size = utf8.DecodeRune(l.src[l.pos:])
l.pos += size
}
nextState := -1
if rune1 != -1 {
nextState = TransTab[state](rune1)
}
state = nextState
if state != -1 {
switch rune1 {
case '\n':
l.line++
l.column = 1
case '\r':
l.column = 1
case '\t':
l.column += 4
default:
l.column++
}
switch {
case ActTab[state].Accept != -1:
tok.Type = ActTab[state].Accept
end = l.pos
case ActTab[state].Ignore != "":
start, startLine, startColumn = l.pos, l.line, l.column
state = 0
if start >= len(l.src) {
tok.Type = token.EOF
}
}
} else {
if tok.Type == token.INVALID {
end = l.pos
}
}
}
if end > start {
l.pos = end
tok.Lit = l.src[start:end]
} else {
tok.Lit = []byte{}
}
tok.Pos.Offset, tok.Pos.Line, tok.Pos.Column = start, startLine, startColumn
return
}
func (l *Lexer) Reset() {
l.pos = 0
}
/*
Lexer symbols:
0: 'n'
1: 'o'
2: 'd'
3: 'e'
4: 'N'
5: 'o'
6: 'd'
7: 'e'
8: 'N'
9: 'O'
10: 'D'
11: 'E'
12: 'e'
13: 'd'
14: 'g'
15: 'e'
16: 'E'
17: 'd'
18: 'g'
19: 'e'
20: 'E'
21: 'D'
22: 'G'
23: 'E'
24: 'g'
25: 'r'
26: 'a'
27: 'p'
28: 'h'
29: 'G'
30: 'r'
31: 'a'
32: 'p'
33: 'h'
34: 'G'
35: 'R'
36: 'A'
37: 'P'
38: 'H'
39: 'd'
40: 'i'
41: 'g'
42: 'r'
43: 'a'
44: 'p'
45: 'h'
46: 'D'
47: 'i'
48: 'g'
49: 'r'
50: 'a'
51: 'p'
52: 'h'
53: 'd'
54: 'i'
55: 'G'
56: 'r'
57: 'a'
58: 'p'
59: 'h'
60: 'D'
61: 'i'
62: 'G'
63: 'r'
64: 'a'
65: 'p'
66: 'h'
67: 'D'
68: 'I'
69: 'G'
70: 'R'
71: 'A'
72: 'P'
73: 'H'
74: 's'
75: 'u'
76: 'b'
77: 'g'
78: 'r'
79: 'a'
80: 'p'
81: 'h'
82: 'S'
83: 'u'
84: 'b'
85: 'g'
86: 'r'
87: 'a'
88: 'p'
89: 'h'
90: 's'
91: 'u'
92: 'b'
93: 'G'
94: 'r'
95: 'a'
96: 'p'
97: 'h'
98: 'S'
99: 'u'
100: 'b'
101: 'G'
102: 'r'
103: 'a'
104: 'p'
105: 'h'
106: 'S'
107: 'U'
108: 'B'
109: 'G'
110: 'R'
111: 'A'
112: 'P'
113: 'H'
114: 's'
115: 't'
116: 'r'
117: 'i'
118: 'c'
119: 't'
120: 'S'
121: 't'
122: 'r'
123: 'i'
124: 'c'
125: 't'
126: 'S'
127: 'T'
128: 'R'
129: 'I'
130: 'C'
131: 'T'
132: '{'
133: '}'
134: ';'
135: '-'
136: '-'
137: '-'
138: '>'
139: '['
140: ']'
141: ','
142: '='
143: ':'
144: '_'
145: '-'
146: '.'
147: '-'
148: '.'
149: '\'
150: '"'
151: '\'
152: '"'
153: '"'
154: '='
155: '<'
156: '>'
157: '<'
158: '>'
159: '/'
160: '/'
161: '\n'
162: '#'
163: '\n'
164: '/'
165: '*'
166: '*'
167: '*'
168: '/'
169: ' '
170: '\t'
171: '\r'
172: '\n'
173: \u0001-'!'
174: '#'-'['
175: ']'-\u007f
176: 'a'-'z'
177: 'A'-'Z'
178: '0'-'9'
179: \u0080-\ufffc
180: \ufffe-\U0010ffff
181: \u0001-';'
182: '?'-\u00ff
183: .
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +0,0 @@
// Code generated by gocc; DO NOT EDIT.
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
package parser
import (
"fmt"
)
type action interface {
act()
String() string
}
type (
accept bool
shift int // value is next state index
reduce int // value is production index
)
func (this accept) act() {}
func (this shift) act() {}
func (this reduce) act() {}
func (this accept) Equal(that action) bool {
if _, ok := that.(accept); ok {
return true
}
return false
}
func (this reduce) Equal(that action) bool {
that1, ok := that.(reduce)
if !ok {
return false
}
return this == that1
}
func (this shift) Equal(that action) bool {
that1, ok := that.(shift)
if !ok {
return false
}
return this == that1
}
func (this accept) String() string { return "accept(0)" }
func (this shift) String() string { return fmt.Sprintf("shift:%d", this) }
func (this reduce) String() string {
return fmt.Sprintf("reduce:%d(%s)", this, productionsTable[this].String)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +0,0 @@
// Copyright ©2018 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 parser provides generated internal parsing functions for DOT parsing.
package parser // import "gonum.org/v1/gonum/graph/formats/dot/internal/parser"

File diff suppressed because it is too large Load Diff

View File

@ -1,226 +0,0 @@
// Code generated by gocc; DO NOT EDIT.
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
package parser
import (
"fmt"
"strings"
parseError "gonum.org/v1/gonum/graph/formats/dot/internal/errors"
"gonum.org/v1/gonum/graph/formats/dot/internal/token"
)
const (
numProductions = 55
numStates = 87
numSymbols = 50
)
// Stack
type stack struct {
state []int
attrib []Attrib
}
const iNITIAL_STACK_SIZE = 100
func newStack() *stack {
return &stack{
state: make([]int, 0, iNITIAL_STACK_SIZE),
attrib: make([]Attrib, 0, iNITIAL_STACK_SIZE),
}
}
func (s *stack) reset() {
s.state = s.state[:0]
s.attrib = s.attrib[:0]
}
func (s *stack) push(state int, a Attrib) {
s.state = append(s.state, state)
s.attrib = append(s.attrib, a)
}
func (s *stack) top() int {
return s.state[len(s.state)-1]
}
func (s *stack) peek(pos int) int {
return s.state[pos]
}
func (s *stack) topIndex() int {
return len(s.state) - 1
}
func (s *stack) popN(items int) []Attrib {
lo, hi := len(s.state)-items, len(s.state)
attrib := s.attrib[lo:hi]
s.state = s.state[:lo]
s.attrib = s.attrib[:lo]
return attrib
}
func (s *stack) String() string {
w := new(strings.Builder)
fmt.Fprintf(w, "stack:\n")
for i, st := range s.state {
fmt.Fprintf(w, "\t%d: %d , ", i, st)
if s.attrib[i] == nil {
fmt.Fprintf(w, "nil")
} else {
switch attr := s.attrib[i].(type) {
case *token.Token:
fmt.Fprintf(w, "%s", attr.Lit)
default:
fmt.Fprintf(w, "%v", attr)
}
}
fmt.Fprintf(w, "\n")
}
return w.String()
}
// Parser
type Parser struct {
stack *stack
nextToken *token.Token
pos int
}
type Scanner interface {
Scan() (tok *token.Token)
}
func NewParser() *Parser {
p := &Parser{stack: newStack()}
p.Reset()
return p
}
func (p *Parser) Reset() {
p.stack.reset()
p.stack.push(0, nil)
}
func (p *Parser) Error(err error, scanner Scanner) (recovered bool, errorAttrib *parseError.Error) {
errorAttrib = &parseError.Error{
Err: err,
ErrorToken: p.nextToken,
ErrorSymbols: p.popNonRecoveryStates(),
ExpectedTokens: make([]string, 0, 8),
}
for t, action := range actionTab[p.stack.top()].actions {
if action != nil {
errorAttrib.ExpectedTokens = append(errorAttrib.ExpectedTokens, token.TokMap.Id(token.Type(t)))
}
}
if action := actionTab[p.stack.top()].actions[token.TokMap.Type("error")]; action != nil {
p.stack.push(int(action.(shift)), errorAttrib) // action can only be shift
} else {
return
}
if action := actionTab[p.stack.top()].actions[p.nextToken.Type]; action != nil {
recovered = true
}
for !recovered && p.nextToken.Type != token.EOF {
p.nextToken = scanner.Scan()
if action := actionTab[p.stack.top()].actions[p.nextToken.Type]; action != nil {
recovered = true
}
}
return
}
func (p *Parser) popNonRecoveryStates() (removedAttribs []parseError.ErrorSymbol) {
if rs, ok := p.firstRecoveryState(); ok {
errorSymbols := p.stack.popN(p.stack.topIndex() - rs)
removedAttribs = make([]parseError.ErrorSymbol, len(errorSymbols))
for i, e := range errorSymbols {
removedAttribs[i] = e
}
} else {
removedAttribs = []parseError.ErrorSymbol{}
}
return
}
// recoveryState points to the highest state on the stack, which can recover
func (p *Parser) firstRecoveryState() (recoveryState int, canRecover bool) {
recoveryState, canRecover = p.stack.topIndex(), actionTab[p.stack.top()].canRecover
for recoveryState > 0 && !canRecover {
recoveryState--
canRecover = actionTab[p.stack.peek(recoveryState)].canRecover
}
return
}
func (p *Parser) newError(err error) error {
e := &parseError.Error{
Err: err,
StackTop: p.stack.top(),
ErrorToken: p.nextToken,
}
actRow := actionTab[p.stack.top()]
for i, t := range actRow.actions {
if t != nil {
e.ExpectedTokens = append(e.ExpectedTokens, token.TokMap.Id(token.Type(i)))
}
}
return e
}
func (p *Parser) Parse(scanner Scanner) (res interface{}, err error) {
p.Reset()
p.nextToken = scanner.Scan()
for acc := false; !acc; {
action := actionTab[p.stack.top()].actions[p.nextToken.Type]
if action == nil {
if recovered, errAttrib := p.Error(nil, scanner); !recovered {
p.nextToken = errAttrib.ErrorToken
return nil, p.newError(nil)
}
if action = actionTab[p.stack.top()].actions[p.nextToken.Type]; action == nil {
panic("Error recovery led to invalid action")
}
}
switch act := action.(type) {
case accept:
res = p.stack.popN(1)[0]
acc = true
case shift:
p.stack.push(int(act), p.nextToken)
p.nextToken = scanner.Scan()
case reduce:
prod := productionsTable[int(act)]
attrib, err := prod.ReduceFunc(p.stack.popN(prod.NumSymbols))
if err != nil {
return nil, p.newError(err)
} else {
p.stack.push(gotoTab[p.stack.top()][prod.NTType], attrib)
}
default:
panic("unknown action: " + action.String())
}
}
return res, nil
}

View File

@ -1,586 +0,0 @@
// Code generated by gocc; DO NOT EDIT.
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
package parser
import (
"gonum.org/v1/gonum/graph/formats/dot/ast"
"gonum.org/v1/gonum/graph/formats/dot/internal/astx"
)
type (
//TODO: change type and variable names to be consistent with other tables
ProdTab [numProductions]ProdTabEntry
ProdTabEntry struct {
String string
Id string
NTType int
Index int
NumSymbols int
ReduceFunc func([]Attrib) (Attrib, error)
}
Attrib interface {
}
)
var productionsTable = ProdTab{
ProdTabEntry{
String: `S' : File << >>`,
Id: "S'",
NTType: 0,
Index: 0,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `File : Graph << astx.NewFile(X[0]) >>`,
Id: "File",
NTType: 1,
Index: 1,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewFile(X[0])
},
},
ProdTabEntry{
String: `File : File Graph << astx.AppendGraph(X[0], X[1]) >>`,
Id: "File",
NTType: 1,
Index: 2,
NumSymbols: 2,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.AppendGraph(X[0], X[1])
},
},
ProdTabEntry{
String: `Graph : OptStrict DirectedGraph OptID "{" OptStmtList "}" << astx.NewGraph(X[0], X[1], X[2], X[4]) >>`,
Id: "Graph",
NTType: 2,
Index: 3,
NumSymbols: 6,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewGraph(X[0], X[1], X[2], X[4])
},
},
ProdTabEntry{
String: `OptStrict : empty << false, nil >>`,
Id: "OptStrict",
NTType: 3,
Index: 4,
NumSymbols: 0,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return false, nil
},
},
ProdTabEntry{
String: `OptStrict : strict << true, nil >>`,
Id: "OptStrict",
NTType: 3,
Index: 5,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return true, nil
},
},
ProdTabEntry{
String: `DirectedGraph : graphx << false, nil >>`,
Id: "DirectedGraph",
NTType: 4,
Index: 6,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return false, nil
},
},
ProdTabEntry{
String: `DirectedGraph : digraph << true, nil >>`,
Id: "DirectedGraph",
NTType: 4,
Index: 7,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return true, nil
},
},
ProdTabEntry{
String: `StmtList : Stmt OptSemi << astx.NewStmtList(X[0]) >>`,
Id: "StmtList",
NTType: 5,
Index: 8,
NumSymbols: 2,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewStmtList(X[0])
},
},
ProdTabEntry{
String: `StmtList : StmtList Stmt OptSemi << astx.AppendStmt(X[0], X[1]) >>`,
Id: "StmtList",
NTType: 5,
Index: 9,
NumSymbols: 3,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.AppendStmt(X[0], X[1])
},
},
ProdTabEntry{
String: `OptStmtList : empty << >>`,
Id: "OptStmtList",
NTType: 6,
Index: 10,
NumSymbols: 0,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return nil, nil
},
},
ProdTabEntry{
String: `OptStmtList : StmtList << >>`,
Id: "OptStmtList",
NTType: 6,
Index: 11,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `Stmt : NodeStmt << >>`,
Id: "Stmt",
NTType: 7,
Index: 12,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `Stmt : EdgeStmt << >>`,
Id: "Stmt",
NTType: 7,
Index: 13,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `Stmt : AttrStmt << >>`,
Id: "Stmt",
NTType: 7,
Index: 14,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `Stmt : Attr << >>`,
Id: "Stmt",
NTType: 7,
Index: 15,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `Stmt : Subgraph << >>`,
Id: "Stmt",
NTType: 7,
Index: 16,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `OptSemi : empty << >>`,
Id: "OptSemi",
NTType: 8,
Index: 17,
NumSymbols: 0,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return nil, nil
},
},
ProdTabEntry{
String: `OptSemi : ";" << >>`,
Id: "OptSemi",
NTType: 8,
Index: 18,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `NodeStmt : Node OptAttrList << astx.NewNodeStmt(X[0], X[1]) >>`,
Id: "NodeStmt",
NTType: 9,
Index: 19,
NumSymbols: 2,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewNodeStmt(X[0], X[1])
},
},
ProdTabEntry{
String: `EdgeStmt : Vertex Edge OptAttrList << astx.NewEdgeStmt(X[0], X[1], X[2]) >>`,
Id: "EdgeStmt",
NTType: 10,
Index: 20,
NumSymbols: 3,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewEdgeStmt(X[0], X[1], X[2])
},
},
ProdTabEntry{
String: `Edge : DirectedEdge Vertex OptEdge << astx.NewEdge(X[0], X[1], X[2]) >>`,
Id: "Edge",
NTType: 11,
Index: 21,
NumSymbols: 3,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewEdge(X[0], X[1], X[2])
},
},
ProdTabEntry{
String: `DirectedEdge : "--" << false, nil >>`,
Id: "DirectedEdge",
NTType: 12,
Index: 22,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return false, nil
},
},
ProdTabEntry{
String: `DirectedEdge : "->" << true, nil >>`,
Id: "DirectedEdge",
NTType: 12,
Index: 23,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return true, nil
},
},
ProdTabEntry{
String: `OptEdge : empty << >>`,
Id: "OptEdge",
NTType: 13,
Index: 24,
NumSymbols: 0,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return nil, nil
},
},
ProdTabEntry{
String: `OptEdge : Edge << >>`,
Id: "OptEdge",
NTType: 13,
Index: 25,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `AttrStmt : Component AttrList << astx.NewAttrStmt(X[0], X[1]) >>`,
Id: "AttrStmt",
NTType: 14,
Index: 26,
NumSymbols: 2,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewAttrStmt(X[0], X[1])
},
},
ProdTabEntry{
String: `Component : graphx << ast.GraphKind, nil >>`,
Id: "Component",
NTType: 15,
Index: 27,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return ast.GraphKind, nil
},
},
ProdTabEntry{
String: `Component : node << ast.NodeKind, nil >>`,
Id: "Component",
NTType: 15,
Index: 28,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return ast.NodeKind, nil
},
},
ProdTabEntry{
String: `Component : edge << ast.EdgeKind, nil >>`,
Id: "Component",
NTType: 15,
Index: 29,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return ast.EdgeKind, nil
},
},
ProdTabEntry{
String: `AttrList : "[" OptAList "]" << X[1], nil >>`,
Id: "AttrList",
NTType: 16,
Index: 30,
NumSymbols: 3,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[1], nil
},
},
ProdTabEntry{
String: `AttrList : AttrList "[" OptAList "]" << astx.AppendAttrList(X[0], X[2]) >>`,
Id: "AttrList",
NTType: 16,
Index: 31,
NumSymbols: 4,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.AppendAttrList(X[0], X[2])
},
},
ProdTabEntry{
String: `OptAttrList : empty << >>`,
Id: "OptAttrList",
NTType: 17,
Index: 32,
NumSymbols: 0,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return nil, nil
},
},
ProdTabEntry{
String: `OptAttrList : AttrList << >>`,
Id: "OptAttrList",
NTType: 17,
Index: 33,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `AList : Attr OptSep << astx.NewAttrList(X[0]) >>`,
Id: "AList",
NTType: 18,
Index: 34,
NumSymbols: 2,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewAttrList(X[0])
},
},
ProdTabEntry{
String: `AList : AList Attr OptSep << astx.AppendAttr(X[0], X[1]) >>`,
Id: "AList",
NTType: 18,
Index: 35,
NumSymbols: 3,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.AppendAttr(X[0], X[1])
},
},
ProdTabEntry{
String: `OptAList : empty << >>`,
Id: "OptAList",
NTType: 19,
Index: 36,
NumSymbols: 0,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return nil, nil
},
},
ProdTabEntry{
String: `OptAList : AList << >>`,
Id: "OptAList",
NTType: 19,
Index: 37,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `OptSep : empty << >>`,
Id: "OptSep",
NTType: 20,
Index: 38,
NumSymbols: 0,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return nil, nil
},
},
ProdTabEntry{
String: `OptSep : ";" << >>`,
Id: "OptSep",
NTType: 20,
Index: 39,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `OptSep : "," << >>`,
Id: "OptSep",
NTType: 20,
Index: 40,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `Attr : ID "=" ID << astx.NewAttr(X[0], X[2]) >>`,
Id: "Attr",
NTType: 21,
Index: 41,
NumSymbols: 3,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewAttr(X[0], X[2])
},
},
ProdTabEntry{
String: `Subgraph : OptSubgraphID "{" OptStmtList "}" << astx.NewSubgraph(X[0], X[2]) >>`,
Id: "Subgraph",
NTType: 22,
Index: 42,
NumSymbols: 4,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewSubgraph(X[0], X[2])
},
},
ProdTabEntry{
String: `OptSubgraphID : empty << >>`,
Id: "OptSubgraphID",
NTType: 23,
Index: 43,
NumSymbols: 0,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return nil, nil
},
},
ProdTabEntry{
String: `OptSubgraphID : subgraph OptID << X[1], nil >>`,
Id: "OptSubgraphID",
NTType: 23,
Index: 44,
NumSymbols: 2,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[1], nil
},
},
ProdTabEntry{
String: `Vertex : Node << >>`,
Id: "Vertex",
NTType: 24,
Index: 45,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `Vertex : Subgraph << >>`,
Id: "Vertex",
NTType: 24,
Index: 46,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `Node : ID OptPort << astx.NewNode(X[0], X[1]) >>`,
Id: "Node",
NTType: 25,
Index: 47,
NumSymbols: 2,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewNode(X[0], X[1])
},
},
ProdTabEntry{
String: `Port : ":" ID << astx.NewPort(X[1], nil) >>`,
Id: "Port",
NTType: 26,
Index: 48,
NumSymbols: 2,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewPort(X[1], nil)
},
},
ProdTabEntry{
String: `Port : ":" ID ":" ID << astx.NewPort(X[1], X[3]) >>`,
Id: "Port",
NTType: 26,
Index: 49,
NumSymbols: 4,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewPort(X[1], X[3])
},
},
ProdTabEntry{
String: `OptPort : empty << >>`,
Id: "OptPort",
NTType: 27,
Index: 50,
NumSymbols: 0,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return nil, nil
},
},
ProdTabEntry{
String: `OptPort : Port << >>`,
Id: "OptPort",
NTType: 27,
Index: 51,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
ProdTabEntry{
String: `ID : id << astx.NewID(X[0]) >>`,
Id: "ID",
NTType: 28,
Index: 52,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return astx.NewID(X[0])
},
},
ProdTabEntry{
String: `OptID : empty << "", nil >>`,
Id: "OptID",
NTType: 29,
Index: 53,
NumSymbols: 0,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return "", nil
},
},
ProdTabEntry{
String: `OptID : ID << >>`,
Id: "OptID",
NTType: 29,
Index: 54,
NumSymbols: 1,
ReduceFunc: func(X []Attrib) (Attrib, error) {
return X[0], nil
},
},
}

View File

@ -1,6 +0,0 @@
// Copyright ©2018 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 token provides generated internal tokenizing functions for DOT parsing.
package token // import "gonum.org/v1/gonum/graph/formats/dot/internal/token"

View File

@ -1,116 +0,0 @@
// Code generated by gocc; DO NOT EDIT.
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
package token
import (
"fmt"
)
type Token struct {
Type
Lit []byte
Pos
}
type Type int
const (
INVALID Type = iota
EOF
)
type Pos struct {
Offset int
Line int
Column int
}
func (p Pos) String() string {
return fmt.Sprintf("Pos(offset=%d, line=%d, column=%d)", p.Offset, p.Line, p.Column)
}
type TokenMap struct {
typeMap []string
idMap map[string]Type
}
func (m TokenMap) Id(tok Type) string {
if int(tok) < len(m.typeMap) {
return m.typeMap[tok]
}
return "unknown"
}
func (m TokenMap) Type(tok string) Type {
if typ, exist := m.idMap[tok]; exist {
return typ
}
return INVALID
}
func (m TokenMap) TokenString(tok *Token) string {
//TODO: refactor to print pos & token string properly
return fmt.Sprintf("%s(%d,%s)", m.Id(tok.Type), tok.Type, tok.Lit)
}
func (m TokenMap) StringType(typ Type) string {
return fmt.Sprintf("%s(%d)", m.Id(typ), typ)
}
var TokMap = TokenMap{
typeMap: []string{
"INVALID",
"$",
"{",
"}",
"empty",
"strict",
"graphx",
"digraph",
";",
"--",
"->",
"node",
"edge",
"[",
"]",
",",
"=",
"subgraph",
":",
"id",
},
idMap: map[string]Type{
"INVALID": 0,
"$": 1,
"{": 2,
"}": 3,
"empty": 4,
"strict": 5,
"graphx": 6,
"digraph": 7,
";": 8,
"--": 9,
"->": 10,
"node": 11,
"edge": 12,
"[": 13,
"]": 14,
",": 15,
"=": 16,
"subgraph": 17,
":": 18,
"id": 19,
},
}

View File

@ -1,4 +0,0 @@
#!/usr/bin/env bash
cd internal
make clean && make

View File

@ -1,160 +0,0 @@
// This file is dual licensed under CC0 and The gonum license.
//
// Copyright ©2017 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.
//
// Copyright ©2017 Robin Eklind.
// This file is made available under a Creative Commons CC0 1.0
// Universal Public Domain Dedication.
package dot
import (
"fmt"
"gonum.org/v1/gonum/graph/formats/dot/ast"
)
// check validates the semantics of the given DOT file.
func check(file *ast.File) error {
for _, graph := range file.Graphs {
// TODO: Check graph.ID for duplicates?
if err := checkGraph(graph); err != nil {
return err
}
}
return nil
}
// check validates the semantics of the given graph.
func checkGraph(graph *ast.Graph) error {
for _, stmt := range graph.Stmts {
if err := checkStmt(graph, stmt); err != nil {
return err
}
}
return nil
}
// check validates the semantics of the given statement.
func checkStmt(graph *ast.Graph, stmt ast.Stmt) error {
switch stmt := stmt.(type) {
case *ast.NodeStmt:
return checkNodeStmt(graph, stmt)
case *ast.EdgeStmt:
return checkEdgeStmt(graph, stmt)
case *ast.AttrStmt:
return checkAttrStmt(graph, stmt)
case *ast.Attr:
// TODO: Verify that the attribute is indeed of graph component kind.
return checkAttr(graph, ast.GraphKind, stmt)
case *ast.Subgraph:
return checkSubgraph(graph, stmt)
default:
panic(fmt.Sprintf("support for statement of type %T not yet implemented", stmt))
}
}
// checkNodeStmt validates the semantics of the given node statement.
func checkNodeStmt(graph *ast.Graph, stmt *ast.NodeStmt) error {
if err := checkNode(graph, stmt.Node); err != nil {
return err
}
for _, attr := range stmt.Attrs {
// TODO: Verify that the attribute is indeed of node component kind.
if err := checkAttr(graph, ast.NodeKind, attr); err != nil {
return err
}
}
return nil
}
// checkEdgeStmt validates the semantics of the given edge statement.
func checkEdgeStmt(graph *ast.Graph, stmt *ast.EdgeStmt) error {
// TODO: if graph.Strict, check for multi-edges.
if err := checkVertex(graph, stmt.From); err != nil {
return err
}
for _, attr := range stmt.Attrs {
// TODO: Verify that the attribute is indeed of edge component kind.
if err := checkAttr(graph, ast.EdgeKind, attr); err != nil {
return err
}
}
return checkEdge(graph, stmt.From, stmt.To)
}
// checkEdge validates the semantics of the given edge.
func checkEdge(graph *ast.Graph, from ast.Vertex, to *ast.Edge) error {
if !graph.Directed && to.Directed {
return fmt.Errorf("undirected graph %q contains directed edge from %q to %q", graph.ID, from, to.Vertex)
}
if err := checkVertex(graph, to.Vertex); err != nil {
return err
}
if to.To != nil {
return checkEdge(graph, to.Vertex, to.To)
}
return nil
}
// checkAttrStmt validates the semantics of the given attribute statement.
func checkAttrStmt(graph *ast.Graph, stmt *ast.AttrStmt) error {
for _, attr := range stmt.Attrs {
if err := checkAttr(graph, stmt.Kind, attr); err != nil {
return err
}
}
return nil
}
// checkAttr validates the semantics of the given attribute for the given
// component kind.
func checkAttr(graph *ast.Graph, kind ast.Kind, attr *ast.Attr) error {
switch kind {
case ast.GraphKind:
// TODO: Validate key-value pairs for graphs.
return nil
case ast.NodeKind:
// TODO: Validate key-value pairs for nodes.
return nil
case ast.EdgeKind:
// TODO: Validate key-value pairs for edges.
return nil
default:
panic(fmt.Sprintf("support for component kind %v not yet supported", kind))
}
}
// checkSubgraph validates the semantics of the given subgraph.
func checkSubgraph(graph *ast.Graph, subgraph *ast.Subgraph) error {
// TODO: Check subgraph.ID for duplicates?
for _, stmt := range subgraph.Stmts {
// TODO: Refine handling of subgraph statements?
// checkSubgraphStmt(graph, subgraph, stmt)
if err := checkStmt(graph, stmt); err != nil {
return err
}
}
return nil
}
// checkVertex validates the semantics of the given vertex.
func checkVertex(graph *ast.Graph, vertex ast.Vertex) error {
switch vertex := vertex.(type) {
case *ast.Node:
return checkNode(graph, vertex)
case *ast.Subgraph:
return checkSubgraph(graph, vertex)
default:
panic(fmt.Sprintf("support for vertex of type %T not yet supported", vertex))
}
}
// checNode validates the semantics of the given node.
func checkNode(graph *ast.Graph, node *ast.Node) error {
// TODO: Check node.ID for duplicates?
// TODO: Validate node.Port.
return nil
}

View File

@ -1,282 +0,0 @@
// 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
// Node is a graph node. It returns a graph-unique integer ID.
type Node interface {
ID() int64
}
// 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 returns the from node of the edge.
From() Node
// To returns the to node of the edge.
To() Node
// ReversedEdge returns an edge that has
// the end points of the receiver swapped.
ReversedEdge() Edge
}
// WeightedEdge is a weighted graph edge. In directed graphs, the direction
// of the edge is given from -> to, otherwise the edge is semantically
// unordered.
type WeightedEdge interface {
Edge
Weight() float64
}
// Graph is a generalized graph.
type Graph interface {
// Node returns the node with the given ID if it exists
// in the graph, and nil otherwise.
Node(id int64) Node
// Nodes returns all the nodes in the graph.
//
// Nodes must not return nil.
Nodes() Nodes
// From returns all nodes that can be reached directly
// from the node with the given ID.
//
// From must not return nil.
From(id int64) Nodes
// HasEdgeBetween returns whether an edge exists between
// nodes with IDs xid and yid without considering direction.
HasEdgeBetween(xid, yid int64) bool
// Edge returns the edge from u to v, with IDs uid and vid,
// if such an edge exists and nil otherwise. The node v
// must be directly reachable from u as defined by the
// From method.
Edge(uid, vid int64) Edge
}
// Weighted is a weighted graph.
type Weighted interface {
Graph
// WeightedEdge returns the weighted edge from u to v
// with IDs uid and vid if such an edge exists and
// nil otherwise. The node v must be directly
// reachable from u as defined by the From method.
WeightedEdge(uid, vid int64) WeightedEdge
// Weight returns the weight for the edge between
// x and y with IDs xid and yid if Edge(xid, yid)
// returns a non-nil Edge.
// If x and y are the same node or there is no
// joining edge between the two nodes the weight
// value returned is implementation dependent.
// Weight returns true if an edge exists between
// x and y or if x and y have the same ID, false
// otherwise.
Weight(xid, yid int64) (w float64, ok bool)
}
// Undirected is an undirected graph.
type Undirected interface {
Graph
// EdgeBetween returns the edge between nodes x and y
// with IDs xid and yid.
EdgeBetween(xid, yid int64) Edge
}
// WeightedUndirected is a weighted undirected graph.
type WeightedUndirected interface {
Weighted
// WeightedEdgeBetween returns the edge between nodes
// x and y with IDs xid and yid.
WeightedEdgeBetween(xid, yid int64) WeightedEdge
}
// Directed is a directed graph.
type Directed interface {
Graph
// HasEdgeFromTo returns whether an edge exists
// in the graph from u to v with IDs uid and vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly
// to the node with the given ID.
//
// To must not return nil.
To(id int64) Nodes
}
// WeightedDirected is a weighted directed graph.
type WeightedDirected interface {
Weighted
// HasEdgeFromTo returns whether an edge exists
// in the graph from u to v with the IDs uid and
// vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly
// to the node with the given ID.
//
// To must not return nil.
To(id int64) Nodes
}
// NodeAdder is an interface for adding arbitrary nodes to a graph.
type NodeAdder interface {
// NewNode returns a new Node with a unique
// arbitrary ID.
NewNode() Node
// AddNode adds a node to the graph. AddNode panics if
// the added node ID matches an existing node ID.
AddNode(Node)
}
// NodeRemover is an interface for removing nodes from a graph.
type NodeRemover interface {
// RemoveNode removes the node with the given ID
// 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(id int64)
}
// EdgeAdder is an interface for adding edges to a graph.
type EdgeAdder interface {
// NewEdge returns a new Edge from the source to the destination node.
NewEdge(from, to Node) Edge
// SetEdge adds an edge from one node to another.
// If the graph supports node addition the nodes
// will be added if they do not exist, otherwise
// SetEdge will panic.
// The behavior of an EdgeAdder when the IDs
// returned by e.From() and e.To() are equal is
// implementation-dependent.
// Whether e, e.From() and e.To() are stored
// within the graph is implementation dependent.
SetEdge(e Edge)
}
// WeightedEdgeAdder is an interface for adding edges to a graph.
type WeightedEdgeAdder interface {
// NewWeightedEdge returns a new WeightedEdge from
// the source to the destination node.
NewWeightedEdge(from, to Node, weight float64) WeightedEdge
// SetWeightedEdge adds an edge from one node to
// another. If the graph supports node addition
// the nodes will be added if they do not exist,
// otherwise SetWeightedEdge will panic.
// The behavior of a WeightedEdgeAdder when the IDs
// returned by e.From() and e.To() are equal is
// implementation-dependent.
// Whether e, e.From() and e.To() are stored
// within the graph is implementation dependent.
SetWeightedEdge(e WeightedEdge)
}
// EdgeRemover is an interface for removing nodes from a graph.
type EdgeRemover interface {
// RemoveEdge removes the edge with the given end
// IDs, leaving the terminal nodes. If the edge
// does not exist it is a no-op.
RemoveEdge(fid, tid int64)
}
// Builder is a graph that can have nodes and edges added.
type Builder interface {
NodeAdder
EdgeAdder
}
// WeightedBuilder is a graph that can have nodes and weighted edges added.
type WeightedBuilder interface {
NodeAdder
WeightedEdgeAdder
}
// UndirectedBuilder is an undirected graph builder.
type UndirectedBuilder interface {
Undirected
Builder
}
// UndirectedWeightedBuilder is an undirected weighted graph builder.
type UndirectedWeightedBuilder interface {
Undirected
WeightedBuilder
}
// DirectedBuilder is a directed graph builder.
type DirectedBuilder interface {
Directed
Builder
}
// DirectedWeightedBuilder is a directed weighted graph builder.
type DirectedWeightedBuilder interface {
Directed
WeightedBuilder
}
// Copy copies nodes and edges as undirected edges from the source to the destination
// without first clearing the destination. Copy will panic if a node ID in the source
// graph matches a node ID in the destination.
//
// If the source is undirected and the destination is directed both directions will
// be present in the destination after the copy is complete.
func Copy(dst Builder, src Graph) {
nodes := src.Nodes()
for nodes.Next() {
dst.AddNode(nodes.Node())
}
nodes.Reset()
for nodes.Next() {
u := nodes.Node()
uid := u.ID()
to := src.From(uid)
for to.Next() {
v := to.Node()
dst.SetEdge(src.Edge(uid, v.ID()))
}
}
}
// CopyWeighted copies nodes and edges as undirected edges from the source to the destination
// without first clearing the destination. Copy will panic if a node ID in the source
// graph matches a node ID in the destination.
//
// If the source is undirected and the destination is directed both directions will
// be present in the destination after the copy is complete.
//
// If the source is a directed graph, the destination is undirected, 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. If there is a defined function
// to resolve such conflicts, an UndirectWeighted may be used to do this.
func CopyWeighted(dst WeightedBuilder, src Weighted) {
nodes := src.Nodes()
for nodes.Next() {
dst.AddNode(nodes.Node())
}
nodes.Reset()
for nodes.Next() {
u := nodes.Node()
uid := u.ID()
to := src.From(uid)
for to.Next() {
v := to.Node()
dst.SetWeightedEdge(src.WeightedEdge(uid, v.ID()))
}
}
}

View File

@ -1,6 +0,0 @@
// Copyright ©2017 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 ordered provides common sort ordering types.
package ordered // import "gonum.org/v1/gonum/graph/internal/ordered"

View File

@ -1,93 +0,0 @@
// 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 ordered
import "gonum.org/v1/gonum/graph"
// ByID implements the sort.Interface sorting a slice of graph.Node
// by ID.
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] }
// BySliceValues implements the sort.Interface sorting a slice of
// []int64 lexically by the values of the []int64.
type BySliceValues [][]int64
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] }
// BySliceIDs implements the sort.Interface sorting a slice of
// []graph.Node lexically by the IDs of the []graph.Node.
type BySliceIDs [][]graph.Node
func (c BySliceIDs) Len() int { return len(c) }
func (c BySliceIDs) 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.ID() < b[k].ID() {
return true
}
if v.ID() > b[k].ID() {
return false
}
}
return len(a) < len(b)
}
func (c BySliceIDs) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
// Int64s implements the sort.Interface sorting a slice of
// int64.
type Int64s []int64
func (s Int64s) Len() int { return len(s) }
func (s Int64s) Less(i, j int) bool { return s[i] < s[j] }
func (s Int64s) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// Reverse reverses the order of nodes.
func Reverse(nodes []graph.Node) {
for i, j := 0, len(nodes)-1; i < j; i, j = i+1, j-1 {
nodes[i], nodes[j] = nodes[j], nodes[i]
}
}
// LinesByIDs implements the sort.Interface sorting a slice of graph.LinesByIDs
// lexically by the From IDs, then by the To IDs, finally by the Line IDs.
type LinesByIDs []graph.Line
func (n LinesByIDs) Len() int { return len(n) }
func (n LinesByIDs) Less(i, j int) bool {
a, b := n[i], n[j]
if a.From().ID() != b.From().ID() {
return a.From().ID() < b.From().ID()
}
if a.To().ID() != b.To().ID() {
return a.To().ID() < b.To().ID()
}
return n[i].ID() < n[j].ID()
}
func (n LinesByIDs) Swap(i, j int) { n[i], n[j] = n[j], n[i] }

View File

@ -1,6 +0,0 @@
// Copyright ©2017 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 set provides integer and graph.Node sets.
package set // import "gonum.org/v1/gonum/graph/internal/set"

View File

@ -1,36 +0,0 @@
// 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.
// +build !appengine,!safe
package set
import "unsafe"
// 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 are passed as a pointer to a runtime Hmap struct. A map is
// not seen by the runtime as a pointer though, so we use unsafe to get
// the maps' pointer values to compare.
func same(a, b Nodes) bool {
return *(*uintptr)(unsafe.Pointer(&a)) == *(*uintptr)(unsafe.Pointer(&b))
}
// intsSame 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 are passed as a pointer to a runtime Hmap struct. A map is
// not seen by the runtime as a pointer though, so we use unsafe to get
// the maps' pointer values to compare.
func intsSame(a, b Ints) bool {
return *(*uintptr)(unsafe.Pointer(&a)) == *(*uintptr)(unsafe.Pointer(&b))
}
// int64sSame 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 are passed as a pointer to a runtime Hmap struct. A map is
// not seen by the runtime as a pointer though, so we use unsafe to get
// the maps' pointer values to compare.
func int64sSame(a, b Int64s) bool {
return *(*uintptr)(unsafe.Pointer(&a)) == *(*uintptr)(unsafe.Pointer(&b))
}

View File

@ -1,36 +0,0 @@
// 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.
// +build appengine safe
package set
import "reflect"
// 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 are passed as a pointer to a runtime Hmap struct. A map is
// not seen by the runtime as a pointer though, so we use reflect to get
// the maps' pointer values to compare.
func same(a, b Nodes) bool {
return reflect.ValueOf(a).Pointer() == reflect.ValueOf(b).Pointer()
}
// intsSame 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 are passed as a pointer to a runtime Hmap struct. A map is
// not seen by the runtime as a pointer though, so we use reflect to get
// the maps' pointer values to compare.
func intsSame(a, b Ints) bool {
return reflect.ValueOf(a).Pointer() == reflect.ValueOf(b).Pointer()
}
// int64sSame 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 are passed as a pointer to a runtime Hmap struct. A map is
// not seen by the runtime as a pointer though, so we use reflect to get
// the maps' pointer values to compare.
func int64sSame(a, b Int64s) bool {
return reflect.ValueOf(a).Pointer() == reflect.ValueOf(b).Pointer()
}

View File

@ -1,228 +0,0 @@
// 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 set
import "gonum.org/v1/gonum/graph"
// Ints is a set of int identifiers.
type Ints map[int]struct{}
// The simple accessor methods for Ints are provided to allow ease of
// implementation change should the need arise.
// Add inserts an element into the set.
func (s Ints) Add(e int) {
s[e] = struct{}{}
}
// Has reports the existence of the element in the set.
func (s Ints) Has(e int) bool {
_, ok := s[e]
return ok
}
// Remove deletes the specified element from the set.
func (s Ints) Remove(e int) {
delete(s, e)
}
// Count reports the number of elements stored in the set.
func (s Ints) Count() int {
return len(s)
}
// IntsEqual reports set equality between the parameters. Sets are equal if
// and only if they have the same elements.
func IntsEqual(a, b Ints) bool {
if intsSame(a, b) {
return true
}
if len(a) != len(b) {
return false
}
for e := range a {
if _, ok := b[e]; !ok {
return false
}
}
return true
}
// Int64s is a set of int64 identifiers.
type Int64s map[int64]struct{}
// The simple accessor methods for Ints are provided to allow ease of
// implementation change should the need arise.
// Add inserts an element into the set.
func (s Int64s) Add(e int64) {
s[e] = struct{}{}
}
// Has reports the existence of the element in the set.
func (s Int64s) Has(e int64) bool {
_, ok := s[e]
return ok
}
// Remove deletes the specified element from the set.
func (s Int64s) Remove(e int64) {
delete(s, e)
}
// Count reports the number of elements stored in the set.
func (s Int64s) Count() int {
return len(s)
}
// Int64sEqual reports set equality between the parameters. Sets are equal if
// and only if they have the same elements.
func Int64sEqual(a, b Int64s) bool {
if int64sSame(a, b) {
return true
}
if len(a) != len(b) {
return false
}
for e := range a {
if _, ok := b[e]; !ok {
return false
}
}
return true
}
// Nodes is a set of nodes keyed in their integer identifiers.
type Nodes map[int64]graph.Node
// NewNodes returns a new Nodes.
func NewNodes() Nodes {
return make(Nodes)
}
// NewNodes returns a new Nodes with the given size hint, n.
func NewNodesSize(n int) Nodes {
return make(Nodes, n)
}
// The simple accessor methods for Nodes are provided to allow ease of
// implementation change should the need arise.
// Add inserts an element into the set.
func (s Nodes) Add(n graph.Node) {
s[n.ID()] = n
}
// Remove deletes the specified element from the set.
func (s Nodes) Remove(e graph.Node) {
delete(s, e.ID())
}
// Count returns the number of element in the set.
func (s Nodes) Count() int {
return len(s)
}
// Has reports the existence of the elements in the set.
func (s Nodes) Has(n graph.Node) bool {
_, ok := s[n.ID()]
return ok
}
// CloneNodes returns a clone of src.
func CloneNodes(src Nodes) Nodes {
dst := make(Nodes, 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(a, b Nodes) bool {
if same(a, b) {
return true
}
if len(a) != len(b) {
return false
}
for e := range a {
if _, ok := b[e]; !ok {
return false
}
}
return true
}
// UnionOfNodes returns the union of a and b.
//
// The union of two sets, a and b, 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 UnionOfNodes(a, b Nodes) Nodes {
if same(a, b) {
return CloneNodes(a)
}
dst := make(Nodes)
for e, n := range a {
dst[e] = n
}
for e, n := range b {
dst[e] = n
}
return dst
}
// IntersectionOfNodes returns the intersection of a and b.
//
// The intersection of two sets, a and b, 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 IntersectionOfNodes(a, b Nodes) Nodes {
if same(a, b) {
return CloneNodes(a)
}
dst := make(Nodes)
if len(a) > len(b) {
a, b = b, a
}
for e, n := range a {
if _, ok := b[e]; ok {
dst[e] = n
}
}
return dst
}

View File

@ -1,54 +0,0 @@
// 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 uid implements unique ID provision for graphs.
package uid
import "gonum.org/v1/gonum/graph/internal/set"
// Max is the maximum value of int64.
const Max = int64(^uint64(0) >> 1)
// Set implements available ID storage.
type Set struct {
maxID int64
used, free set.Int64s
}
// NewSet returns a new Set. The returned value should not be passed except by pointer.
func NewSet() Set {
return Set{maxID: -1, used: make(set.Int64s), free: make(set.Int64s)}
}
// NewID returns a new unique ID. The ID returned is not considered used
// until passed in a call to use.
func (s *Set) NewID() int64 {
for id := range s.free {
return id
}
if s.maxID != Max {
return s.maxID + 1
}
for id := int64(0); id <= s.maxID+1; id++ {
if !s.used.Has(id) {
return id
}
}
panic("unreachable")
}
// Use adds the id to the used IDs in the Set.
func (s *Set) Use(id int64) {
s.used.Add(id)
s.free.Remove(id)
if id > s.maxID {
s.maxID = id
}
}
// Release frees the id for reuse.
func (s *Set) Release(id int64) {
s.free.Add(id)
s.used.Remove(id)
}

View File

@ -1,9 +0,0 @@
// Copyright ©2018 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 iterator provides node, edge and line iterators.
//
// The iterators provided satisfy the graph.Nodes, graph.Edges and
// graph.Lines interfaces.
package iterator

View File

@ -1,131 +0,0 @@
// Copyright ©2018 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 iterator
import "gonum.org/v1/gonum/graph"
// OrderedEdges implements the graph.Edges and graph.EdgeSlicer interfaces.
// The iteration order of OrderedEdges is the order of edges passed to
// NewEdgeIterator.
type OrderedEdges struct {
idx int
edges []graph.Edge
}
// NewOrderedEdges returns an OrderedEdges initialized with the provided edges.
func NewOrderedEdges(edges []graph.Edge) *OrderedEdges {
return &OrderedEdges{idx: -1, edges: edges}
}
// Len returns the remaining number of edges to be iterated over.
func (e *OrderedEdges) Len() int {
if e.idx >= len(e.edges) {
return 0
}
if e.idx <= 0 {
return len(e.edges)
}
return len(e.edges[e.idx:])
}
// Next returns whether the next call of Edge will return a valid edge.
func (e *OrderedEdges) Next() bool {
if uint(e.idx)+1 < uint(len(e.edges)) {
e.idx++
return true
}
e.idx = len(e.edges)
return false
}
// Edge returns the current edge of the iterator. Next must have been
// called prior to a call to Edge.
func (e *OrderedEdges) Edge() graph.Edge {
if e.idx >= len(e.edges) || e.idx < 0 {
return nil
}
return e.edges[e.idx]
}
// EdgeSlice returns all the remaining edges in the iterator and advances
// the iterator.
func (e *OrderedEdges) EdgeSlice() []graph.Edge {
if e.idx >= len(e.edges) {
return nil
}
idx := e.idx
if idx == -1 {
idx = 0
}
e.idx = len(e.edges)
return e.edges[idx:]
}
// Reset returns the iterator to its initial state.
func (e *OrderedEdges) Reset() {
e.idx = -1
}
// OrderedWeightedEdges implements the graph.Edges and graph.EdgeSlicer interfaces.
// The iteration order of OrderedWeightedEdges is the order of edges passed to
// NewEdgeIterator.
type OrderedWeightedEdges struct {
idx int
edges []graph.WeightedEdge
}
// NewOrderedWeightedEdges returns an OrderedWeightedEdges initialized with the provided edges.
func NewOrderedWeightedEdges(edges []graph.WeightedEdge) *OrderedWeightedEdges {
return &OrderedWeightedEdges{idx: -1, edges: edges}
}
// Len returns the remaining number of edges to be iterated over.
func (e *OrderedWeightedEdges) Len() int {
if e.idx >= len(e.edges) {
return 0
}
if e.idx <= 0 {
return len(e.edges)
}
return len(e.edges[e.idx:])
}
// Next returns whether the next call of WeightedEdge will return a valid edge.
func (e *OrderedWeightedEdges) Next() bool {
if uint(e.idx)+1 < uint(len(e.edges)) {
e.idx++
return true
}
e.idx = len(e.edges)
return false
}
// WeightedEdge returns the current edge of the iterator. Next must have been
// called prior to a call to WeightedEdge.
func (e *OrderedWeightedEdges) WeightedEdge() graph.WeightedEdge {
if e.idx >= len(e.edges) || e.idx < 0 {
return nil
}
return e.edges[e.idx]
}
// WeightedEdgeSlice returns all the remaining edges in the iterator and advances
// the iterator.
func (e *OrderedWeightedEdges) WeightedEdgeSlice() []graph.WeightedEdge {
if e.idx >= len(e.edges) {
return nil
}
idx := e.idx
if idx == -1 {
idx = 0
}
e.idx = len(e.edges)
return e.edges[idx:]
}
// Reset returns the iterator to its initial state.
func (e *OrderedWeightedEdges) Reset() {
e.idx = -1
}

View File

@ -1,131 +0,0 @@
// Copyright ©2018 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 iterator
import "gonum.org/v1/gonum/graph"
// OrderedLines implements the graph.Lines and graph.LineSlicer interfaces.
// The iteration order of OrderedLines is the order of lines passed to
// NewLineIterator.
type OrderedLines struct {
idx int
lines []graph.Line
}
// NewOrderedLines returns an OrderedLines initialized with the provided lines.
func NewOrderedLines(lines []graph.Line) *OrderedLines {
return &OrderedLines{idx: -1, lines: lines}
}
// Len returns the remaining number of lines to be iterated over.
func (e *OrderedLines) Len() int {
if e.idx >= len(e.lines) {
return 0
}
if e.idx <= 0 {
return len(e.lines)
}
return len(e.lines[e.idx:])
}
// Next returns whether the next call of Line will return a valid line.
func (e *OrderedLines) Next() bool {
if uint(e.idx)+1 < uint(len(e.lines)) {
e.idx++
return true
}
e.idx = len(e.lines)
return false
}
// Line returns the current line of the iterator. Next must have been
// called prior to a call to Line.
func (e *OrderedLines) Line() graph.Line {
if e.idx >= len(e.lines) || e.idx < 0 {
return nil
}
return e.lines[e.idx]
}
// LineSlice returns all the remaining lines in the iterator and advances
// the iterator.
func (e *OrderedLines) LineSlice() []graph.Line {
if e.idx >= len(e.lines) {
return nil
}
idx := e.idx
if idx == -1 {
idx = 0
}
e.idx = len(e.lines)
return e.lines[idx:]
}
// Reset returns the iterator to its initial state.
func (e *OrderedLines) Reset() {
e.idx = -1
}
// OrderedWeightedLines implements the graph.Lines and graph.LineSlicer interfaces.
// The iteration order of OrderedWeightedLines is the order of lines passed to
// NewLineIterator.
type OrderedWeightedLines struct {
idx int
lines []graph.WeightedLine
}
// NewWeightedLineIterator returns an OrderedWeightedLines initialized with the provided lines.
func NewOrderedWeightedLines(lines []graph.WeightedLine) *OrderedWeightedLines {
return &OrderedWeightedLines{idx: -1, lines: lines}
}
// Len returns the remaining number of lines to be iterated over.
func (e *OrderedWeightedLines) Len() int {
if e.idx >= len(e.lines) {
return 0
}
if e.idx <= 0 {
return len(e.lines)
}
return len(e.lines[e.idx:])
}
// Next returns whether the next call of WeightedLine will return a valid line.
func (e *OrderedWeightedLines) Next() bool {
if uint(e.idx)+1 < uint(len(e.lines)) {
e.idx++
return true
}
e.idx = len(e.lines)
return false
}
// WeightedLine returns the current line of the iterator. Next must have been
// called prior to a call to WeightedLine.
func (e *OrderedWeightedLines) WeightedLine() graph.WeightedLine {
if e.idx >= len(e.lines) || e.idx < 0 {
return nil
}
return e.lines[e.idx]
}
// WeightedLineSlice returns all the remaining lines in the iterator and advances
// the iterator.
func (e *OrderedWeightedLines) WeightedLineSlice() []graph.WeightedLine {
if e.idx >= len(e.lines) {
return nil
}
idx := e.idx
if idx == -1 {
idx = 0
}
e.idx = len(e.lines)
return e.lines[idx:]
}
// Reset returns the iterator to its initial state.
func (e *OrderedWeightedLines) Reset() {
e.idx = -1
}

View File

@ -1,180 +0,0 @@
// Copyright ©2018 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 iterator
import (
"reflect"
"gonum.org/v1/gonum/graph"
)
// OrderedNodes implements the graph.Nodes and graph.NodeSlicer interfaces.
// The iteration order of OrderedNodes is the order of nodes passed to
// NewNodeIterator.
type OrderedNodes struct {
idx int
nodes []graph.Node
}
// NewOrderedNodes returns a OrderedNodes initialized with the provided nodes.
func NewOrderedNodes(nodes []graph.Node) *OrderedNodes {
return &OrderedNodes{idx: -1, nodes: nodes}
}
// Len returns the remaining number of nodes to be iterated over.
func (n *OrderedNodes) Len() int {
if n.idx >= len(n.nodes) {
return 0
}
if n.idx <= 0 {
return len(n.nodes)
}
return len(n.nodes[n.idx:])
}
// Next returns whether the next call of Node will return a valid node.
func (n *OrderedNodes) Next() bool {
if uint(n.idx)+1 < uint(len(n.nodes)) {
n.idx++
return true
}
n.idx = len(n.nodes)
return false
}
// Node returns the current node of the iterator. Next must have been
// called prior to a call to Node.
func (n *OrderedNodes) Node() graph.Node {
if n.idx >= len(n.nodes) || n.idx < 0 {
return nil
}
return n.nodes[n.idx]
}
// NodeSlice returns all the remaining nodes in the iterator and advances
// the iterator.
func (n *OrderedNodes) NodeSlice() []graph.Node {
if n.idx >= len(n.nodes) {
return nil
}
idx := n.idx
if idx == -1 {
idx = 0
}
n.idx = len(n.nodes)
return n.nodes[idx:]
}
// Reset returns the iterator to its initial state.
func (n *OrderedNodes) Reset() {
n.idx = -1
}
// ImplicitNodes implements the graph.Nodes interface for a set of nodes over
// a contiguous ID range.
type ImplicitNodes struct {
beg, end int
curr int
newNode func(id int) graph.Node
}
// NewImplicitNodes returns a new implicit node iterator spanning nodes in [beg,end).
// The provided new func maps the id to a graph.Node. NewImplicitNodes will panic
// if beg is greater than end.
func NewImplicitNodes(beg, end int, new func(id int) graph.Node) *ImplicitNodes {
if beg > end {
panic("iterator: invalid range")
}
return &ImplicitNodes{beg: beg, end: end, curr: beg - 1, newNode: new}
}
// Len returns the remaining number of nodes to be iterated over.
func (n *ImplicitNodes) Len() int {
return n.end - n.curr - 1
}
// Next returns whether the next call of Node will return a valid node.
func (n *ImplicitNodes) Next() bool {
if n.curr == n.end {
return false
}
n.curr++
return n.curr < n.end
}
// Node returns the current node of the iterator. Next must have been
// called prior to a call to Node.
func (n *ImplicitNodes) Node() graph.Node {
if n.Len() == -1 || n.curr < n.beg {
return nil
}
return n.newNode(n.curr)
}
// Reset returns the iterator to its initial state.
func (n *ImplicitNodes) Reset() {
n.curr = n.beg - 1
}
// NodeSlice returns all the remaining nodes in the iterator and advances
// the iterator.
func (n *ImplicitNodes) NodeSlice() []graph.Node {
nodes := make([]graph.Node, 0, n.Len())
for n.curr++; n.curr < n.end; n.curr++ {
nodes = append(nodes, n.newNode(n.curr))
}
return nodes
}
// Nodes implements the graph.Nodes interfaces.
// The iteration order of Nodes is randomized.
type Nodes struct {
nodes reflect.Value
iter *reflect.MapIter
pos int
curr graph.Node
}
// NewNodes returns a Nodes initialized with the provided nodes, a
// map of node IDs to graph.Nodes. No check is made that the keys
// match the graph.Node IDs, and the map keys are not used.
//
// Behavior of the Nodes is unspecified if nodes is mutated after
// the call the NewNodes.
func NewNodes(nodes map[int64]graph.Node) *Nodes {
rv := reflect.ValueOf(nodes)
return &Nodes{nodes: rv, iter: rv.MapRange()}
}
// Len returns the remaining number of nodes to be iterated over.
func (n *Nodes) Len() int {
return n.nodes.Len() - n.pos
}
// Next returns whether the next call of Node will return a valid node.
func (n *Nodes) Next() bool {
if n.pos >= n.nodes.Len() {
return false
}
ok := n.iter.Next()
if ok {
n.pos++
n.curr = n.iter.Value().Interface().(graph.Node)
}
return ok
}
// Node returns the current node of the iterator. Next must have been
// called prior to a call to Node.
func (n *Nodes) Node() graph.Node {
return n.curr
}
// Reset returns the iterator to its initial state.
func (n *Nodes) Reset() {
n.curr = nil
n.pos = 0
n.iter = n.nodes.MapRange()
}

View File

@ -1,198 +0,0 @@
// 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
// Line is an edge in a multigraph. A Line returns an ID that must
// distinguish Lines sharing Node end points.
type Line interface {
// From returns the from node of the edge.
From() Node
// To returns the to node of the edge.
To() Node
// ReversedLine returns a line that has the
// end points of the receiver swapped.
ReversedLine() Line
// ID returns the unique ID for the Line.
ID() int64
}
// WeightedLine is a weighted multigraph edge.
type WeightedLine interface {
Line
Weight() float64
}
// Multigraph is a generalized multigraph.
type Multigraph interface {
// Node returns the node with the given ID if it exists
// in the multigraph, and nil otherwise.
Node(id int64) Node
// Nodes returns all the nodes in the multigraph.
//
// Nodes must not return nil.
Nodes() Nodes
// From returns all nodes that can be reached directly
// from the node with the given ID.
//
// From must not return nil.
From(id int64) Nodes
// HasEdgeBetween returns whether an edge exists between
// nodes with IDs xid and yid without considering direction.
HasEdgeBetween(xid, yid int64) bool
// Lines returns the lines from u to v, with IDs uid and
// vid, if any such lines exist and nil otherwise. The
// node v must be directly reachable from u as defined by
// the From method.
//
// Lines must not return nil.
Lines(uid, vid int64) Lines
}
// WeightedMultigraph is a weighted multigraph.
type WeightedMultigraph interface {
Multigraph
// WeightedLines returns the weighted lines from u to v
// with IDs uid and vid if any such lines exist and nil
// otherwise. The node v must be directly reachable
// from u as defined by the From method.
//
// WeightedLines must not return nil.
WeightedLines(uid, vid int64) WeightedLines
}
// UndirectedMultigraph is an undirected multigraph.
type UndirectedMultigraph interface {
Multigraph
// LinesBetween returns the lines between nodes x and y
// with IDs xid and yid.
//
// LinesBetween must not return nil.
LinesBetween(xid, yid int64) Lines
}
// WeightedUndirectedMultigraph is a weighted undirected multigraph.
type WeightedUndirectedMultigraph interface {
WeightedMultigraph
// WeightedLinesBetween returns the lines between nodes
// x and y with IDs xid and yid.
//
// WeightedLinesBetween must not return nil.
WeightedLinesBetween(xid, yid int64) WeightedLines
}
// DirectedMultigraph is a directed multigraph.
type DirectedMultigraph interface {
Multigraph
// HasEdgeFromTo returns whether an edge exists
// in the multigraph from u to v with IDs uid
// and vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly
// to the node with the given ID.
//
// To must not return nil.
To(id int64) Nodes
}
// WeightedDirectedMultigraph is a weighted directed multigraph.
type WeightedDirectedMultigraph interface {
WeightedMultigraph
// HasEdgeFromTo returns whether an edge exists
// in the multigraph from u to v with IDs uid
// and vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly
// to the node with the given ID.
//
// To must not return nil.
To(id int64) Nodes
}
// LineAdder is an interface for adding lines to a multigraph.
type LineAdder interface {
// NewLine returns a new Line from the source to the destination node.
NewLine(from, to Node) Line
// SetLine adds a Line from one node to another.
// If the multigraph supports node addition the nodes
// will be added if they do not exist, otherwise
// SetLine will panic.
// Whether l, l.From() and l.To() are stored
// within the graph is implementation dependent.
SetLine(l Line)
}
// WeightedLineAdder is an interface for adding lines to a multigraph.
type WeightedLineAdder interface {
// NewWeightedLine returns a new WeightedLine from
// the source to the destination node.
NewWeightedLine(from, to Node, weight float64) WeightedLine
// SetWeightedLine adds a weighted line from one node
// to another. If the multigraph supports node addition
// the nodes will be added if they do not exist,
// otherwise SetWeightedLine will panic.
// Whether l, l.From() and l.To() are stored
// within the graph is implementation dependent.
SetWeightedLine(l WeightedLine)
}
// LineRemover is an interface for removing lines from a multigraph.
type LineRemover interface {
// RemoveLine removes the line with the given end
// and line IDs, leaving the terminal nodes. If
// the line does not exist it is a no-op.
RemoveLine(fid, tid, id int64)
}
// MultigraphBuilder is a multigraph that can have nodes and lines added.
type MultigraphBuilder interface {
NodeAdder
LineAdder
}
// WeightedMultigraphBuilder is a multigraph that can have nodes and weighted lines added.
type WeightedMultigraphBuilder interface {
NodeAdder
WeightedLineAdder
}
// UndirectedMultgraphBuilder is an undirected multigraph builder.
type UndirectedMultigraphBuilder interface {
UndirectedMultigraph
MultigraphBuilder
}
// UndirectedWeightedMultigraphBuilder is an undirected weighted multigraph builder.
type UndirectedWeightedMultigraphBuilder interface {
UndirectedMultigraph
WeightedMultigraphBuilder
}
// DirectedMultigraphBuilder is a directed multigraph builder.
type DirectedMultigraphBuilder interface {
DirectedMultigraph
MultigraphBuilder
}
// DirectedWeightedMultigraphBuilder is a directed weighted multigraph builder.
type DirectedWeightedMultigraphBuilder interface {
DirectedMultigraph
WeightedMultigraphBuilder
}

View File

@ -1,300 +0,0 @@
// Copyright ©2018 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
// Iterator is an item iterator.
type Iterator interface {
// Next advances the iterator and returns whether
// the next call to the item method will return a
// non-nil item.
//
// Next should be called prior to any call to the
// iterator's item retrieval method after the
// iterator has been obtained or reset.
//
// The order of iteration is implementation
// dependent.
Next() bool
// Len returns the number of items remaining in the
// iterator.
//
// If the number of items in the iterator is unknown,
// too large to materialize or too costly to calculate
// then Len may return a negative value.
// In this case the consuming function must be able
// to operate on the items of the iterator directly
// without materializing the items into a slice.
// The magnitude of a negative length has
// implementation-dependent semantics.
Len() int
// Reset returns the iterator to its start position.
Reset()
}
// Nodes is a Node iterator.
type Nodes interface {
Iterator
// Node returns the current Node from the iterator.
Node() Node
}
// NodeSlicer wraps the NodeSlice method.
type NodeSlicer interface {
// NodeSlice returns the set of nodes remaining
// to be iterated by a Nodes iterator.
// The holder of the iterator may arbitrarily
// change elements in the returned slice, but
// those changes may be reflected to other
// iterators.
NodeSlice() []Node
}
// NodesOf returns it.Len() nodes from it. If it is a NodeSlicer, the NodeSlice method
// is used to obtain the nodes. It is safe to pass a nil Nodes to NodesOf.
//
// If the Nodes has an indeterminate length, NodesOf will panic.
func NodesOf(it Nodes) []Node {
if it == nil {
return nil
}
len := it.Len()
switch {
case len == 0:
return nil
case len < 0:
panic("graph: called NodesOf on indeterminate iterator")
}
switch it := it.(type) {
case NodeSlicer:
return it.NodeSlice()
}
n := make([]Node, 0, len)
for it.Next() {
n = append(n, it.Node())
}
return n
}
// Edges is an Edge iterator.
type Edges interface {
Iterator
// Edge returns the current Edge from the iterator.
Edge() Edge
}
// EdgeSlicer wraps the EdgeSlice method.
type EdgeSlicer interface {
// EdgeSlice returns the set of edges remaining
// to be iterated by an Edges iterator.
// The holder of the iterator may arbitrarily
// change elements in the returned slice, but
// those changes may be reflected to other
// iterators.
EdgeSlice() []Edge
}
// EdgesOf returns it.Len() nodes from it. If it is an EdgeSlicer, the EdgeSlice method is used
// to obtain the edges. It is safe to pass a nil Edges to EdgesOf.
//
// If the Edges has an indeterminate length, EdgesOf will panic.
func EdgesOf(it Edges) []Edge {
if it == nil {
return nil
}
len := it.Len()
switch {
case len == 0:
return nil
case len < 0:
panic("graph: called EdgesOf on indeterminate iterator")
}
switch it := it.(type) {
case EdgeSlicer:
return it.EdgeSlice()
}
e := make([]Edge, 0, len)
for it.Next() {
e = append(e, it.Edge())
}
return e
}
// WeightedEdges is a WeightedEdge iterator.
type WeightedEdges interface {
Iterator
// Edge returns the current Edge from the iterator.
WeightedEdge() WeightedEdge
}
// WeightedEdgeSlicer wraps the WeightedEdgeSlice method.
type WeightedEdgeSlicer interface {
// EdgeSlice returns the set of edges remaining
// to be iterated by an Edges iterator.
// The holder of the iterator may arbitrarily
// change elements in the returned slice, but
// those changes may be reflected to other
// iterators.
WeightedEdgeSlice() []WeightedEdge
}
// WeightedEdgesOf returns it.Len() weighted edge from it. If it is a WeightedEdgeSlicer, the
// WeightedEdgeSlice method is used to obtain the edges. It is safe to pass a nil WeightedEdges
// to WeightedEdgesOf.
//
// If the WeightedEdges has an indeterminate length, WeightedEdgesOf will panic.
func WeightedEdgesOf(it WeightedEdges) []WeightedEdge {
if it == nil {
return nil
}
len := it.Len()
switch {
case len == 0:
return nil
case len < 0:
panic("graph: called WeightedEdgesOf on indeterminate iterator")
}
switch it := it.(type) {
case WeightedEdgeSlicer:
return it.WeightedEdgeSlice()
}
e := make([]WeightedEdge, 0, len)
for it.Next() {
e = append(e, it.WeightedEdge())
}
return e
}
// Lines is a Line iterator.
type Lines interface {
Iterator
// Line returns the current Line from the iterator.
Line() Line
}
// LineSlicer wraps the LineSlice method.
type LineSlicer interface {
// LineSlice returns the set of lines remaining
// to be iterated by an Lines iterator.
// The holder of the iterator may arbitrarily
// change elements in the returned slice, but
// those changes may be reflected to other
// iterators.
LineSlice() []Line
}
// LinesOf returns it.Len() nodes from it. If it is a LineSlicer, the LineSlice method is used
// to obtain the lines. It is safe to pass a nil Lines to LinesOf.
//
// If the Lines has an indeterminate length, LinesOf will panic.
func LinesOf(it Lines) []Line {
if it == nil {
return nil
}
len := it.Len()
switch {
case len == 0:
return nil
case len < 0:
panic("graph: called LinesOf on indeterminate iterator")
}
switch it := it.(type) {
case LineSlicer:
return it.LineSlice()
}
l := make([]Line, 0, len)
for it.Next() {
l = append(l, it.Line())
}
return l
}
// WeightedLines is a WeightedLine iterator.
type WeightedLines interface {
Iterator
// Line returns the current Line from the iterator.
WeightedLine() WeightedLine
}
// WeightedLineSlicer wraps the WeightedLineSlice method.
type WeightedLineSlicer interface {
// LineSlice returns the set of lines remaining
// to be iterated by an Lines iterator.
// The holder of the iterator may arbitrarily
// change elements in the returned slice, but
// those changes may be reflected to other
// iterators.
WeightedLineSlice() []WeightedLine
}
// WeightedLinesOf returns it.Len() weighted line from it. If it is a WeightedLineSlicer, the
// WeightedLineSlice method is used to obtain the lines. It is safe to pass a nil WeightedLines
// to WeightedLinesOf.
//
// If the WeightedLines has an indeterminate length, WeightedLinesOf will panic.
func WeightedLinesOf(it WeightedLines) []WeightedLine {
if it == nil {
return nil
}
len := it.Len()
switch {
case len == 0:
return nil
case len < 0:
panic("graph: called WeightedLinesOf on indeterminate iterator")
}
switch it := it.(type) {
case WeightedLineSlicer:
return it.WeightedLineSlice()
}
l := make([]WeightedLine, 0, len)
for it.Next() {
l = append(l, it.WeightedLine())
}
return l
}
// Empty is an empty set of nodes, edges or lines. It should be used when
// a graph returns a zero-length Iterator. Empty implements the slicer
// interfaces for nodes, edges and lines, returning nil for each of these.
const Empty = nothing
var (
_ Iterator = Empty
_ Nodes = Empty
_ NodeSlicer = Empty
_ Edges = Empty
_ EdgeSlicer = Empty
_ WeightedEdges = Empty
_ WeightedEdgeSlicer = Empty
_ Lines = Empty
_ LineSlicer = Empty
_ WeightedLines = Empty
_ WeightedLineSlicer = Empty
)
const nothing = empty(true)
type empty bool
func (empty) Next() bool { return false }
func (empty) Len() int { return 0 }
func (empty) Reset() {}
func (empty) Node() Node { return nil }
func (empty) NodeSlice() []Node { return nil }
func (empty) Edge() Edge { return nil }
func (empty) EdgeSlice() []Edge { return nil }
func (empty) WeightedEdge() WeightedEdge { return nil }
func (empty) WeightedEdgeSlice() []WeightedEdge { return nil }
func (empty) Line() Line { return nil }
func (empty) LineSlice() []Line { return nil }
func (empty) WeightedLine() WeightedLine { return nil }
func (empty) WeightedLineSlice() []WeightedLine { return nil }

View File

@ -1,301 +0,0 @@
// 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 simple
import (
"sort"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/ordered"
"gonum.org/v1/gonum/graph/iterator"
"gonum.org/v1/gonum/mat"
)
var (
dm *DirectedMatrix
_ graph.Graph = dm
_ graph.Directed = dm
_ edgeSetter = dm
_ weightedEdgeSetter = dm
)
// DirectedMatrix represents a directed graph using an adjacency
// matrix such that all IDs are in a contiguous block from 0 to n-1.
// Edges are stored implicitly as an edge weight, so edges stored in
// the graph are not recoverable.
type DirectedMatrix struct {
mat *mat.Dense
nodes []graph.Node
self float64
absent float64
}
// NewDirectedMatrix creates a directed dense graph with n nodes.
// All edges are initialized with the weight given by init. The self parameter
// specifies the cost of self connection, and absent specifies the weight
// returned for absent edges.
func NewDirectedMatrix(n int, init, self, absent float64) *DirectedMatrix {
matrix := make([]float64, n*n)
if init != 0 {
for i := range matrix {
matrix[i] = init
}
}
for i := 0; i < len(matrix); i += n + 1 {
matrix[i] = self
}
return &DirectedMatrix{
mat: mat.NewDense(n, n, matrix),
self: self,
absent: absent,
}
}
// NewDirectedMatrixFrom creates a directed dense graph with the given nodes.
// The IDs of the nodes must be contiguous from 0 to len(nodes)-1, but may
// be in any order. If IDs are not contiguous NewDirectedMatrixFrom will panic.
// All edges are initialized with the weight given by init. The self parameter
// specifies the cost of self connection, and absent specifies the weight
// returned for absent edges.
func NewDirectedMatrixFrom(nodes []graph.Node, init, self, absent float64) *DirectedMatrix {
sort.Sort(ordered.ByID(nodes))
for i, n := range nodes {
if int64(i) != n.ID() {
panic("simple: non-contiguous node IDs")
}
}
g := NewDirectedMatrix(len(nodes), init, self, absent)
g.nodes = nodes
return g
}
// 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.
func (g *DirectedMatrix) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(uid, vid)
}
// Edges returns all the edges in the graph.
func (g *DirectedMatrix) Edges() graph.Edges {
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 w := g.mat.At(i, j); !isSame(w, g.absent) {
edges = append(edges, WeightedEdge{F: g.Node(int64(i)), T: g.Node(int64(j)), W: w})
}
}
}
if len(edges) == 0 {
return graph.Empty
}
return iterator.NewOrderedEdges(edges)
}
// From returns all nodes in g that can be reached directly from n.
func (g *DirectedMatrix) From(id int64) graph.Nodes {
if !g.has(id) {
return graph.Empty
}
var nodes []graph.Node
_, c := g.mat.Dims()
for j := 0; j < c; j++ {
if int64(j) == id {
continue
}
// id is not greater than maximum int by this point.
if !isSame(g.mat.At(int(id), j), g.absent) {
nodes = append(nodes, g.Node(int64(j)))
}
}
if len(nodes) == 0 {
return graph.Empty
}
return iterator.NewOrderedNodes(nodes)
}
// HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction.
func (g *DirectedMatrix) HasEdgeBetween(xid, yid int64) bool {
if !g.has(xid) {
return false
}
if !g.has(yid) {
return false
}
// xid and yid are not greater than maximum int by this point.
return xid != yid && (!isSame(g.mat.At(int(xid), int(yid)), g.absent) || !isSame(g.mat.At(int(yid), int(xid)), g.absent))
}
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *DirectedMatrix) HasEdgeFromTo(uid, vid int64) bool {
if !g.has(uid) {
return false
}
if !g.has(vid) {
return false
}
// uid and vid are not greater than maximum int by this point.
return uid != vid && !isSame(g.mat.At(int(uid), int(vid)), g.absent)
}
// Matrix returns the mat.Matrix representation of the graph. The orientation
// of the matrix is such that the matrix entry at G_{ij} is the weight of the edge
// from node i to node j.
func (g *DirectedMatrix) Matrix() mat.Matrix {
// Prevent alteration of dimensions of the returned matrix.
m := *g.mat
return &m
}
// Node returns the node with the given ID if it exists in the graph,
// and nil otherwise.
func (g *DirectedMatrix) Node(id int64) graph.Node {
if !g.has(id) {
return nil
}
if g.nodes == nil {
return Node(id)
}
return g.nodes[id]
}
// Nodes returns all the nodes in the graph.
func (g *DirectedMatrix) Nodes() graph.Nodes {
if g.nodes != nil {
nodes := make([]graph.Node, len(g.nodes))
copy(nodes, g.nodes)
return iterator.NewOrderedNodes(nodes)
}
r, _ := g.mat.Dims()
// Matrix graphs must have at least one node.
return iterator.NewImplicitNodes(0, r, newSimpleNode)
}
// RemoveEdge removes the edge with the given end point nodes from the graph, leaving the terminal
// nodes. If the edge does not exist it is a no-op.
func (g *DirectedMatrix) RemoveEdge(fid, tid int64) {
if !g.has(fid) {
return
}
if !g.has(tid) {
return
}
// fid and tid are not greater than maximum int by this point.
g.mat.Set(int(fid), int(tid), g.absent)
}
// SetEdge sets e, an edge from one node to another with unit weight. If the ends of the edge
// are not in g or the edge is a self loop, SetEdge panics. SetEdge will store the nodes of
// e in the graph if it was initialized with NewDirectedMatrixFrom.
func (g *DirectedMatrix) SetEdge(e graph.Edge) {
g.setWeightedEdge(e, 1)
}
// SetWeightedEdge sets e, an edge from one node to another. If the ends of the edge are not in g
// or the edge is a self loop, SetWeightedEdge panics. SetWeightedEdge will store the nodes of
// e in the graph if it was initialized with NewDirectedMatrixFrom.
func (g *DirectedMatrix) SetWeightedEdge(e graph.WeightedEdge) {
g.setWeightedEdge(e, e.Weight())
}
func (g *DirectedMatrix) setWeightedEdge(e graph.Edge, weight float64) {
from := e.From()
fid := from.ID()
to := e.To()
tid := to.ID()
if fid == tid {
panic("simple: set illegal edge")
}
if int64(int(fid)) != fid {
panic("simple: unavailable from node ID for dense graph")
}
if int64(int(tid)) != tid {
panic("simple: unavailable to node ID for dense graph")
}
if g.nodes != nil {
g.nodes[fid] = from
g.nodes[tid] = to
}
// fid and tid are not greater than maximum int by this point.
g.mat.Set(int(fid), int(tid), weight)
}
// To returns all nodes in g that can reach directly to n.
func (g *DirectedMatrix) To(id int64) graph.Nodes {
if !g.has(id) {
return graph.Empty
}
var nodes []graph.Node
r, _ := g.mat.Dims()
for i := 0; i < r; i++ {
if int64(i) == id {
continue
}
// id is not greater than maximum int by this point.
if !isSame(g.mat.At(i, int(id)), g.absent) {
nodes = append(nodes, g.Node(int64(i)))
}
}
if len(nodes) == 0 {
return graph.Empty
}
return iterator.NewOrderedNodes(nodes)
}
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
// If x and y are the same node or there is no joining edge between the two nodes the weight
// value returned is either the graph's absent or self value. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g *DirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) {
if xid == yid {
return g.self, true
}
if g.HasEdgeFromTo(xid, yid) {
// xid and yid are not greater than maximum int by this point.
return g.mat.At(int(xid), int(yid)), true
}
return g.absent, false
}
// WeightedEdge returns the weighted 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.
func (g *DirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge {
if g.HasEdgeFromTo(uid, vid) {
// xid and yid are not greater than maximum int by this point.
return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))}
}
return nil
}
// WeightedEdges returns all the edges in the graph.
func (g *DirectedMatrix) WeightedEdges() graph.WeightedEdges {
var edges []graph.WeightedEdge
r, _ := g.mat.Dims()
for i := 0; i < r; i++ {
for j := 0; j < r; j++ {
if i == j {
continue
}
if w := g.mat.At(i, j); !isSame(w, g.absent) {
edges = append(edges, WeightedEdge{F: g.Node(int64(i)), T: g.Node(int64(j)), W: w})
}
}
}
if len(edges) == 0 {
return graph.Empty
}
return iterator.NewOrderedWeightedEdges(edges)
}
func (g *DirectedMatrix) has(id int64) bool {
r, _ := g.mat.Dims()
return 0 <= id && id < int64(r)
}

View File

@ -1,268 +0,0 @@
// 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 simple
import (
"sort"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/ordered"
"gonum.org/v1/gonum/graph/iterator"
"gonum.org/v1/gonum/mat"
)
var (
um *UndirectedMatrix
_ graph.Graph = um
_ graph.Undirected = um
_ edgeSetter = um
_ weightedEdgeSetter = um
)
// UndirectedMatrix represents an undirected graph using an adjacency
// matrix such that all IDs are in a contiguous block from 0 to n-1.
// Edges are stored implicitly as an edge weight, so edges stored in
// the graph are not recoverable.
type UndirectedMatrix struct {
mat *mat.SymDense
nodes []graph.Node
self float64
absent float64
}
// NewUndirectedMatrix creates an undirected dense graph with n nodes.
// All edges are initialized with the weight given by init. The self parameter
// specifies the cost of self connection, and absent specifies the weight
// returned for absent edges.
func NewUndirectedMatrix(n int, init, self, absent float64) *UndirectedMatrix {
matrix := make([]float64, n*n)
if init != 0 {
for i := range matrix {
matrix[i] = init
}
}
for i := 0; i < len(matrix); i += n + 1 {
matrix[i] = self
}
return &UndirectedMatrix{
mat: mat.NewSymDense(n, matrix),
self: self,
absent: absent,
}
}
// NewUndirectedMatrixFrom creates an undirected dense graph with the given nodes.
// The IDs of the nodes must be contiguous from 0 to len(nodes)-1, but may
// be in any order. If IDs are not contiguous NewUndirectedMatrixFrom will panic.
// All edges are initialized with the weight given by init. The self parameter
// specifies the cost of self connection, and absent specifies the weight
// returned for absent edges.
func NewUndirectedMatrixFrom(nodes []graph.Node, init, self, absent float64) *UndirectedMatrix {
sort.Sort(ordered.ByID(nodes))
for i, n := range nodes {
if int64(i) != n.ID() {
panic("simple: non-contiguous node IDs")
}
}
g := NewUndirectedMatrix(len(nodes), init, self, absent)
g.nodes = nodes
return g
}
// 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.
func (g *UndirectedMatrix) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(uid, vid)
}
// EdgeBetween returns the edge between nodes x and y.
func (g *UndirectedMatrix) EdgeBetween(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(uid, vid)
}
// Edges returns all the edges in the graph.
func (g *UndirectedMatrix) Edges() graph.Edges {
var edges []graph.Edge
r, _ := g.mat.Dims()
for i := 0; i < r; i++ {
for j := i + 1; j < r; j++ {
if w := g.mat.At(i, j); !isSame(w, g.absent) {
edges = append(edges, WeightedEdge{F: g.Node(int64(i)), T: g.Node(int64(j)), W: w})
}
}
}
if len(edges) == 0 {
return graph.Empty
}
return iterator.NewOrderedEdges(edges)
}
// From returns all nodes in g that can be reached directly from n.
func (g *UndirectedMatrix) From(id int64) graph.Nodes {
if !g.has(id) {
return graph.Empty
}
var nodes []graph.Node
r := g.mat.Symmetric()
for i := 0; i < r; i++ {
if int64(i) == id {
continue
}
// id is not greater than maximum int by this point.
if !isSame(g.mat.At(int(id), i), g.absent) {
nodes = append(nodes, g.Node(int64(i)))
}
}
if len(nodes) == 0 {
return graph.Empty
}
return iterator.NewOrderedNodes(nodes)
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *UndirectedMatrix) HasEdgeBetween(uid, vid int64) bool {
if !g.has(uid) {
return false
}
if !g.has(vid) {
return false
}
// uid and vid are not greater than maximum int by this point.
return uid != vid && !isSame(g.mat.At(int(uid), int(vid)), g.absent)
}
// Matrix returns the mat.Matrix representation of the graph.
func (g *UndirectedMatrix) Matrix() mat.Matrix {
// Prevent alteration of dimensions of the returned matrix.
m := *g.mat
return &m
}
// Node returns the node with the given ID if it exists in the graph,
// and nil otherwise.
func (g *UndirectedMatrix) Node(id int64) graph.Node {
if !g.has(id) {
return nil
}
if g.nodes == nil {
return Node(id)
}
return g.nodes[id]
}
// Nodes returns all the nodes in the graph.
func (g *UndirectedMatrix) Nodes() graph.Nodes {
if g.nodes != nil {
nodes := make([]graph.Node, len(g.nodes))
copy(nodes, g.nodes)
return iterator.NewOrderedNodes(nodes)
}
r := g.mat.Symmetric()
// Matrix graphs must have at least one node.
return iterator.NewImplicitNodes(0, r, newSimpleNode)
}
// RemoveEdge removes the edge with the given end point IDs from the graph, leaving the terminal
// nodes. If the edge does not exist it is a no-op.
func (g *UndirectedMatrix) RemoveEdge(fid, tid int64) {
if !g.has(fid) {
return
}
if !g.has(tid) {
return
}
// fid and tid are not greater than maximum int by this point.
g.mat.SetSym(int(fid), int(tid), g.absent)
}
// SetEdge sets e, an edge from one node to another with unit weight. If the ends of the edge are
// not in g or the edge is a self loop, SetEdge panics. SetEdge will store the nodes of
// e in the graph if it was initialized with NewUndirectedMatrixFrom.
func (g *UndirectedMatrix) SetEdge(e graph.Edge) {
g.setWeightedEdge(e, 1)
}
// SetWeightedEdge sets e, an edge from one node to another. If the ends of the edge are not in g
// or the edge is a self loop, SetWeightedEdge panics. SetWeightedEdge will store the nodes of
// e in the graph if it was initialized with NewUndirectedMatrixFrom.
func (g *UndirectedMatrix) SetWeightedEdge(e graph.WeightedEdge) {
g.setWeightedEdge(e, e.Weight())
}
func (g *UndirectedMatrix) setWeightedEdge(e graph.Edge, weight float64) {
from := e.From()
fid := from.ID()
to := e.To()
tid := to.ID()
if fid == tid {
panic("simple: set illegal edge")
}
if int64(int(fid)) != fid {
panic("simple: unavailable from node ID for dense graph")
}
if int64(int(tid)) != tid {
panic("simple: unavailable to node ID for dense graph")
}
if g.nodes != nil {
g.nodes[fid] = from
g.nodes[tid] = to
}
// fid and tid are not greater than maximum int by this point.
g.mat.SetSym(int(fid), int(tid), weight)
}
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
// If x and y are the same node or there is no joining edge between the two nodes the weight
// value returned is either the graph's absent or self value. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g *UndirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) {
if xid == yid {
return g.self, true
}
if g.HasEdgeBetween(xid, yid) {
// xid and yid are not greater than maximum int by this point.
return g.mat.At(int(xid), int(yid)), true
}
return g.absent, false
}
// WeightedEdge returns the weighted 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.
func (g *UndirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(uid, vid)
}
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g *UndirectedMatrix) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
if g.HasEdgeBetween(uid, vid) {
// uid and vid are not greater than maximum int by this point.
return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))}
}
return nil
}
// WeightedEdges returns all the edges in the graph.
func (g *UndirectedMatrix) WeightedEdges() graph.WeightedEdges {
var edges []graph.WeightedEdge
r, _ := g.mat.Dims()
for i := 0; i < r; i++ {
for j := i + 1; j < r; j++ {
if w := g.mat.At(i, j); !isSame(w, g.absent) {
edges = append(edges, WeightedEdge{F: g.Node(int64(i)), T: g.Node(int64(j)), W: w})
}
}
}
if len(edges) == 0 {
return graph.Empty
}
return iterator.NewOrderedWeightedEdges(edges)
}
func (g *UndirectedMatrix) has(id int64) bool {
r := g.mat.Symmetric()
return 0 <= id && id < int64(r)
}

View File

@ -1,241 +0,0 @@
// 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 simple
import (
"fmt"
"gonum.org/v1/gonum/graph"
"gonum.org/v1/gonum/graph/internal/uid"
"gonum.org/v1/gonum/graph/iterator"
)
var (
dg *DirectedGraph
_ graph.Graph = dg
_ graph.Directed = dg
_ graph.NodeAdder = dg
_ graph.NodeRemover = dg
_ graph.EdgeAdder = dg
_ graph.EdgeRemover = dg
)
// DirectedGraph implements a generalized directed graph.
type DirectedGraph struct {
nodes map[int64]graph.Node
from map[int64]map[int64]graph.Edge
to map[int64]map[int64]graph.Edge
nodeIDs uid.Set
}
// NewDirectedGraph returns a DirectedGraph.
func NewDirectedGraph() *DirectedGraph {
return &DirectedGraph{
nodes: make(map[int64]graph.Node),
from: make(map[int64]map[int64]graph.Edge),
to: make(map[int64]map[int64]graph.Edge),
nodeIDs: uid.NewSet(),
}
}
// AddNode adds n to the graph. It panics if the added node ID matches an existing node ID.
func (g *DirectedGraph) AddNode(n graph.Node) {
if _, exists := g.nodes[n.ID()]; exists {
panic(fmt.Sprintf("simple: node ID collision: %d", n.ID()))
}
g.nodes[n.ID()] = n
g.nodeIDs.Use(n.ID())
}
// 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.
func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
edge, ok := g.from[uid][vid]
if !ok {
return nil
}
return edge
}
// Edges returns all the edges in the graph.
func (g *DirectedGraph) Edges() graph.Edges {
var edges []graph.Edge
for _, u := range g.nodes {
for _, e := range g.from[u.ID()] {
edges = append(edges, e)
}
}
if len(edges) == 0 {
return graph.Empty
}
return iterator.NewOrderedEdges(edges)
}
// From returns all nodes in g that can be reached directly from n.
func (g *DirectedGraph) From(id int64) graph.Nodes {
if _, ok := g.from[id]; !ok {
return graph.Empty
}
from := make([]graph.Node, len(g.from[id]))
i := 0
for vid := range g.from[id] {
from[i] = g.nodes[vid]
i++
}
if len(from) == 0 {
return graph.Empty
}
return iterator.NewOrderedNodes(from)
}
// HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction.
func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
if _, ok := g.from[xid][yid]; ok {
return true
}
_, ok := g.from[yid][xid]
return ok
}
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
if _, ok := g.from[uid][vid]; !ok {
return false
}
return true
}
// NewEdge returns a new Edge from the source to the destination node.
func (g *DirectedGraph) NewEdge(from, to graph.Node) graph.Edge {
return &Edge{F: from, T: to}
}
// NewNode returns a new unique Node to be added to g. The Node's ID does
// not become valid in g until the Node is added to g.
func (g *DirectedGraph) NewNode() graph.Node {
if len(g.nodes) == 0 {
return Node(0)
}
if int64(len(g.nodes)) == uid.Max {
panic("simple: cannot allocate node: no slot")
}
return Node(g.nodeIDs.NewID())
}
// Node returns the node with the given ID if it exists in the graph,
// and nil otherwise.
func (g *DirectedGraph) Node(id int64) graph.Node {
return g.nodes[id]
}
// Nodes returns all the nodes in the graph.
func (g *DirectedGraph) Nodes() graph.Nodes {
if len(g.nodes) == 0 {
return graph.Empty
}
nodes := make([]graph.Node, len(g.nodes))
i := 0
for _, n := range g.nodes {
nodes[i] = n
i++
}
return iterator.NewOrderedNodes(nodes)
}
// RemoveEdge removes the edge with the given end point IDs from the graph, leaving the terminal
// nodes. If the edge does not exist it is a no-op.
func (g *DirectedGraph) RemoveEdge(fid, tid int64) {
if _, ok := g.nodes[fid]; !ok {
return
}
if _, ok := g.nodes[tid]; !ok {
return
}
delete(g.from[fid], tid)
delete(g.to[tid], fid)
}
// RemoveNode removes the node with the given ID from the graph, as well as any edges attached
// to it. If the node is not in the graph it is a no-op.
func (g *DirectedGraph) RemoveNode(id int64) {
if _, ok := g.nodes[id]; !ok {
return
}
delete(g.nodes, id)
for from := range g.from[id] {
delete(g.to[from], id)
}
delete(g.from, id)
for to := range g.to[id] {
delete(g.from[to], id)
}
delete(g.to, id)
g.nodeIDs.Release(id)
}
// SetEdge adds e, an edge from one node to another. If the nodes do not exist, they are added
// and are set to the nodes of the edge otherwise.
// It will panic if the IDs of the e.From and e.To are equal.
func (g *DirectedGraph) SetEdge(e graph.Edge) {
var (
from = e.From()
fid = from.ID()
to = e.To()
tid = to.ID()
)
if fid == tid {
panic("simple: adding self edge")
}
if _, ok := g.nodes[fid]; !ok {
g.AddNode(from)
} else {
g.nodes[fid] = from
}
if _, ok := g.nodes[tid]; !ok {
g.AddNode(to)
} else {
g.nodes[tid] = to
}
if fm, ok := g.from[fid]; ok {
fm[tid] = e
} else {
g.from[fid] = map[int64]graph.Edge{tid: e}
}
if tm, ok := g.to[tid]; ok {
tm[fid] = e
} else {
g.to[tid] = map[int64]graph.Edge{fid: e}
}
}
// To returns all nodes in g that can reach directly to n.
func (g *DirectedGraph) To(id int64) graph.Nodes {
if _, ok := g.to[id]; !ok {
return graph.Empty
}
to := make([]graph.Node, len(g.to[id]))
i := 0
for uid := range g.to[id] {
to[i] = g.nodes[uid]
i++
}
if len(to) == 0 {
return graph.Empty
}
return iterator.NewOrderedNodes(to)
}

View File

@ -1,9 +0,0 @@
// Copyright ©2017 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 simple provides a suite of simple graph implementations satisfying
// the gonum/graph interfaces.
//
// All types in simple return the graph.Empty value for empty iterators.
package simple // import "gonum.org/v1/gonum/graph/simple"

View File

@ -1,72 +0,0 @@
// 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 simple
import (
"math"
"gonum.org/v1/gonum/graph"
)
// Node is a simple graph node.
type Node int64
// ID returns the ID number of the node.
func (n Node) ID() int64 {
return int64(n)
}
func newSimpleNode(id int) graph.Node {
return Node(id)
}
// Edge is a simple graph edge.
type Edge struct {
F, T graph.Node
}
// From returns the from-node of the edge.
func (e Edge) From() graph.Node { return e.F }
// To returns the to-node of the edge.
func (e Edge) To() graph.Node { return e.T }
// ReversedLine returns a new Edge with the F and T fields
// swapped.
func (e Edge) ReversedEdge() graph.Edge { return Edge{F: e.T, T: e.F} }
// WeightedEdge is a simple weighted graph edge.
type WeightedEdge struct {
F, T graph.Node
W float64
}
// From returns the from-node of the edge.
func (e WeightedEdge) From() graph.Node { return e.F }
// To returns the to-node of the edge.
func (e WeightedEdge) To() graph.Node { return e.T }
// ReversedLine returns a new Edge with the F and T fields
// swapped. The weight of the new Edge is the same as
// the weight of the receiver.
func (e WeightedEdge) ReversedEdge() graph.Edge { return WeightedEdge{F: e.T, T: e.F, W: e.W} }
// Weight returns the weight of the edge.
func (e WeightedEdge) Weight() float64 { return e.W }
// isSame returns whether two float64 values are the same where NaN values
// are equalable.
func isSame(a, b float64) bool {
return a == b || (math.IsNaN(a) && math.IsNaN(b))
}
type edgeSetter interface {
SetEdge(e graph.Edge)
}
type weightedEdgeSetter interface {
SetWeightedEdge(e graph.WeightedEdge)
}

Some files were not shown because too many files have changed in this diff Show More